From 4ddf7c6025266271c5a01576b712c42af78f3afe Mon Sep 17 00:00:00 2001 From: Devang Gaur Date: Fri, 31 Mar 2017 19:58:40 +0530 Subject: [PATCH 1/2] MDL-55548 course: added timemodified field to course_sections table --- backup/moodle2/backup_stepslib.php | 7 ++++--- backup/moodle2/restore_stepslib.php | 14 +++++++++++--- course/lib.php | 2 ++ course/tests/courselib_test.php | 23 +++++++++++++++++++++++ lib/db/install.xml | 1 + lib/db/upgrade.php | 12 ++++++++++++ version.php | 4 ++-- 7 files changed, 55 insertions(+), 8 deletions(-) diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index acdf34b45ed..3303963d477 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -267,7 +267,7 @@ class backup_module_structure_step extends backup_structure_step { 'added', 'score', 'indent', 'visible', 'visibleoncoursepage', 'visibleold', 'groupmode', 'groupingid', 'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected', - 'availability', 'showdescription')); + 'availability', 'showdescription', 'timemodified')); $tags = new backup_nested_element('tags'); $tag = new backup_nested_element('tag', array('id'), array('name', 'rawname')); @@ -291,7 +291,8 @@ class backup_module_structure_step extends backup_structure_step { // Set the sources $concat = $DB->sql_concat("'mod_'", 'm.name'); $module->set_source_sql(" - SELECT cm.*, cp.value AS version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber + SELECT cm.*, cp.value AS version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber, + s.timemodified AS timemodified FROM {course_modules} cm JOIN {modules} m ON m.id = cm.module JOIN {config_plugins} cp ON cp.plugin = $concat AND cp.name = 'version' @@ -325,7 +326,7 @@ class backup_section_structure_step extends backup_structure_step { $section = new backup_nested_element('section', array('id'), array( 'number', 'name', 'summary', 'summaryformat', 'sequence', 'visible', - 'availabilityjson')); + 'availabilityjson', 'timemodified')); // attach format plugin structure to $section element, only one allowed $this->add_plugin_structure('format', $section, false); diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index 5d607ef780e..6ef247820ec 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -795,7 +795,8 @@ class restore_rebuild_course_cache extends restore_execution_step { if (!$DB->record_exists('course_sections', array('course' => $this->get_courseid(), 'section' => $i))) { $sectionrec = array( 'course' => $this->get_courseid(), - 'section' => $i); + 'section' => $i, + 'timemodified' => 0); $DB->insert_record('course_sections', $sectionrec); // missing section created } } @@ -1592,6 +1593,8 @@ class restore_section_structure_step extends restore_structure_step { $data, true); } } + + $section->timemodified = !isset($data->timemodified) ? 0 : $this->apply_date_offset($data->timemodified); $newitemid = $DB->insert_record('course_sections', $section); $section->id = $newitemid; @@ -1611,6 +1614,7 @@ class restore_section_structure_step extends restore_structure_step { $restorefiles = true; } + $section->timemodified = !isset($data->timemodified) ? 0 : $this->apply_date_offset($data->timemodified); // Don't update availability (I didn't see a useful way to define // whether existing or new one should take precedence). @@ -4014,6 +4018,8 @@ class restore_module_structure_step extends restore_structure_step { $oldid = $data->id; $this->task->set_old_moduleversion($data->version); + $timemodified = !isset($data->timemodified) ? 0 : $this->apply_date_offset($data->timemodified); + $data->course = $this->task->get_courseid(); $data->module = $DB->get_field('modules', 'id', array('name' => $data->modulename)); // Map section (first try by course_section mapping match. Useful in course and section restores) @@ -4032,11 +4038,13 @@ class restore_module_structure_step extends restore_structure_step { if (!$data->section) { // no sections in course, create section 0 and 1 and assign module to 1 $sectionrec = array( 'course' => $this->get_courseid(), - 'section' => 0); + 'section' => 0, + 'timemodified' => $timemodified); $DB->insert_record('course_sections', $sectionrec); // section 0 $sectionrec = array( 'course' => $this->get_courseid(), - 'section' => 1); + 'section' => 1, + 'timemodified' => $timemodified); $data->section = $DB->insert_record('course_sections', $sectionrec); // section 1 } $data->groupingid= $this->get_mappingid('grouping', $data->groupingid); // grouping diff --git a/course/lib.php b/course/lib.php index e60bd2c48b4..6e7a5b704b9 100644 --- a/course/lib.php +++ b/course/lib.php @@ -863,6 +863,7 @@ function course_create_section($courseorid, $position = 0, $skipcheck = false) { $cw->name = null; $cw->visible = 1; $cw->availability = null; + $cw->timemodified = time(); $cw->id = $DB->insert_record("course_sections", $cw); // Now move it to the specified position. @@ -1611,6 +1612,7 @@ function course_update_section($course, $section, $data) { // Update record in the DB and course format options. $data['id'] = $section->id; + $data['timemodified'] = time(); $DB->update_record('course_sections', $data); rebuild_course_cache($courseid, true); course_get_format($courseid)->update_section_format_options($data); diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php index 61169d5b0b5..c58964800fe 100644 --- a/course/tests/courselib_test.php +++ b/course/tests/courselib_test.php @@ -678,6 +678,29 @@ class core_course_courselib_testcase extends advanced_testcase { } } + public function test_update_course_section_time_modified() { + global $DB; + + $this->resetAfterTest(); + + // Create the course with sections. + $course = $this->getDataGenerator()->create_course(array('numsections' => 10), array('createsections' => true)); + $sections = $DB->get_records('course_sections', array('course' => $course->id)); + + // Get the last section's time modified value. + $section = array_pop($sections); + $oldtimemodified = $section->timemodified; + + // Update the section. + sleep(1); // Ensuring that the section update occurs at a different timestamp. + course_update_section($course, $section, array()); + + // Check that the time has changed. + $section = $DB->get_record('course_sections', array('id' => $section->id)); + $newtimemodified = $section->timemodified; + $this->assertGreaterThan($oldtimemodified, $newtimemodified); + } + public function test_course_add_cm_to_section() { global $DB; $this->resetAfterTest(true); diff --git a/lib/db/install.xml b/lib/db/install.xml index 39ab0c62304..ce5dda2b38c 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -343,6 +343,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index b130390cf1e..d8a50609428 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2865,5 +2865,17 @@ function xmldb_main_upgrade($oldversion) { // Automatically generated Moodle v3.3.0 release upgrade line. // Put any upgrade step following this. + if ($oldversion < 2017061200.00) { + $table = new xmldb_table('course_sections'); + $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'availability'); + + // Define a field 'timemodified' in the 'course_sections' table, to background deletion tasks. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + upgrade_main_savepoint(true, 2017061200.00); + } + return true; } diff --git a/version.php b/version.php index e90db3493dd..9075dac9cd0 100644 --- a/version.php +++ b/version.php @@ -29,11 +29,11 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017060800.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2017061200.00; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. -$release = '3.4dev (Build: 20170608)'; // Human-friendly version name +$release = '3.4dev (Build: 20170612)'; // Human-friendly version name $branch = '34'; // This version's branch. $maturity = MATURITY_ALPHA; // This version's maturity level. From b75ff4744155ff4e241bee5491bd1f00c8c9eecc Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 11 Apr 2017 12:56:05 +0800 Subject: [PATCH 2/2] MDL-55548 backup: changes after review 1) There is no need to store the 'timemodified' value of the section when backing up a course module, they do not refer to the same time. 2) When creating a new course section during restore use the current time. 3) Added timemodified value to more places when updating the 'course_sections' table. --- availability/classes/info_section.php | 8 +++-- .../condition/date/classes/condition.php | 8 +++-- backup/moodle2/backup_stepslib.php | 5 ++-- backup/moodle2/restore_stepslib.php | 29 +++++++++++-------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/availability/classes/info_section.php b/availability/classes/info_section.php index d65729ae38d..6ef4fc96ddb 100644 --- a/availability/classes/info_section.php +++ b/availability/classes/info_section.php @@ -62,8 +62,12 @@ class info_section extends info { protected function set_in_database($availability) { global $DB; - $DB->set_field('course_sections', 'availability', $availability, - array('id' => $this->section->id)); + + $section = new \stdClass(); + $section->id = $this->section->id; + $section->availability = $availability; + $section->timemodified = time(); + $DB->update_record('course_sections', $section); } /** diff --git a/availability/condition/date/classes/condition.php b/availability/condition/date/classes/condition.php index 722b0247be2..63b61b4ebce 100644 --- a/availability/condition/date/classes/condition.php +++ b/availability/condition/date/classes/condition.php @@ -287,8 +287,12 @@ class condition extends \core_availability\condition { // Save the updated course module. if ($changed) { - $DB->set_field('course_sections', 'availability', json_encode($tree->save()), - array('id' => $section->id)); + $updatesection = new \stdClass(); + $updatesection->id = $section->id; + $updatesection->availability = json_encode($tree->save()); + $updatesection->timemodified = time(); + $DB->update_record('course_sections', $updatesection); + $anychanged = true; } } diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index 3303963d477..2ea524856bd 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -267,7 +267,7 @@ class backup_module_structure_step extends backup_structure_step { 'added', 'score', 'indent', 'visible', 'visibleoncoursepage', 'visibleold', 'groupmode', 'groupingid', 'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected', - 'availability', 'showdescription', 'timemodified')); + 'availability', 'showdescription')); $tags = new backup_nested_element('tags'); $tag = new backup_nested_element('tag', array('id'), array('name', 'rawname')); @@ -291,8 +291,7 @@ class backup_module_structure_step extends backup_structure_step { // Set the sources $concat = $DB->sql_concat("'mod_'", 'm.name'); $module->set_source_sql(" - SELECT cm.*, cp.value AS version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber, - s.timemodified AS timemodified + SELECT cm.*, cp.value AS version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber FROM {course_modules} cm JOIN {modules} m ON m.id = cm.module JOIN {config_plugins} cp ON cp.plugin = $concat AND cp.name = 'version' diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index 6ef247820ec..c788ac11c82 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -796,7 +796,7 @@ class restore_rebuild_course_cache extends restore_execution_step { $sectionrec = array( 'course' => $this->get_courseid(), 'section' => $i, - 'timemodified' => 0); + 'timemodified' => time()); $DB->insert_record('course_sections', $sectionrec); // missing section created } } @@ -1576,8 +1576,9 @@ class restore_section_structure_step extends restore_structure_step { $section = new stdclass(); $section->course = $this->get_courseid(); $section->section = $data->number; + $section->timemodified = isset($data->timemodified) ? $this->apply_date_offset($data->timemodified) : 0; // Section doesn't exist, create it with all the info from backup - if (!$secrec = $DB->get_record('course_sections', (array)$section)) { + if (!$secrec = $DB->get_record('course_sections', ['course' => $this->get_courseid(), 'section' => $data->number])) { $section->name = $data->name; $section->summary = $data->summary; $section->summaryformat = $data->summaryformat; @@ -1593,8 +1594,6 @@ class restore_section_structure_step extends restore_structure_step { $data, true); } } - - $section->timemodified = !isset($data->timemodified) ? 0 : $this->apply_date_offset($data->timemodified); $newitemid = $DB->insert_record('course_sections', $section); $section->id = $newitemid; @@ -1614,7 +1613,6 @@ class restore_section_structure_step extends restore_structure_step { $restorefiles = true; } - $section->timemodified = !isset($data->timemodified) ? 0 : $this->apply_date_offset($data->timemodified); // Don't update availability (I didn't see a useful way to define // whether existing or new one should take precedence). @@ -1725,8 +1723,12 @@ class restore_section_structure_step extends restore_structure_step { array('id' => $availfield->coursesectionid), MUST_EXIST); $newvalue = \core_availability\info::add_legacy_availability_field_condition( $currentvalue, $availfield, $show); - $DB->set_field('course_sections', 'availability', $newvalue, - array('id' => $availfield->coursesectionid)); + + $section = new stdClass(); + $section->id = $availfield->coursesectionid; + $section->availability = $newvalue; + $section->timemodified = time(); + $DB->update_record('course_sections', $section); } } @@ -4018,8 +4020,6 @@ class restore_module_structure_step extends restore_structure_step { $oldid = $data->id; $this->task->set_old_moduleversion($data->version); - $timemodified = !isset($data->timemodified) ? 0 : $this->apply_date_offset($data->timemodified); - $data->course = $this->task->get_courseid(); $data->module = $DB->get_field('modules', 'id', array('name' => $data->modulename)); // Map section (first try by course_section mapping match. Useful in course and section restores) @@ -4039,12 +4039,12 @@ class restore_module_structure_step extends restore_structure_step { $sectionrec = array( 'course' => $this->get_courseid(), 'section' => 0, - 'timemodified' => $timemodified); + 'timemodified' => time()); $DB->insert_record('course_sections', $sectionrec); // section 0 $sectionrec = array( 'course' => $this->get_courseid(), 'section' => 1, - 'timemodified' => $timemodified); + 'timemodified' => time()); $data->section = $DB->insert_record('course_sections', $sectionrec); // section 1 } $data->groupingid= $this->get_mappingid('grouping', $data->groupingid); // grouping @@ -4098,7 +4098,12 @@ class restore_module_structure_step extends restore_structure_step { } else { $sequence = $newitemid; } - $DB->set_field('course_sections', 'sequence', $sequence, array('id' => $data->section)); + + $updatesection = new \stdClass(); + $updatesection->id = $data->section; + $updatesection->sequence = $sequence; + $updatesection->timemodified = time(); + $DB->update_record('course_sections', $updatesection); // If there is the legacy showavailability data, store this for later use. // (This data is not present when restoring 'new' backups.)