diff --git a/lib/db/upgradelib.php b/lib/db/upgradelib.php index 5b0c83884a880..e6b29abcf65d8 100644 --- a/lib/db/upgradelib.php +++ b/lib/db/upgradelib.php @@ -76,387 +76,6 @@ function upgrade_mysql_get_supported_tables() { return $tables; } -/** - * Remove all signed numbers from current database and change - * text fields to long texts - mysql only. - */ -function upgrade_mysql_fix_unsigned_and_lob_columns() { - // We are not using standard API for changes of column - // because everything 'signed'-related will be removed soon. - - // If anybody already has numbers higher than signed limit the execution stops - // and tables must be fixed manually before continuing upgrade. - - global $DB; - - if ($DB->get_dbfamily() !== 'mysql') { - return; - } - - $pbar = new progress_bar('mysqlconvertunsignedlobs', 500, true); - - $prefix = $DB->get_prefix(); - $tables = upgrade_mysql_get_supported_tables(); - - $tablecount = count($tables); - $i = 0; - foreach ($tables as $table) { - $i++; - - $changes = array(); - - $sql = "SHOW COLUMNS FROM `{{$table}}`"; - $rs = $DB->get_recordset_sql($sql); - foreach ($rs as $column) { - $column = (object)array_change_key_case((array)$column, CASE_LOWER); - if (stripos($column->type, 'unsigned') !== false) { - $maxvalue = 0; - if (preg_match('/^int/i', $column->type)) { - $maxvalue = 2147483647; - } else if (preg_match('/^medium/i', $column->type)) { - $maxvalue = 8388607; - } else if (preg_match('/^smallint/i', $column->type)) { - $maxvalue = 32767; - } else if (preg_match('/^tinyint/i', $column->type)) { - $maxvalue = 127; - } - if ($maxvalue) { - // Make sure nobody is abusing our integer ranges - moodle int sizes are in digits, not bytes!!! - $invalidcount = $DB->get_field_sql("SELECT COUNT('x') FROM `{{$table}}` WHERE `$column->field` > :maxnumber", array('maxnumber'=>$maxvalue)); - if ($invalidcount) { - throw new moodle_exception('notlocalisederrormessage', 'error', new moodle_url('/admin/'), "Database table '{$table}'' contains unsigned column '{$column->field}' with $invalidcount values that are out of allowed range, upgrade can not continue."); - } - } - $type = preg_replace('/unsigned/i', 'signed', $column->type); - $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL'; - $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : ''; - $autoinc = (stripos($column->extra, 'auto_increment') !== false) ? 'AUTO_INCREMENT' : ''; - // Primary and unique not necessary here, change_database_structure does not add prefix. - $changes[] = "MODIFY COLUMN `$column->field` $type $notnull $default $autoinc"; - - } else if ($column->type === 'tinytext' or $column->type === 'mediumtext' or $column->type === 'text') { - $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL'; - $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : ''; - // Primary, unique and inc are not supported for texts. - $changes[] = "MODIFY COLUMN `$column->field` LONGTEXT $notnull $default"; - - } else if ($column->type === 'tinyblob' or $column->type === 'mediumblob' or $column->type === 'blob') { - $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL'; - $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : ''; - // Primary, unique and inc are not supported for blobs. - $changes[] = "MODIFY COLUMN `$column->field` LONGBLOB $notnull $default"; - } - - } - $rs->close(); - - if ($changes) { - // Set appropriate timeout - 1 minute per thousand of records should be enough, min 60 minutes just in case. - $count = $DB->count_records($table, array()); - $timeout = ($count/1000)*60; - $timeout = ($timeout < 60*60) ? 60*60 : (int)$timeout; - upgrade_set_timeout($timeout); - - $sql = "ALTER TABLE `{$prefix}$table` ".implode(', ', $changes); - $DB->change_database_structure($sql); - } - - $pbar->update($i, $tablecount, "Converted unsigned/lob columns in MySQL database - $i/$tablecount."); - } -} - -/** - * Migrate NTEXT to NVARCHAR(MAX). - */ -function upgrade_mssql_nvarcharmax() { - global $DB; - - if ($DB->get_dbfamily() !== 'mssql') { - return; - } - - $pbar = new progress_bar('mssqlconvertntext', 500, true); - - $prefix = $DB->get_prefix(); - $tables = $DB->get_tables(false); - - $tablecount = count($tables); - $i = 0; - foreach ($tables as $table) { - $i++; - - $columns = array(); - - $sql = "SELECT column_name - FROM INFORMATION_SCHEMA.COLUMNS - WHERE table_name = '{{$table}}' AND UPPER(data_type) = 'NTEXT'"; - $rs = $DB->get_recordset_sql($sql); - foreach ($rs as $column) { - $columns[] = $column->column_name; - } - $rs->close(); - - if ($columns) { - // Set appropriate timeout - 1 minute per thousand of records should be enough, min 60 minutes just in case. - $count = $DB->count_records($table, array()); - $timeout = ($count/1000)*60; - $timeout = ($timeout < 60*60) ? 60*60 : (int)$timeout; - upgrade_set_timeout($timeout); - - $updates = array(); - foreach ($columns as $column) { - // Change the definition. - $sql = "ALTER TABLE {$prefix}$table ALTER COLUMN $column NVARCHAR(MAX)"; - $DB->change_database_structure($sql); - $updates[] = "$column = $column"; - } - - // Now force the migration of text data to new optimised storage. - $sql = "UPDATE {{$table}} SET ".implode(', ', $updates); - $DB->execute($sql); - } - - $pbar->update($i, $tablecount, "Converted NTEXT to NVARCHAR(MAX) columns in MS SQL Server database - $i/$tablecount."); - } -} - -/** - * Migrate IMAGE to VARBINARY(MAX). - */ -function upgrade_mssql_varbinarymax() { - global $DB; - - if ($DB->get_dbfamily() !== 'mssql') { - return; - } - - $pbar = new progress_bar('mssqlconvertimage', 500, true); - - $prefix = $DB->get_prefix(); - $tables = $DB->get_tables(false); - - $tablecount = count($tables); - $i = 0; - foreach ($tables as $table) { - $i++; - - $columns = array(); - - $sql = "SELECT column_name - FROM INFORMATION_SCHEMA.COLUMNS - WHERE table_name = '{{$table}}' AND UPPER(data_type) = 'IMAGE'"; - $rs = $DB->get_recordset_sql($sql); - foreach ($rs as $column) { - $columns[] = $column->column_name; - } - $rs->close(); - - if ($columns) { - // Set appropriate timeout - 1 minute per thousand of records should be enough, min 60 minutes just in case. - $count = $DB->count_records($table, array()); - $timeout = ($count/1000)*60; - $timeout = ($timeout < 60*60) ? 60*60 : (int)$timeout; - upgrade_set_timeout($timeout); - - foreach ($columns as $column) { - // Change the definition. - $sql = "ALTER TABLE {$prefix}$table ALTER COLUMN $column VARBINARY(MAX)"; - $DB->change_database_structure($sql); - } - - // Binary columns should not be used, do not waste time optimising the storage. - } - - $pbar->update($i, $tablecount, "Converted IMAGE to VARBINARY(MAX) columns in MS SQL Server database - $i/$tablecount."); - } -} - -/** - * This upgrade script fixes the mismatches between DB fields course_modules.section - * and course_sections.sequence. It makes sure that each module is included - * in the sequence of at least one section. - * Note that this script is different from admin/cli/fix_course_sortorder.php - * in the following ways: - * 1. It does not fix the cases when module appears several times in section(s) sequence(s) - - * it will be done automatically on the next viewing of the course. - * 2. It does not remove non-existing modules from section sequences - administrator - * has to run the CLI script to do it. - * 3. When this script finds an orphaned module it adds it to the section but makes hidden - * where CLI script does not change the visiblity specified in the course_modules table. - */ -function upgrade_course_modules_sequences() { - global $DB; - - // Find all modules that point to the section which does not point back to this module. - $sequenceconcat = $DB->sql_concat("','", "s.sequence", "','"); - $moduleconcat = $DB->sql_concat("'%,'", "m.id", "',%'"); - $sql = "SELECT m.id, m.course, m.section, s.sequence - FROM {course_modules} m LEFT OUTER JOIN {course_sections} s - ON m.course = s.course and m.section = s.id - WHERE s.sequence IS NULL OR ($sequenceconcat NOT LIKE $moduleconcat) - ORDER BY m.course"; - $rs = $DB->get_recordset_sql($sql); - $sections = null; - foreach ($rs as $cm) { - if (!isset($sections[$cm->course])) { - // Retrieve all sections for the course (only once for each corrupt course). - $sections = array($cm->course => - $DB->get_records('course_sections', array('course' => $cm->course), - 'section', 'id, section, sequence, visible')); - if (empty($sections[$cm->course])) { - // Very odd - the course has a module in it but has no sections. Create 0-section. - $newsection = array('sequence' => '', 'section' => 0, 'visible' => 1); - $newsection['id'] = $DB->insert_record('course_sections', - $newsection + array('course' => $cm->course, 'summary' => '', 'summaryformat' => FORMAT_HTML)); - $sections[$cm->course] = array($newsection['id'] => (object)$newsection); - } - } - // Attempt to find the section that has this module in it's sequence. - // If there are several of them, pick the last because this is what get_fast_modinfo() does. - $sectionid = null; - foreach ($sections[$cm->course] as $section) { - if (!empty($section->sequence) && in_array($cm->id, preg_split('/,/', $section->sequence))) { - $sectionid = $section->id; - } - } - if ($sectionid) { - // Found the section. Update course_module to point to the correct section. - $params = array('id' => $cm->id, 'section' => $sectionid); - if (!$sections[$cm->course][$sectionid]->visible) { - $params['visible'] = 0; - } - $DB->update_record('course_modules', $params); - } else { - // No section in the course has this module in it's sequence. - if (isset($sections[$cm->course][$cm->section])) { - // Try to add module to the section it points to (if it is valid). - $sectionid = $cm->section; - } else { - // Section not found. Just add to the first available section. - reset($sections[$cm->course]); - $sectionid = key($sections[$cm->course]); - } - $newsequence = ltrim($sections[$cm->course][$sectionid]->sequence . ',' . $cm->id, ','); - $sections[$cm->course][$sectionid]->sequence = $newsequence; - $DB->update_record('course_sections', array('id' => $sectionid, 'sequence' => $newsequence)); - // Make module invisible because it was not displayed at all before this upgrade script. - $DB->update_record('course_modules', array('id' => $cm->id, 'section' => $sectionid, 'visible' => 0, 'visibleold' => 0)); - } - } - $rs->close(); - unset($sections); - - // Note that we don't need to reset course cache here because it is reset automatically after upgrade. -} - -/** - * Updates a single item (course module or course section) to transfer the - * availability settings from the old to the new format. - * - * Note: We do not convert groupmembersonly for modules at present. If we did, - * $groupmembersonly would be set to the groupmembersonly option for the - * module. Since we don't, it will be set to 0 for modules, and 1 for sections - * if they have a grouping. - * - * @param int $groupmembersonly 1 if activity has groupmembersonly option - * @param int $groupingid Grouping id (0 = none) - * @param int $availablefrom Available from time (0 = none) - * @param int $availableuntil Available until time (0 = none) - * @param int $showavailability Show availability (1) or hide activity entirely - * @param array $availrecs Records from course_modules/sections_availability - * @param array $fieldrecs Records from course_modules/sections_avail_fields - */ -function upgrade_availability_item($groupmembersonly, $groupingid, - $availablefrom, $availableuntil, $showavailability, - array $availrecs, array $fieldrecs) { - global $CFG, $DB; - $conditions = array(); - $shows = array(); - - // Group members only condition (if enabled). - if ($CFG->enablegroupmembersonly && $groupmembersonly) { - if ($groupingid) { - $conditions[] = '{"type":"grouping"' . - ($groupingid ? ',"id":' . $groupingid : '') . '}'; - } else { - // No grouping specified, so allow any group. - $conditions[] = '{"type":"group"}'; - } - // Group members only condition was not displayed to students. - $shows[] = 'false'; - - // In the unlikely event that the site had enablegroupmembers only - // but NOT enableavailability, we need to turn this on now. - if (!$CFG->enableavailability) { - set_config('enableavailability', 1); - } - } - - // Date conditions. - if ($availablefrom) { - $conditions[] = '{"type":"date","d":">=","t":' . $availablefrom . '}'; - $shows[] = $showavailability ? 'true' : 'false'; - } - if ($availableuntil) { - $conditions[] = '{"type":"date","d":"<","t":' . $availableuntil . '}'; - // Until dates never showed to students. - $shows[] = 'false'; - } - - // Conditions from _availability table. - foreach ($availrecs as $rec) { - if (!empty($rec->sourcecmid)) { - // Completion condition. - $conditions[] = '{"type":"completion","cm":' . $rec->sourcecmid . - ',"e":' . $rec->requiredcompletion . '}'; - } else { - // Grade condition. - $minmax = ''; - if (!empty($rec->grademin)) { - $minmax .= ',"min":' . sprintf('%.5f', $rec->grademin); - } - if (!empty($rec->grademax)) { - $minmax .= ',"max":' . sprintf('%.5f', $rec->grademax); - } - $conditions[] = '{"type":"grade","id":' . $rec->gradeitemid . $minmax . '}'; - } - $shows[] = $showavailability ? 'true' : 'false'; - } - - // Conditions from _fields table. - foreach ($fieldrecs as $rec) { - if (isset($rec->userfield)) { - // Standard field. - $fieldbit = ',"sf":' . json_encode($rec->userfield); - } else { - // Custom field. - $fieldbit = ',"cf":' . json_encode($rec->shortname); - } - // Value is not included for certain operators. - switch($rec->operator) { - case 'isempty': - case 'isnotempty': - $valuebit = ''; - break; - - default: - $valuebit = ',"v":' . json_encode($rec->value); - break; - } - $conditions[] = '{"type":"profile","op":"' . $rec->operator . '"' . - $fieldbit . $valuebit . '}'; - $shows[] = $showavailability ? 'true' : 'false'; - } - - // If there are some conditions, set them into database. - if ($conditions) { - return '{"op":"&","showc":[' . implode(',', $shows) . '],' . - '"c":[' . implode(',', $conditions) . ']}'; - } else { - return null; - } -} - /** * Using data for a single course-module that has groupmembersonly enabled, * returns the new availability value that incorporates the correct diff --git a/lib/tests/upgradelib_test.php b/lib/tests/upgradelib_test.php index ca40f86439860..1c4b7073de0e8 100644 --- a/lib/tests/upgradelib_test.php +++ b/lib/tests/upgradelib_test.php @@ -43,80 +43,6 @@ public function test_upgrade_stale_php_files_present() { $this->assertFalse(upgrade_stale_php_files_present()); } - /** - * Test the {@link upgrade_grade_item_fix_sortorder() function with - * faked duplicate sortorder data. - */ - public function test_upgrade_grade_item_fix_sortorder() { - global $DB; - - $this->resetAfterTest(true); - - // The purpose of this test is to make sure that after upgrade script - // there is no duplicates in the field grade_items.sortorder (for each course) - // and the result of query "SELECT id FROM grade_items WHERE courseid=? ORDER BY sortorder, id" does not change. - $sequencesql = 'SELECT id FROM {grade_items} WHERE courseid=? ORDER BY sortorder, id'; - - // Each set is used for filling the db with fake data and will be representing the result of query: - // "SELECT sortorder from {grade_items} WHERE courseid=? ORDER BY id". - $testsets = array( - // Items that need no action. - array(1,2,3), - array(5,6,7), - array(7,6,1,3,2,5), - // Items with sortorder duplicates - array(1,2,2,3,3,4,5), - // Only one sortorder duplicate. - array(1,1), - array(3,3), - // Non-sequential sortorders with one or multiple duplicates. - array(3,3,7,5,6,6,9,10,8,3), - array(7,7,3), - array(3,4,5,3,5,4,7,1) - ); - $origsequences = array(); - - // Generate the data and remember the initial sequence or items. - foreach ($testsets as $testset) { - $course = $this->getDataGenerator()->create_course(); - foreach ($testset as $sortorder) { - $this->insert_fake_grade_item_sortorder($course->id, $sortorder); - } - $DB->get_records('grade_items'); - $origsequences[$course->id] = $DB->get_fieldset_sql($sequencesql, array($course->id)); - } - - $duplicatedetectionsql = "SELECT courseid, sortorder - FROM {grade_items} - GROUP BY courseid, sortorder - HAVING COUNT(id) > 1"; - - // Verify there are duplicates before we start the fix. - $dupes = $DB->record_exists_sql($duplicatedetectionsql); - $this->assertTrue($dupes); - - // Do the work. - upgrade_grade_item_fix_sortorder(); - - // Verify that no duplicates are left in the database. - $dupes = $DB->record_exists_sql($duplicatedetectionsql); - $this->assertFalse($dupes); - - // Verify that sequences are exactly the same as they were before upgrade script. - $idx = 0; - foreach ($origsequences as $courseid => $origsequence) { - if (count(($testsets[$idx])) == count(array_unique($testsets[$idx]))) { - // If there were no duplicates for this course verify that sortorders are not modified. - $newsortorders = $DB->get_fieldset_sql("SELECT sortorder from {grade_items} WHERE courseid=? ORDER BY id", array($courseid)); - $this->assertEquals($testsets[$idx], $newsortorders); - } - $newsequence = $DB->get_fieldset_sql($sequencesql, array($courseid)); - $this->assertEquals($origsequence, $newsequence, - "Sequences do not match for test set $idx : ".join(',', $testsets[$idx])); - $idx++; - } - } - /** * Populate some fake grade items into the database with specified * sortorder and course id. @@ -150,57 +76,6 @@ private function insert_fake_grade_item_sortorder($courseid, $sortorder) { return $DB->get_record('grade_items', array('id' => $item->id)); } - public function test_upgrade_fix_missing_root_folders() { - global $DB, $SITE; - - $this->resetAfterTest(true); - - // Setup some broken data... - // Create two resources (and associated file areas). - $this->setAdminUser(); - $resource1 = $this->getDataGenerator()->get_plugin_generator('mod_resource') - ->create_instance(array('course' => $SITE->id)); - $resource2 = $this->getDataGenerator()->get_plugin_generator('mod_resource') - ->create_instance(array('course' => $SITE->id)); - - // Delete the folder record of resource1 to simulate broken data. - $context = context_module::instance($resource1->cmid); - $selectargs = array('contextid' => $context->id, - 'component' => 'mod_resource', - 'filearea' => 'content', - 'itemid' => 0); - - // Verify file records exist. - $areafilecount = $DB->count_records('files', $selectargs); - $this->assertNotEmpty($areafilecount); - - // Delete the folder record. - $folderrecord = $selectargs; - $folderrecord['filepath'] = '/'; - $folderrecord['filename'] = '.'; - - // Get previous folder record. - $oldrecord = $DB->get_record('files', $folderrecord); - $DB->delete_records('files', $folderrecord); - - // Verify the folder record has been removed. - $newareafilecount = $DB->count_records('files', $selectargs); - $this->assertSame($newareafilecount, $areafilecount - 1); - - $this->assertFalse($DB->record_exists('files', $folderrecord)); - - // Run the upgrade step! - upgrade_fix_missing_root_folders(); - - // Verify the folder record has been restored. - $newareafilecount = $DB->count_records('files', $selectargs); - $this->assertSame($newareafilecount, $areafilecount); - - $newrecord = $DB->get_record('files', $folderrecord, '*', MUST_EXIST); - // Verify the hash is correctly created. - $this->assertSame($oldrecord->pathnamehash, $newrecord->pathnamehash); - } - public function test_upgrade_fix_missing_root_folders_draft() { global $DB, $SITE; @@ -245,115 +120,6 @@ public function test_upgrade_fix_missing_root_folders_draft() { $this->assertEquals($originalhash, $newhash); } - /** - * Tests the upgrade of an individual course-module or section from the - * old to new availability system. (This test does not use the database - * so it can run any time.) - */ - public function test_upgrade_availability_item() { - global $CFG; - $this->resetAfterTest(); - - // This function is in the other upgradelib. - require_once($CFG->libdir . '/db/upgradelib.php'); - - // Groupmembersonly (or nothing). Show option on but ignored. - // Note: This $CFG option doesn't exist any more but we are testing the - // upgrade function so it did exist then... - $CFG->enablegroupmembersonly = 0; - $this->assertNull( - upgrade_availability_item(1, 0, 0, 0, 1, array(), array())); - $CFG->enablegroupmembersonly = 1; - $this->assertNull( - upgrade_availability_item(0, 0, 0, 0, 1, array(), array())); - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"group"}]}', - upgrade_availability_item(1, 0, 0, 0, 1, array(), array())); - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"grouping","id":4}]}', - upgrade_availability_item(1, 4, 0, 0, 1, array(), array())); - - // Dates (with show/hide options - until date always hides). - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"date","d":">=","t":996}]}', - upgrade_availability_item(0, 0, 996, 0, 1, array(), array())); - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"date","d":">=","t":997}]}', - upgrade_availability_item(0, 0, 997, 0, 0, array(), array())); - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"date","d":"<","t":998}]}', - upgrade_availability_item(0, 0, 0, 998, 1, array(), array())); - $this->assertEquals( - '{"op":"&","showc":[true,false],"c":[' . - '{"type":"date","d":">=","t":995},{"type":"date","d":"<","t":999}]}', - upgrade_availability_item(0, 0, 995, 999, 1, array(), array())); - - // Grade (show option works as normal). - $availrec = (object)array( - 'sourcecmid' => null, 'requiredcompletion' => null, - 'gradeitemid' => 13, 'grademin' => null, 'grademax' => null); - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"grade","id":13}]}', - upgrade_availability_item(0, 0, 0, 0, 1, array($availrec), array())); - $availrec->grademin = 4.1; - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"grade","id":13,"min":4.10000}]}', - upgrade_availability_item(0, 0, 0, 0, 0, array($availrec), array())); - $availrec->grademax = 9.9; - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"grade","id":13,"min":4.10000,"max":9.90000}]}', - upgrade_availability_item(0, 0, 0, 0, 1, array($availrec), array())); - $availrec->grademin = null; - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"grade","id":13,"max":9.90000}]}', - upgrade_availability_item(0, 0, 0, 0, 1, array($availrec), array())); - - // Completion (show option normal). - $availrec->grademax = null; - $availrec->gradeitemid = null; - $availrec->sourcecmid = 666; - $availrec->requiredcompletion = 1; - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"completion","cm":666,"e":1}]}', - upgrade_availability_item(0, 0, 0, 0, 1, array($availrec), array())); - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"completion","cm":666,"e":1}]}', - upgrade_availability_item(0, 0, 0, 0, 0, array($availrec), array())); - - // Profile conditions (custom/standard field, values/not, show option normal). - $fieldrec = (object)array('userfield' => 'email', 'operator' => 'isempty', - 'value' => '', 'shortname' => null); - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"profile","op":"isempty","sf":"email"}]}', - upgrade_availability_item(0, 0, 0, 0, 1, array(), array($fieldrec))); - $fieldrec->value = '@'; - $fieldrec->operator = 'contains'; - $this->assertEquals( - '{"op":"&","showc":[true],"c":[{"type":"profile","op":"contains","sf":"email","v":"@"}]}', - upgrade_availability_item(0, 0, 0, 0, 1, array(), array($fieldrec))); - $fieldrec->operator = 'isnotempty'; - $fieldrec->userfield = null; - $fieldrec->shortname = 'frogtype'; - $this->assertEquals( - '{"op":"&","showc":[false],"c":[{"type":"profile","op":"isnotempty","cf":"frogtype"}]}', - upgrade_availability_item(0, 0, 0, 0, 0, array(), array($fieldrec))); - - // Everything at once. - $this->assertEquals('{"op":"&","showc":[false,true,false,true,true,true],' . - '"c":[{"type":"grouping","id":13},' . - '{"type":"date","d":">=","t":990},' . - '{"type":"date","d":"<","t":991},' . - '{"type":"grade","id":665,"min":70.00000},' . - '{"type":"completion","cm":42,"e":2},' . - '{"type":"profile","op":"isempty","sf":"email"}]}', - upgrade_availability_item(1, 13, 990, 991, 1, array( - (object)array('sourcecmid' => null, 'gradeitemid' => 665, 'grademin' => 70), - (object)array('sourcecmid' => 42, 'gradeitemid' => null, 'requiredcompletion' => 2) - ), array( - (object)array('userfield' => 'email', 'shortname' => null, 'operator' => 'isempty'), - ))); - } - /** * Test upgrade minmaxgrade step. */ @@ -488,6 +254,8 @@ public function test_upgrade_extra_credit_weightoverride() { $this->resetAfterTest(true); + require_once($CFG->libdir . '/db/upgradelib.php'); + $c = array(); $a = array(); $gi = array(); @@ -551,8 +319,11 @@ public function test_upgrade_extra_credit_weightoverride() { */ public function test_upgrade_calculated_grade_items_freeze() { global $DB, $CFG; + $this->resetAfterTest(); + require_once($CFG->libdir . '/db/upgradelib.php'); + // Create a user. $user = $this->getDataGenerator()->create_user(); @@ -679,8 +450,11 @@ public function test_upgrade_calculated_grade_items_freeze() { function test_upgrade_calculated_grade_items_regrade() { global $DB, $CFG; + $this->resetAfterTest(); + require_once($CFG->libdir . '/db/upgradelib.php'); + // Create a user. $user = $this->getDataGenerator()->create_user(); @@ -743,9 +517,12 @@ function test_upgrade_calculated_grade_items_regrade() { } public function test_upgrade_course_tags() { - global $DB; + global $DB, $CFG; + $this->resetAfterTest(); + require_once($CFG->libdir . '/db/upgradelib.php'); + // Running upgrade script when there are no tags. upgrade_course_tags(); $this->assertFalse($DB->record_exists('tag_instance', array())); diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 255b7647e4105..50cc8dadf4a59 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -3,6 +3,19 @@ information provided here is intended especially for developers. === 3.1 === +* The following functions, previously used (exclusively) by upgrade steps are not available + anymore because of the upgrade cleanup performed for this version. See MDL-51580 for more info: + - upgrade_mysql_fix_unsigned_and_lob_columns() + - upgrade_course_completion_remove_duplicates() + - upgrade_save_orphaned_questions() + - upgrade_rename_old_backup_files_using_shortname() + - upgrade_mssql_nvarcharmax() + - upgrade_mssql_varbinarymax() + - upgrade_fix_missing_root_folders() + - upgrade_course_modules_sequences() + - upgrade_grade_item_fix_sortorder() + - upgrade_availability_item() + * Plugins can extend the navigation for user by declaring the following callback: _extend_navigation_user(navigation_node $parentnode, stdClass $user, context_user $context, stdClass $course, diff --git a/lib/upgradelib.php b/lib/upgradelib.php index 1771153be9097..4f96d38b370f1 100644 --- a/lib/upgradelib.php +++ b/lib/upgradelib.php @@ -1915,300 +1915,6 @@ function admin_mnet_method_profile(Zend_Server_Reflection_Function_Abstract $fun return $profile; } - -/** - * This function finds duplicate records (based on combinations of fields that should be unique) - * and then progamatically generated a "most correct" version of the data, update and removing - * records as appropriate - * - * Thanks to Dan Marsden for help - * - * @param string $table Table name - * @param array $uniques Array of field names that should be unique - * @param array $fieldstocheck Array of fields to generate "correct" data from (optional) - * @return void - */ -function upgrade_course_completion_remove_duplicates($table, $uniques, $fieldstocheck = array()) { - global $DB; - - // Find duplicates - $sql_cols = implode(', ', $uniques); - - $sql = "SELECT {$sql_cols} FROM {{$table}} GROUP BY {$sql_cols} HAVING (count(id) > 1)"; - $duplicates = $DB->get_recordset_sql($sql, array()); - - // Loop through duplicates - foreach ($duplicates as $duplicate) { - $pointer = 0; - - // Generate SQL for finding records with these duplicate uniques - $sql_select = implode(' = ? AND ', $uniques).' = ?'; // builds "fieldname = ? AND fieldname = ?" - $uniq_values = array(); - foreach ($uniques as $u) { - $uniq_values[] = $duplicate->$u; - } - - $sql_order = implode(' DESC, ', $uniques).' DESC'; // builds "fieldname DESC, fieldname DESC" - - // Get records with these duplicate uniques - $records = $DB->get_records_select( - $table, - $sql_select, - $uniq_values, - $sql_order - ); - - // Loop through and build a "correct" record, deleting the others - $needsupdate = false; - $origrecord = null; - foreach ($records as $record) { - $pointer++; - if ($pointer === 1) { // keep 1st record but delete all others. - $origrecord = $record; - } else { - // If we have fields to check, update original record - if ($fieldstocheck) { - // we need to keep the "oldest" of all these fields as the valid completion record. - // but we want to ignore null values - foreach ($fieldstocheck as $f) { - if ($record->$f && (($origrecord->$f > $record->$f) || !$origrecord->$f)) { - $origrecord->$f = $record->$f; - $needsupdate = true; - } - } - } - $DB->delete_records($table, array('id' => $record->id)); - } - } - if ($needsupdate || isset($origrecord->reaggregate)) { - // If this table has a reaggregate field, update to force recheck on next cron run - if (isset($origrecord->reaggregate)) { - $origrecord->reaggregate = time(); - } - $DB->update_record($table, $origrecord); - } - } -} - -/** - * Find questions missing an existing category and associate them with - * a category which purpose is to gather them. - * - * @return void - */ -function upgrade_save_orphaned_questions() { - global $DB; - - // Looking for orphaned questions - $orphans = $DB->record_exists_select('question', - 'NOT EXISTS (SELECT 1 FROM {question_categories} WHERE {question_categories}.id = {question}.category)'); - if (!$orphans) { - return; - } - - // Generate a unique stamp for the orphaned questions category, easier to identify it later on - $uniquestamp = "unknownhost+120719170400+orphan"; - $systemcontext = context_system::instance(); - - // Create the orphaned category at system level - $cat = $DB->get_record('question_categories', array('stamp' => $uniquestamp, - 'contextid' => $systemcontext->id)); - if (!$cat) { - $cat = new stdClass(); - $cat->parent = 0; - $cat->contextid = $systemcontext->id; - $cat->name = get_string('orphanedquestionscategory', 'question'); - $cat->info = get_string('orphanedquestionscategoryinfo', 'question'); - $cat->sortorder = 999; - $cat->stamp = $uniquestamp; - $cat->id = $DB->insert_record("question_categories", $cat); - } - - // Set a category to those orphans - $params = array('catid' => $cat->id); - $DB->execute('UPDATE {question} SET category = :catid WHERE NOT EXISTS - (SELECT 1 FROM {question_categories} WHERE {question_categories}.id = {question}.category)', $params); -} - -/** - * Rename old backup files to current backup files. - * - * When added the setting 'backup_shortname' (MDL-28657) the backup file names did not contain the id of the course. - * Further we fixed that behaviour by forcing the id to be always present in the file name (MDL-33812). - * This function will explore the backup directory and attempt to rename the previously created files to include - * the id in the name. Doing this will put them back in the process of deleting the excess backups for each course. - * - * This function manually recreates the file name, instead of using - * {@link backup_plan_dbops::get_default_backup_filename()}, use it carefully if you're using it outside of the - * usual upgrade process. - * - * @see backup_cron_automated_helper::remove_excess_backups() - * @link http://tracker.moodle.org/browse/MDL-35116 - * @return void - * @since Moodle 2.4 - */ -function upgrade_rename_old_backup_files_using_shortname() { - global $CFG; - $dir = get_config('backup', 'backup_auto_destination'); - $useshortname = get_config('backup', 'backup_shortname'); - if (empty($dir) || !is_dir($dir) || !is_writable($dir)) { - return; - } - - require_once($CFG->dirroot.'/backup/util/includes/backup_includes.php'); - $backupword = str_replace(' ', '_', core_text::strtolower(get_string('backupfilename'))); - $backupword = trim(clean_filename($backupword), '_'); - $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-'; - $regex = '#^'.preg_quote($filename, '#').'.*\.mbz$#'; - $thirtyapril = strtotime('30 April 2012 00:00'); - - // Reading the directory. - if (!$files = scandir($dir)) { - return; - } - foreach ($files as $file) { - // Skip directories and files which do not start with the common prefix. - // This avoids working on files which are not related to this issue. - if (!is_file($dir . '/' . $file) || !preg_match($regex, $file)) { - continue; - } - - // Extract the information from the XML file. - try { - $bcinfo = backup_general_helper::get_backup_information_from_mbz($dir . '/' . $file); - } catch (backup_helper_exception $e) { - // Some error while retrieving the backup informations, skipping... - continue; - } - - // Make sure this a course backup. - if ($bcinfo->format !== backup::FORMAT_MOODLE || $bcinfo->type !== backup::TYPE_1COURSE) { - continue; - } - - // Skip the backups created before the short name option was initially introduced (MDL-28657). - // This was integrated on the 2nd of May 2012. Let's play safe with timezone and use the 30th of April. - if ($bcinfo->backup_date < $thirtyapril) { - continue; - } - - // Let's check if the file name contains the ID where it is supposed to be, if it is the case then - // we will skip the file. Of course it could happen that the course ID is identical to the course short name - // even though really unlikely, but then renaming this file is not necessary. If the ID is not found in the - // file name then it was probably the short name which was used. - $idfilename = $filename . $bcinfo->original_course_id . '-'; - $idregex = '#^'.preg_quote($idfilename, '#').'.*\.mbz$#'; - if (preg_match($idregex, $file)) { - continue; - } - - // Generating the file name manually. We do not use backup_plan_dbops::get_default_backup_filename() because - // it will query the database to get some course information, and the course could not exist any more. - $newname = $filename . $bcinfo->original_course_id . '-'; - if ($useshortname) { - $shortname = str_replace(' ', '_', $bcinfo->original_course_shortname); - $shortname = core_text::strtolower(trim(clean_filename($shortname), '_')); - $newname .= $shortname . '-'; - } - - $backupdateformat = str_replace(' ', '_', get_string('backupnameformat', 'langconfig')); - $date = userdate($bcinfo->backup_date, $backupdateformat, 99, false); - $date = core_text::strtolower(trim(clean_filename($date), '_')); - $newname .= $date; - - if (isset($bcinfo->root_settings['users']) && !$bcinfo->root_settings['users']) { - $newname .= '-nu'; - } else if (isset($bcinfo->root_settings['anonymize']) && $bcinfo->root_settings['anonymize']) { - $newname .= '-an'; - } - $newname .= '.mbz'; - - // Final check before attempting the renaming. - if ($newname == $file || file_exists($dir . '/' . $newname)) { - continue; - } - @rename($dir . '/' . $file, $dir . '/' . $newname); - } -} - -/** - * Detect duplicate grade item sortorders and resort the - * items to remove them. - */ -function upgrade_grade_item_fix_sortorder() { - global $DB; - - // The simple way to fix these sortorder duplicates would be simply to resort each - // affected course. But in order to reduce the impact of this upgrade step we're trying - // to do it more efficiently by doing a series of update statements rather than updating - // every single grade item in affected courses. - - $sql = "SELECT DISTINCT g1.courseid - FROM {grade_items} g1 - JOIN {grade_items} g2 ON g1.courseid = g2.courseid - WHERE g1.sortorder = g2.sortorder AND g1.id != g2.id - ORDER BY g1.courseid ASC"; - foreach ($DB->get_fieldset_sql($sql) as $courseid) { - $transaction = $DB->start_delegated_transaction(); - $items = $DB->get_records('grade_items', array('courseid' => $courseid), '', 'id, sortorder, sortorder AS oldsort'); - - // Get all duplicates in course order, highest sort order, and higest id first so that we can make space at the - // bottom higher end of the sort orders and work down by id. - $sql = "SELECT DISTINCT g1.id, g1.sortorder - FROM {grade_items} g1 - JOIN {grade_items} g2 ON g1.courseid = g2.courseid - WHERE g1.sortorder = g2.sortorder AND g1.id != g2.id AND g1.courseid = :courseid - ORDER BY g1.sortorder DESC, g1.id DESC"; - - // This is the O(N*N) like the database version we're replacing, but at least the constants are a billion times smaller... - foreach ($DB->get_records_sql($sql, array('courseid' => $courseid)) as $duplicate) { - foreach ($items as $item) { - if ($item->sortorder > $duplicate->sortorder || ($item->sortorder == $duplicate->sortorder && $item->id > $duplicate->id)) { - $item->sortorder += 1; - } - } - } - foreach ($items as $item) { - if ($item->sortorder != $item->oldsort) { - $DB->update_record('grade_items', array('id' => $item->id, 'sortorder' => $item->sortorder)); - } - } - - $transaction->allow_commit(); - } -} - -/** - * Detect file areas with missing root directory records and add them. - */ -function upgrade_fix_missing_root_folders() { - global $DB, $USER; - - $transaction = $DB->start_delegated_transaction(); - - $sql = "SELECT contextid, component, filearea, itemid - FROM {files} - WHERE (component <> 'user' OR filearea <> 'draft') - GROUP BY contextid, component, filearea, itemid - HAVING MAX(CASE WHEN filename = '.' AND filepath = '/' THEN 1 ELSE 0 END) = 0"; - - $rs = $DB->get_recordset_sql($sql); - $defaults = array('filepath' => '/', - 'filename' => '.', - 'userid' => 0, // Don't rely on any particular user for these system records. - 'filesize' => 0, - 'timecreated' => time(), - 'timemodified' => time(), - 'contenthash' => sha1('')); - foreach ($rs as $r) { - $pathhash = sha1("/$r->contextid/$r->component/$r->filearea/$r->itemid/."); - $DB->insert_record('files', (array)$r + $defaults + - array('pathnamehash' => $pathhash)); - } - $rs->close(); - $transaction->allow_commit(); -} - /** * Detect draft file areas with missing root directory records and add them. */ diff --git a/mod/assignment/db/upgradelib.php b/mod/assignment/db/upgradelib.php deleted file mode 100644 index d245d359fc155..0000000000000 --- a/mod/assignment/db/upgradelib.php +++ /dev/null @@ -1,54 +0,0 @@ -. - -/** - * Assignment upgrade script. - * - * @package mod_assignment - * @copyright 2013 Damyon Wiese - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Inform admins about assignments that still need upgrading. - */ -function mod_assignment_pending_upgrades_notification($count) { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - - $a = new stdClass; - $a->count = $count; - $a->docsurl = get_docs_url('Assignment_upgrade_tool'); - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = \core_user::get_noreply_user(); - $message->userto = $admin; - $message->smallmessage = get_string('pendingupgrades_message_small', 'mod_assignment'); - $message->subject = get_string('pendingupgrades_message_subject', 'mod_assignment'); - $message->fullmessage = get_string('pendingupgrades_message_content', 'mod_assignment', $a); - $message->fullmessagehtml = get_string('pendingupgrades_message_content', 'mod_assignment', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/mod/book/db/upgradelib.php b/mod/book/db/upgradelib.php deleted file mode 100644 index 73d0a0af59a1d..0000000000000 --- a/mod/book/db/upgradelib.php +++ /dev/null @@ -1,172 +0,0 @@ -. - -/** - * 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 (core_text::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, $OUTPUT; - - $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); - if (empty($cm) || empty($cm->id)) { - echo $OUTPUT->notification("Course module not found, skipping: {$book->name}"); - continue; - } - $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/upgrade.txt b/mod/book/upgrade.txt index 14dade6d51688..53f766d96d4c4 100644 --- a/mod/book/upgrade.txt +++ b/mod/book/upgrade.txt @@ -1,5 +1,13 @@ This files describes API changes in the book code. +=== 3.1 === + +* The following functions, previously used (exclusively) by upgrade steps are not available + anymore because of the upgrade cleanup performed for this version. See MDL-51580 for more info: + - mod_book_migrate_moddata_dir_to_legacy() + - mod_book_migrate_all_areas() + - mod_book_migrate_area() + === 3.0 === * External function mod_book_external::get_books_by_courses returned parameter "name" has been changed to PARAM_RAW, @@ -8,4 +16,4 @@ This files describes API changes in the book code. === 2.7 === * bogus legacy log calls were removed -* \mod_book\event\chapter_deleted::set_legacy_logdata() was removed \ No newline at end of file +* \mod_book\event\chapter_deleted::set_legacy_logdata() was removed diff --git a/portfolio/boxnet/db/upgradelib.php b/portfolio/boxnet/db/upgradelib.php deleted file mode 100644 index fe87bd6cbf744..0000000000000 --- a/portfolio/boxnet/db/upgradelib.php +++ /dev/null @@ -1,55 +0,0 @@ -. - -/** - * Locallib. - * - * @package portfolio_boxnet - * @copyright 2013 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Send a message to the admin in regard with the APIv1 migration. - * - * @return void - */ -function portfolio_boxnet_admin_upgrade_notification() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - $a = new stdClass(); - $a->docsurl = get_docs_url('Box.net_APIv1_migration'); - - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('apiv1migration_message_small', 'portfolio_boxnet'); - $message->subject = get_string('apiv1migration_message_subject', 'portfolio_boxnet'); - $message->fullmessage = get_string('apiv1migration_message_content', 'portfolio_boxnet', $a); - $message->fullmessagehtml = get_string('apiv1migration_message_content', 'portfolio_boxnet', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/portfolio/googledocs/db/upgradelib.php b/portfolio/googledocs/db/upgradelib.php deleted file mode 100644 index 4658ed8deb5ce..0000000000000 --- a/portfolio/googledocs/db/upgradelib.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Googledocs portfolio upgrade script. - * - * @package portfolio_googledocs - * @copyright 2013 Dan Poltawski - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Inform admins about setup required for googledocs change. - */ -function portfolio_googledocs_admin_upgrade_notification() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - $a = new stdClass; - $a->docsurl = get_docs_url('Google_OAuth_2.0_setup'); - - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('oauth2upgrade_message_small', 'portfolio_googledocs'); - $message->subject = get_string('oauth2upgrade_message_subject', 'portfolio_googledocs'); - $message->fullmessage = get_string('oauth2upgrade_message_content', 'portfolio_googledocs', $a); - $message->fullmessagehtml = get_string('oauth2upgrade_message_content', 'portfolio_googledocs', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/portfolio/picasa/db/upgradelib.php b/portfolio/picasa/db/upgradelib.php deleted file mode 100644 index a711cbfc46ff8..0000000000000 --- a/portfolio/picasa/db/upgradelib.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Picasa portfolio upgrade script. - * - * @package portfolio_picasa - * @copyright 2013 Dan Poltawski - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Inform admins about setup required for picasa change. - */ -function portfolio_picasa_admin_upgrade_notification() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - $a = new stdClass; - $a->docsurl = get_docs_url('Google_OAuth_2.0_setup'); - - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('oauth2upgrade_message_small', 'portfolio_picasa'); - $message->subject = get_string('oauth2upgrade_message_subject', 'portfolio_picasa'); - $message->fullmessage = get_string('oauth2upgrade_message_content', 'portfolio_picasa', $a); - $message->fullmessagehtml = get_string('oauth2upgrade_message_content', 'portfolio_picasa', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/portfolio/upgrade.txt b/portfolio/upgrade.txt index 557a33b34bc2a..49d49937e6c1a 100644 --- a/portfolio/upgrade.txt +++ b/portfolio/upgrade.txt @@ -1,6 +1,14 @@ This files describes API changes in /portfolio/ portfolio system, information provided here is intended especially for developers. +=== 3.1 === + +* The following functions, previously used (exclusively) by upgrade steps are not available + anymore because of the upgrade cleanup performed for this version. See MDL-51580 for more info: + - portfolio_picasa_admin_upgrade_notification() + - portfolio_googledocs_admin_upgrade_notification() + - portfolio_boxnet_admin_upgrade_notification() + === 2.4 === The set_callback_options function's third parameter has been changed from a file path diff --git a/question/type/upgrade.txt b/question/type/upgrade.txt index 2cd5513fcbb3f..470629c4b2618 100644 --- a/question/type/upgrade.txt +++ b/question/type/upgrade.txt @@ -1,5 +1,11 @@ This files describes API changes for question type plugins. +=== 3.1 === + +* The following functions, previously used (exclusively) by upgrade steps are not available + anymore because of the upgrade cleanup performed for this version. See MDL-51580 for more info: + - qtype_essay_convert_to_html() + === 2.7 === + We have added a new method to the question_type base class 'break_down_stats_and_response_analysis_by_variant'. By default it returns true. If your question type does not have variants of question instances then you can ignore this method as it only diff --git a/repository/alfresco/db/upgradelib.php b/repository/alfresco/db/upgradelib.php deleted file mode 100644 index 1a363e68542d4..0000000000000 --- a/repository/alfresco/db/upgradelib.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Locallib. - * - * @package repository_alfresco - * @copyright 2014 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Send a message to the admin in regard with the APIv1 migration. - * - * @return void - */ -function repository_alfresco_admin_security_key_notice() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('security_key_notice_message_small', 'repository_alfresco'); - $message->subject = get_string('security_key_notice_message_subject', 'repository_alfresco'); - $message->fullmessage = get_string('security_key_notice_message_content', 'repository_alfresco'); - $message->fullmessagehtml = get_string('security_key_notice_message_content', 'repository_alfresco'); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/repository/boxnet/db/upgradelib.php b/repository/boxnet/db/upgradelib.php deleted file mode 100644 index c0cf9de80d635..0000000000000 --- a/repository/boxnet/db/upgradelib.php +++ /dev/null @@ -1,55 +0,0 @@ -. - -/** - * Locallib. - * - * @package repository_boxnet - * @copyright 2013 Frédéric Massart - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Send a message to the admin in regard with the APIv1 migration. - * - * @return void - */ -function repository_boxnet_admin_upgrade_notification() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - $a = new stdClass(); - $a->docsurl = get_docs_url('Box.net_APIv1_migration'); - - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('apiv1migration_message_small', 'repository_boxnet'); - $message->subject = get_string('apiv1migration_message_subject', 'repository_boxnet'); - $message->fullmessage = get_string('apiv1migration_message_content', 'repository_boxnet', $a); - $message->fullmessagehtml = get_string('apiv1migration_message_content', 'repository_boxnet', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/repository/googledocs/db/upgradelib.php b/repository/googledocs/db/upgradelib.php deleted file mode 100644 index c065bd0a87e4f..0000000000000 --- a/repository/googledocs/db/upgradelib.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Googledocs repository upgrade script. - * - * @package repository_googledocs - * @copyright 2013 Dan Poltawski - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Inform admins about setup required for googledocs change. - */ -function repository_googledocs_admin_upgrade_notification() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - - $a = new stdClass; - $a->docsurl = get_docs_url('Google_OAuth_2.0_setup'); - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('oauth2upgrade_message_small', 'repository_googledocs'); - $message->subject = get_string('oauth2upgrade_message_subject', 'repository_googledocs'); - $message->fullmessage = get_string('oauth2upgrade_message_content', 'repository_googledocs', $a); - $message->fullmessagehtml = get_string('oauth2upgrade_message_content', 'repository_googledocs', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/repository/picasa/db/upgradelib.php b/repository/picasa/db/upgradelib.php deleted file mode 100644 index 4d76af52bef06..0000000000000 --- a/repository/picasa/db/upgradelib.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Picasa repository upgrade script. - * - * @package repository_picasa - * @copyright 2013 Dan Poltawski - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/** - * Inform admins about setup required for google picasa change. - */ -function repository_picasa_admin_upgrade_notification() { - $admins = get_admins(); - - if (empty($admins)) { - return; - } - $a = new stdClass; - $a->docsurl = get_docs_url('Google_OAuth_2.0_setup'); - - foreach ($admins as $admin) { - $message = new stdClass(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = get_admin(); - $message->userto = $admin; - $message->smallmessage = get_string('oauth2upgrade_message_small', 'repository_picasa'); - $message->subject = get_string('oauth2upgrade_message_subject', 'repository_picasa'); - $message->fullmessage = get_string('oauth2upgrade_message_content', 'repository_picasa', $a); - $message->fullmessagehtml = get_string('oauth2upgrade_message_content', 'repository_picasa', $a); - $message->fullmessageformat = FORMAT_PLAIN; - $message->notification = 1; - message_send($message); - } -} diff --git a/repository/upgrade.txt b/repository/upgrade.txt index e47ba3be344f4..e190f817c8b0f 100644 --- a/repository/upgrade.txt +++ b/repository/upgrade.txt @@ -3,6 +3,15 @@ information provided here is intended especially for developers. Full details of the repository API are available on Moodle docs: http://docs.moodle.org/dev/Repository_API +=== 3.1 === + +* The following functions, previously used (exclusively) by upgrade steps are not available + anymore because of the upgrade cleanup performed for this version. See MDL-51580 for more info: + - repository_picasa_admin_upgrade_notification() + - repository_googledocs_admin_upgrade_notification() + - repository_boxnet_admin_upgrade_notification() + - repository_alfresco_admin_security_key_notice() + === 2.8 === * Repositories working with Moodle files must replace serialize() with json_encode() in the