Permalink
Browse files

Merge branch 'MOODLE_24_STABLE' into install_24_STABLE

  • Loading branch information...
2 parents 26af11e + abb7671 commit a8416f35c5d01bf66118289140bb88422833cc6e AMOS bot committed Aug 24, 2013
View
@@ -113,31 +113,46 @@
// Mark the UI finished.
$rc->finish_ui();
// Execute prechecks
+ $warnings = false;
if (!$rc->execute_precheck()) {
$precheckresults = $rc->get_precheck_results();
- if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
- fulldelete($tempdestination);
-
- echo $OUTPUT->header();
- echo $renderer->precheck_notices($precheckresults);
- echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
- echo $OUTPUT->footer();
- die();
+ if (is_array($precheckresults)) {
+ if (!empty($precheckresults['errors'])) { // If errors are found, terminate the import.
+ fulldelete($tempdestination);
+
+ echo $OUTPUT->header();
+ echo $renderer->precheck_notices($precheckresults);
+ echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
+ echo $OUTPUT->footer();
+ die();
+ }
+ if (!empty($precheckresults['warnings'])) { // If warnings are found, go ahead but display warnings later.
+ $warnings = $precheckresults['warnings'];
+ }
}
- } else {
- if ($restoretarget == backup::TARGET_CURRENT_DELETING || $restoretarget == backup::TARGET_EXISTING_DELETING) {
- restore_dbops::delete_course_content($course->id);
- }
- // Execute the restore
- $rc->execute_plan();
}
+ if ($restoretarget == backup::TARGET_CURRENT_DELETING || $restoretarget == backup::TARGET_EXISTING_DELETING) {
+ restore_dbops::delete_course_content($course->id);
+ }
+ // Execute the restore.
+ $rc->execute_plan();
// Delete the temp directory now
fulldelete($tempdestination);
// Display a notification and a continue button
echo $OUTPUT->header();
- echo $OUTPUT->notification(get_string('importsuccess', 'backup'),'notifysuccess');
+ if ($warnings) {
+ echo $OUTPUT->box_start();
+ echo $OUTPUT->notification(get_string('warning'), 'notifywarning');
+ echo html_writer::start_tag('ul', array('class'=>'list'));
+ foreach ($warnings as $warning) {
+ echo html_writer::tag('li', $warning);
+ }
+ echo html_writer::end_tag('ul');
+ echo $OUTPUT->box_end();
+ }
+ echo $OUTPUT->notification(get_string('importsuccess', 'backup'), 'notifysuccess');
echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
echo $OUTPUT->footer();
@@ -35,6 +35,18 @@
*/
abstract class restore_qtype_plugin extends restore_plugin {
+ /*
+ * A simple answer to id cache for a single questions answers.
+ * @var array
+ */
+ private $questionanswercache = array();
+
+ /*
+ * The id of the current question in the questionanswercache.
+ * @var int
+ */
+ private $questionanswercacheid = null;
+
/**
* Add to $paths the restore_path_elements needed
* to handle question_answers for a given question
@@ -147,38 +159,32 @@ public function process_question_answer($data) {
// The question existed, we need to map the existing question_answers
} else {
- // Look in question_answers by answertext matching
- $sql = 'SELECT id
- FROM {question_answers}
- WHERE question = ?
- AND ' . $DB->sql_compare_text('answer', 255) . ' = ' . $DB->sql_compare_text('?', 255);
- $params = array($newquestionid, $data->answertext);
- $newitemid = $DB->get_field_sql($sql, $params);
-
- // Not able to find the answer, let's try cleaning the answertext
- // of all the question answers in DB as slower fallback. MDL-30018.
- if (!$newitemid) {
+ // Have we cached the current question?
+ if ($this->questionanswercacheid !== $newquestionid) {
+ // The question changed, purge and start again!
+ $this->questionanswercache = array();
$params = array('question' => $newquestionid);
$answers = $DB->get_records('question_answers', $params, '', 'id, answer');
+ $this->questionanswercacheid = $newquestionid;
+ // Cache all cleaned answers for a simple text match.
foreach ($answers as $answer) {
- // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+ // MDL-30018: Clean in the same way as {@link xml_writer::xml_safe_utf8()}.
$clean = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $answer->answer); // Clean CTRL chars.
$clean = preg_replace("/\r\n|\r/", "\n", $clean); // Normalize line ending.
- if ($clean === $data->answertext) {
- $newitemid = $data->id;
- }
+ $this->questionanswercache[$clean] = $answer->id;
}
}
- // If we haven't found the newitemid, something has gone really wrong, question in DB
- // is missing answers, exception
- if (!$newitemid) {
+ if (!isset($this->questionanswercache[$data->answertext])) {
+ // If we haven't found the matching answer, something has gone really wrong, the question in the DB
+ // is missing answers, throw an exception.
$info = new stdClass();
$info->filequestionid = $oldquestionid;
$info->dbquestionid = $newquestionid;
$info->answer = $data->answertext;
throw new restore_step_exception('error_question_answers_missing_in_db', $info);
}
+ $newitemid = $this->questionanswercache[$data->answertext];
}
// Create mapping (we'll use this intensively when restoring question_states. And also answerfeedback files)
$this->set_mapping('question_answer', $oldid, $newitemid);
@@ -0,0 +1,71 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Calendar lib unit tests
+ *
+ * @package core_calendar
+ * @copyright 2013 Dan Poltawski <dan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+global $CFG;
+require_once($CFG->dirroot . '/calendar/lib.php');
+
+/**
+ * Unit tests for calendar lib
+ *
+ * @package core_calendar
+ * @copyright 2013 Dan Poltawski <dan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_calendar_lib_testcase extends advanced_testcase {
+
+ public function test_calendar_get_course_cached() {
+ $this->resetAfterTest(true);
+
+ // Setup some test courses.
+ $course1 = $this->getDataGenerator()->create_course();
+ $course2 = $this->getDataGenerator()->create_course();
+ $course3 = $this->getDataGenerator()->create_course();
+
+ // Load courses into cache.
+ $coursecache = null;
+ calendar_get_course_cached($coursecache, $course1->id);
+ calendar_get_course_cached($coursecache, $course2->id);
+ calendar_get_course_cached($coursecache, $course3->id);
+
+ // Verify the cache.
+ $this->assertArrayHasKey($course1->id, $coursecache);
+ $cachedcourse1 = $coursecache[$course1->id];
+ $this->assertEquals($course1->id, $cachedcourse1->id);
+ $this->assertEquals($course1->shortname, $cachedcourse1->shortname);
+ $this->assertEquals($course1->fullname, $cachedcourse1->fullname);
+
+ $this->assertArrayHasKey($course2->id, $coursecache);
+ $cachedcourse2 = $coursecache[$course2->id];
+ $this->assertEquals($course2->id, $cachedcourse2->id);
+ $this->assertEquals($course2->shortname, $cachedcourse2->shortname);
+ $this->assertEquals($course2->fullname, $cachedcourse2->fullname);
+
+ $this->assertArrayHasKey($course3->id, $coursecache);
+ $cachedcourse3 = $coursecache[$course3->id];
+ $this->assertEquals($course3->id, $cachedcourse3->id);
+ $this->assertEquals($course3->shortname, $cachedcourse3->shortname);
+ $this->assertEquals($course3->fullname, $cachedcourse3->fullname);
+ }
+}
View
@@ -487,7 +487,10 @@
// $CFG->debugusers = '2';
//
// Prevent theme caching
-// $CFG->themerev = -1; // NOT FOR PRODUCTION SERVERS!
+// $CFG->themedesignermode = true; // NOT FOR PRODUCTION SERVERS!
+//
+// Prevent JS caching
+// $CFG->cachejs = false; // NOT FOR PRODUCTION SERVERS!
//
// Prevent core_string_manager on-disk cache
// $CFG->langstringcache = false; // NOT FOR PRODUCTION SERVERS!
View
@@ -1159,7 +1159,9 @@ function get_array_of_activities($courseid) {
$mod[$seq]->extraclasses = $info->extraclasses;
}
if (!empty($info->iconurl)) {
- $mod[$seq]->iconurl = $info->iconurl;
+ // Convert URL to string as it's easier to store. Also serialized object contains \0 byte and can not be written to Postgres DB.
+ $url = new moodle_url($info->iconurl);
+ $mod[$seq]->iconurl = $url->out(false);
}
if (!empty($info->onclick)) {
$mod[$seq]->onclick = $info->onclick;
View
@@ -121,8 +121,8 @@ protected function process_file() {
continue;
}
- if (! $user = $DB->get_record("user", array("idnumber"=>$fields[2]))) {
- $this->log .= "Unknown user idnumber in field 3 - ignoring line\n";
+ if (! $user = $DB->get_record("user", array("idnumber"=>$fields[2], 'deleted'=>0))) {
+ $this->log .= "Unknown user idnumber or deleted user in field 3 - ignoring line\n";
continue;
}
@@ -250,4 +250,33 @@ public function test_enrol_user_sees_own_courses() {
$this->assertTrue(enrol_user_sees_own_courses());
$this->assertEquals($reads, $DB->perf_get_reads());
}
+
+ public function test_enrol_get_shared_courses() {
+ $this->resetAfterTest();
+
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $user3 = $this->getDataGenerator()->create_user();
+
+ $course1 = $this->getDataGenerator()->create_course();
+ $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
+ $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
+
+ $course2 = $this->getDataGenerator()->create_course();
+ $this->getDataGenerator()->enrol_user($user1->id, $course2->id);
+
+ // Test that user1 and user2 have courses in common.
+ $this->assertTrue(enrol_get_shared_courses($user1, $user2, false, true));
+ // Test that user1 and user3 have no courses in common.
+ $this->assertFalse(enrol_get_shared_courses($user1, $user3, false, true));
+
+ // Test retrieving the courses in common.
+ $sharedcourses = enrol_get_shared_courses($user1, $user2, true);
+
+ // Only should be one shared course.
+ $this->assertCount(1, $sharedcourses);
+ $sharedcourse = array_shift($sharedcourses);
+ // It should be course 1.
+ $this->assertEquals($sharedcourse->id, $course1->id);
+ }
}
@@ -1218,7 +1218,7 @@ public function sql_length($fieldname) {
}
public function sql_order_by_text($fieldname, $numchars=32) {
- return ' CONVERT(varchar, ' . $fieldname . ', ' . $numchars . ')';
+ return " CONVERT(varchar({$numchars}), {$fieldname})";
}
/**
@@ -1281,7 +1281,7 @@ public function sql_length($fieldname) {
}
public function sql_order_by_text($fieldname, $numchars = 32) {
- return ' CONVERT(varchar, '.$fieldname.', '.$numchars.')';
+ return " CONVERT(varchar({$numchars}), {$fieldname})";
}
/**
View
@@ -3573,7 +3573,7 @@ function test_cast_char2real() {
$this->assertEquals(next($records)->nametext, '91.10');
}
- function sql_compare_text() {
+ public function test_sql_compare_text() {
$DB = $this->tdb;
$dbman = $DB->get_manager();
@@ -3588,15 +3588,43 @@ function sql_compare_text() {
$DB->insert_record($tablename, array('name'=>'abcd', 'description'=>'abcd'));
$DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
- $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
+ $DB->insert_record($tablename, array('name'=>'aaaa', 'description'=>'aaaacccccccccccccccccc'));
+ $DB->insert_record($tablename, array('name'=>'xxxx', 'description'=>'123456789a123456789b123456789c123456789d'));
+ // Only some supported databases truncate TEXT fields for comparisons, currently MSSQL and Oracle.
+ $dbtruncatestextfields = ($DB->get_dbfamily() == 'mssql' || $DB->get_dbfamily() == 'oracle');
+
+ if ($dbtruncatestextfields) {
+ // Ensure truncation behaves as expected.
+
+ $sql = "SELECT " . $DB->sql_compare_text('description') . " AS field FROM {{$tablename}} WHERE name = ?";
+ $description = $DB->get_field_sql($sql, array('xxxx'));
+
+ // Should truncate to 32 chars (the default).
+ $this->assertEquals('123456789a123456789b123456789c12', $description);
+
+ $sql = "SELECT " . $DB->sql_compare_text('description', 35) . " AS field FROM {{$tablename}} WHERE name = ?";
+ $description = $DB->get_field_sql($sql, array('xxxx'));
+
+ // Should truncate to the specified number of chars.
+ $this->assertEquals('123456789a123456789b123456789c12345', $description);
+ }
+
+ // Ensure text field comparison is successful.
$sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description');
$records = $DB->get_records_sql($sql);
- $this->assertEquals(count($records), 1);
+ $this->assertCount(1, $records);
$sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description', 4);
$records = $DB->get_records_sql($sql);
- $this->assertEquals(count($records), 2);
+ if ($dbtruncatestextfields) {
+ // Should truncate description to 4 characters before comparing.
+ $this->assertCount(2, $records);
+ } else {
+ // Should leave untruncated, so one less match.
+ $this->assertCount(1, $records);
+ }
+
}
function test_unique_index_collation_trouble() {
View
@@ -1952,18 +1952,23 @@ function qf_errorHandler(element, _qfMsg) {
errorSpan.id = \'id_error_\'+element.name;
errorSpan.className = "error";
element.parentNode.insertBefore(errorSpan, element.parentNode.firstChild);
+ document.getElementById(errorSpan.id).setAttribute(\'TabIndex\', \'0\');
+ document.getElementById(errorSpan.id).focus();
}
while (errorSpan.firstChild) {
errorSpan.removeChild(errorSpan.firstChild);
}
errorSpan.appendChild(document.createTextNode(_qfMsg.substring(3)));
- errorSpan.appendChild(document.createElement("br"));
if (div.className.substr(div.className.length - 6, 6) != " error"
- && div.className != "error") {
- div.className += " error";
+ && div.className != "error") {
+ div.className += " error";
+ linebreak = document.createElement("br");
+ linebreak.className = "error";
+ linebreak.id = \'id_error_break_\'+element.name;
+ errorSpan.parentNode.insertBefore(linebreak, errorSpan.nextSibling);
}
return false;
@@ -1972,6 +1977,10 @@ function qf_errorHandler(element, _qfMsg) {
if (errorSpan) {
errorSpan.parentNode.removeChild(errorSpan);
}
+ var linebreak = document.getElementById(\'id_error_break_\'+element.name);
+ if (linebreak) {
+ linebreak.parentNode.removeChild(linebreak);
+ }
if (div.className.substr(div.className.length - 6, 6) == " error") {
div.className = div.className.substr(0, div.className.length - 6);
@@ -2019,7 +2028,7 @@ function validate_' . $this->_formName . '_' . $escapedElementName . '(element)
ret = validate_' . $this->_formName . '_' . $escapedElementName.'(frm.elements[\''.$elementName.'\']) && ret;
if (!ret && !first_focus) {
first_focus = true;
- frm.elements[\''.$elementName.'\'].focus();
+ document.getElementById(\'id_error_'.$elementName.'\').focus();
}
';
Oops, something went wrong.

0 comments on commit a8416f3

Please sign in to comment.