Merge branch 'wip-MDL-28583-master' of git://github.com/marinaglancy/moodle
authorSam Hemelryk <sam@moodle.com>
Tue, 20 Nov 2012 20:15:34 +0000 (09:15 +1300)
committerSam Hemelryk <sam@moodle.com>
Tue, 20 Nov 2012 20:15:34 +0000 (09:15 +1300)
330 files changed:
admin/courseformats.php
admin/settings/plugins.php
admin/settings/server.php
admin/user.php
backup/converter/moodle1/lib.php
backup/converter/moodle1/tests/lib_test.php
backup/moodle2/backup_stepslib.php
backup/moodle2/restore_stepslib.php
blocks/activity_modules/block_activity_modules.php
blocks/community/block_community.php
blocks/course_list/block_course_list.php
blocks/course_overview/renderer.php
blocks/course_overview/styles.css
blocks/dock.js
blocks/glossary_random/block_glossary_random.php
blocks/navigation/styles.css
blocks/participants/block_participants.php
blocks/private_files/renderer.php
blocks/settings/styles.css
blocks/site_main_menu/block_site_main_menu.php
blocks/site_main_menu/styles.css [new file with mode: 0644]
cache/classes/config.php
cache/classes/definition.php
cache/classes/dummystore.php
cache/classes/factory.php
cache/classes/helper.php
cache/classes/interfaces.php
cache/classes/loaders.php
cache/locallib.php
cache/stores/file/lib.php
cache/stores/memcache/lib.php
cache/stores/memcached/lib.php
cache/stores/mongodb/lib.php
cache/stores/session/lib.php
cache/stores/static/lib.php
cache/testperformance.php
cache/tests/locallib_test.php
calendar/lib.php
calendar/managesubscriptions_form.php
calendar/renderer.php
cohort/assign.php
course/category.php
course/dndupload.js
course/format/renderer.php
course/format/topics/styles.css
course/format/weeks/styles.css
course/index.php
course/lib.php
course/renderer.php
course/search.php
course/tests/courselib_test.php
course/yui/dragdrop/dragdrop.js
course/yui/toolboxes/toolboxes.js
enrol/flatfile/lib.php
enrol/manual/lib.php
enrol/renderer.php
grade/edit/tree/calculation.php
grade/edit/tree/grade.php
grade/import/csv/index.php
grade/import/grade_import_form.php
grade/lib.php
grade/report/grader/index.php
grade/report/grader/lib.php
install/lang/en_fix/langconfig.php [deleted file]
install/lang/hr/moodle.php
install/lang/lt/install.php [new file with mode: 0644]
lang/en/admin.php
lang/en/calendar.php
lang/en/message.php
lib/adminlib.php
lib/bennu/iCalendar_components.php
lib/bennu/readme_moodle.txt
lib/blocklib.php
lib/csslib.php
lib/db/install.xml
lib/db/upgrade.php
lib/eaccelerator.class.php [deleted file]
lib/editor/tinymce/plugins/dragmath/dragmath.php
lib/editor/tinymce/plugins/loader.php
lib/editor/tinymce/plugins/moodleemoticon/dialog.php
lib/editor/tinymce/plugins/spellchecker/classes/GoogleSpell.php
lib/editor/tinymce/readme_moodle.txt
lib/enrollib.php
lib/filelib.php
lib/formslib.php
lib/googleapi.php
lib/grade/grade_item.php
lib/grade/tests/grade_item_test.php
lib/gradelib.php
lib/installlib.php
lib/javascript-static.js
lib/jslib.php
lib/memcached.class.php [deleted file]
lib/messagelib.php
lib/minify/lib/JSMin.php [deleted file]
lib/minify/readme_moodle.txt
lib/modinfolib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputlib.php
lib/outputrenderers.php
lib/phpunit/classes/data_generator.php
lib/phpunit/tests/generator_test.php
lib/pluginlib.php
lib/setup.php
lib/setuplib.php
lib/statslib.php
lib/tablelib.php
lib/tests/accesslib_test.php
lib/tests/fixtures/statslib-test00.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test01.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test02.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test03.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test04.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test05.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test06.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test07.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test08.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test09.xml [new file with mode: 0644]
lib/tests/fixtures/statslib-test10.xml [new file with mode: 0644]
lib/tests/gradelib_test.php [new file with mode: 0644]
lib/tests/messagelib_test.php [new file with mode: 0644]
lib/tests/moodlelib_test.php
lib/tests/outputcomponents_test.php
lib/tests/outputlib_test.php
lib/tests/setuplib_test.php
lib/tests/statslib_test.php [new file with mode: 0644]
lib/weblib.php
lib/yui/chooserdialogue/chooserdialogue.js
lib/yui/dragdrop/dragdrop.js
message/lib.php
mod/assign/gradingtable.php
mod/assign/locallib.php
mod/assign/pix/icon.svg
mod/assignment/pix/icon.svg
mod/book/pix/icon.svg
mod/chat/lib.php
mod/chat/pix/icon.svg
mod/chat/upgrade.txt [new file with mode: 0644]
mod/choice/pix/icon.svg
mod/data/field.php
mod/data/lib.php
mod/data/pix/icon.svg
mod/data/preset.php
mod/feedback/pix/icon.svg
mod/folder/pix/icon.svg
mod/forum/pix/icon.svg
mod/glossary/pix/icon.svg
mod/imscp/pix/icon.svg
mod/label/pix/icon.svg
mod/lesson/essay.php
mod/lesson/format.php
mod/lesson/lib.php
mod/lesson/mod_form.php
mod/lesson/pix/icon.svg
mod/lti/pix/icon.svg
mod/lti/tests/generator/lib.php [new file with mode: 0644]
mod/lti/tests/generator_test.php [new file with mode: 0644]
mod/page/pix/icon.svg
mod/quiz/lib.php
mod/quiz/pix/icon.svg
mod/quiz/styles.css
mod/quiz/tests/generator/lib.php [new file with mode: 0644]
mod/resource/pix/icon.svg
mod/scorm/datamodel.php
mod/scorm/loadSCO.php
mod/scorm/mod_form.php
mod/scorm/pix/icon.svg
mod/survey/lang/en/survey.php
mod/survey/pix/icon.svg
mod/url/lib.php
mod/url/locallib.php
mod/url/pix/icon.svg
mod/wiki/pagelib.php
mod/wiki/pix/icon.svg
mod/workshop/lang/en/workshop.php
mod/workshop/pix/icon.svg
mod/workshop/renderer.php
pix/docs.png [new file with mode: 0644]
pix/docs.svg [new file with mode: 0644]
pix/help.png
pix/help.svg
pix/i/assignroles.png [new file with mode: 0644]
pix/i/assignroles.svg [new file with mode: 0644]
pix/i/backup.svg
pix/i/checkpermissions.svg
pix/i/cohort.png [new file with mode: 0644]
pix/i/cohort.svg [new file with mode: 0644]
pix/i/down.png [new file with mode: 0644]
pix/i/down.svg [new file with mode: 0644]
pix/i/dragdrop.png [new file with mode: 0644]
pix/i/dragdrop.svg [new file with mode: 0644]
pix/i/edit.svg
pix/i/enrolusers.png [new file with mode: 0644]
pix/i/enrolusers.svg [new file with mode: 0644]
pix/i/export.png [new file with mode: 0644]
pix/i/export.svg [new file with mode: 0644]
pix/i/filter.png [new file with mode: 0644]
pix/i/filter.svg [new file with mode: 0644]
pix/i/grades.svg
pix/i/group.svg
pix/i/hide.svg
pix/i/import.png [new file with mode: 0644]
pix/i/import.svg [new file with mode: 0644]
pix/i/info.png [new file with mode: 0644]
pix/i/info.svg [new file with mode: 0644]
pix/i/item.png [new file with mode: 0644]
pix/i/item.svg [new file with mode: 0644]
pix/i/marked.svg
pix/i/marker.svg
pix/i/move_2d.svg
pix/i/navigationitem.png
pix/i/navigationitem.svg [new file with mode: 0644]
pix/i/outcomes.png
pix/i/outcomes.svg
pix/i/permissions.png [new file with mode: 0644]
pix/i/permissions.svg [new file with mode: 0644]
pix/i/publish.svg
pix/i/report.svg
pix/i/repository.svg
pix/i/restore.svg
pix/i/return.svg
pix/i/rss.png [new file with mode: 0644]
pix/i/rss.svg [new file with mode: 0644]
pix/i/scales.svg
pix/i/settings.svg
pix/i/show.svg
pix/i/switchrole.png [new file with mode: 0644]
pix/i/switchrole.svg [new file with mode: 0644]
pix/i/test.svg
pix/i/up.png [new file with mode: 0644]
pix/i/up.svg [new file with mode: 0644]
pix/i/user.svg
pix/i/users.png
pix/i/users.svg
pix/i/withsubcat.png
pix/i/withsubcat.svg [new file with mode: 0644]
pix/t/add.svg
pix/t/assignroles.png [moved from pix/i/roles.png with 100% similarity]
pix/t/assignroles.svg [moved from pix/i/roles.svg with 92% similarity]
pix/t/backup.png [new file with mode: 0644]
pix/t/backup.svg [new file with mode: 0644]
pix/t/block_to_dock.png
pix/t/block_to_dock.svg [new file with mode: 0644]
pix/t/block_to_dock_rtl.png [new file with mode: 0644]
pix/t/block_to_dock_rtl.svg [new file with mode: 0644]
pix/t/cohort.png [new file with mode: 0644]
pix/t/cohort.svg [new file with mode: 0644]
pix/t/collapsed.png
pix/t/collapsed.svg [new file with mode: 0644]
pix/t/collapsed_empty.png
pix/t/collapsed_empty.svg [new file with mode: 0644]
pix/t/collapsed_empty_rtl.png
pix/t/collapsed_empty_rtl.svg [new file with mode: 0644]
pix/t/collapsed_rtl.png
pix/t/collapsed_rtl.svg [new file with mode: 0644]
pix/t/copy.svg
pix/t/delete.svg
pix/t/dock_to_block.png
pix/t/dock_to_block.svg [new file with mode: 0644]
pix/t/dock_to_block_rtl.png [new file with mode: 0644]
pix/t/dock_to_block_rtl.svg [new file with mode: 0644]
pix/t/dockclose.png
pix/t/dockclose.svg [new file with mode: 0644]
pix/t/down.png
pix/t/down.svg
pix/t/edit.svg
pix/t/editstring.svg
pix/t/enrolusers.png [new file with mode: 0644]
pix/t/enrolusers.svg [new file with mode: 0644]
pix/t/expanded.png
pix/t/expanded.svg [new file with mode: 0644]
pix/t/groupn.svg
pix/t/groups.svg
pix/t/groupv.svg
pix/t/hide.svg
pix/t/left.svg
pix/t/move.svg
pix/t/restore.png [new file with mode: 0644]
pix/t/restore.svg [new file with mode: 0644]
pix/t/right.svg
pix/t/show.svg
pix/t/sort_asc.png [new file with mode: 0644]
pix/t/sort_asc.svg [new file with mode: 0644]
pix/t/sort_desc.png [new file with mode: 0644]
pix/t/sort_desc.svg [new file with mode: 0644]
pix/t/switch_minus.png [new file with mode: 0644]
pix/t/switch_minus.svg [new file with mode: 0644]
pix/t/switch_plus.png [new file with mode: 0644]
pix/t/switch_plus.svg [new file with mode: 0644]
pix/t/up.png
pix/t/up.svg
question/editlib.php
question/format/xml/format.php
question/type/match/backup/moodle2/restore_qtype_match_plugin.class.php
question/type/multichoice/question.php
question/type/multichoice/tests/question_test.php
repository/filepicker.js
theme/afterburner/config.php
theme/afterburner/layout/default.php
theme/anomaly/config.php
theme/anomaly/layout/general.php
theme/anomaly/layout/report.php
theme/arialist/config.php
theme/arialist/layout/general.php
theme/arialist/layout/report.php
theme/base/cli/svgtool.php [new file with mode: 0644]
theme/base/style/blocks.css
theme/base/style/core.css
theme/base/style/course.css
theme/base/style/dock.css
theme/binarius/config.php
theme/binarius/layout/general.php
theme/binarius/layout/report.php
theme/boxxie/config.php
theme/boxxie/layout/general.php
theme/brick/config.php
theme/brick/layout/general.php
theme/formal_white/layout/frontpage.php
theme/formal_white/layout/general.php
theme/formal_white/layout/report.php
theme/formal_white/style/formal_white.css
theme/formal_white/style/frame.css
theme/standard/style/blocks.css
theme/standard/style/course.css
theme/standard/style/css3.css
theme/standard/style/dock.css
theme/upgrade.txt
user/selector/lib.php
version.php

index 11a5eab..a8377de 100644 (file)
@@ -115,7 +115,7 @@ switch ($action) {
                 $message = get_string('formatuninstallconfirm', 'admin', $format->displayname);
             }
             $deleteurl->param('confirm', 1);
-            echo $OUTPUT->confirm($message, $deleteurl, $return);            
+            echo $OUTPUT->confirm($message, $deleteurl, $return);
         } else {
             $a = new stdClass();
             $a->plugin = $format->displayname;
@@ -128,4 +128,4 @@ switch ($action) {
         echo $OUTPUT->footer();
         exit;
 }
-redirect($return);
\ No newline at end of file
+redirect($return);
index 4d9365c..b7fa57e 100644 (file)
@@ -312,6 +312,10 @@ if ($hassiteconfig) {
 
 // Question type settings
 if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext)) {
+    if (!$hassiteconfig) {
+        require_once("$CFG->libdir/pluginlib.php");
+        $allplugins = plugin_manager::instance()->get_plugins();
+    }
     // Question behaviour settings.
     $ADMIN->add('modules', new admin_category('qbehavioursettings', new lang_string('questionbehaviours', 'admin')));
     $ADMIN->add('qbehavioursettings', new admin_page_manageqbehaviours());
index 4e773cd..3ba7201 100644 (file)
@@ -193,29 +193,6 @@ $temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache'
 
 $temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('curltimeoutkbitrate', 'admin'),
                                         new lang_string('curltimeoutkbitrate_help', 'admin'), 56, PARAM_INT));
-/* //TODO: we need to fix code instead of relying on slow rcache, enable this once we have some code that is actually using it
-$temp->add(new admin_setting_special_selectsetup('cachetype', new lang_string('cachetype', 'admin'),
-                                          new lang_string('configcachetype', 'admin'), '',
-                                          array( '' => new lang_string('none'),
-                                                 'internal' => 'internal',
-                                                 'memcached' => 'memcached',
-                                                 'eaccelerator' => 'eaccelerator')));
-// NOTE: $CFG->rcache is forced to bool in lib/setup.php
-$temp->add(new admin_setting_special_selectsetup('rcache', new lang_string('rcache', 'admin'),
-                                          new lang_string('configrcache', 'admin'), 0,
-                                          array( '0' => new lang_string('no'),
-                                                 '1' => new lang_string('yes'))));
-$temp->add(new admin_setting_configtext('rcachettl', new lang_string('rcachettl', 'admin'),
-                                        new lang_string('configrcachettl', 'admin'), 10));
-$temp->add(new admin_setting_configtext('intcachemax', new lang_string('intcachemax', 'admin'),
-                                        new lang_string('configintcachemax', 'admin'), 10));
-$temp->add(new admin_setting_configtext('memcachedhosts', new lang_string('memcachedhosts', 'admin'),
-                                        new lang_string('configmemcachedhosts', 'admin'), ''));
-$temp->add(new admin_setting_configselect('memcachedpconn', new lang_string('memcachedpconn', 'admin'),
-                                          new lang_string('configmemcachedpconn', 'admin'), 0,
-                                          array( '0' => new lang_string('no'),
-                                                 '1' => new lang_string('yes'))));
-*/
 
 $ADMIN->add('server', $temp);
 
index 5abb3b0..97f1abb 100644 (file)
         } else {
             $columndir = $dir == "ASC" ? "DESC":"ASC";
             if ($column == "lastaccess") {
-                $columnicon = $dir == "ASC" ? "up":"down";
+                $columnicon = ($dir == "ASC") ? "sort_desc" : "sort_asc";
             } else {
-                $columnicon = $dir == "ASC" ? "down":"up";
+                $columnicon = ($dir == "ASC") ? "sort_asc" : "sort_desc";
             }
-            $columnicon = " <img src=\"" . $OUTPUT->pix_url('t/' . $columnicon) . "\" alt=\"\" />";
+            $columnicon = "<img class='iconsort' src=\"" . $OUTPUT->pix_url('t/' . $columnicon) . "\" alt=\"\" />";
 
         }
         $$column = "<a href=\"user.php?sort=$column&amp;dir=$columndir\">".$string[$column]."</a>$columnicon";
index 46d7514..c3b47c6 100644 (file)
@@ -641,7 +641,8 @@ class moodle1_converter extends base_converter {
             return $files;
         }
         foreach ($matches[2] as $match) {
-            $files[] = str_replace(array('$@FILEPHP@$', '$@SLASH@$', '$@FORCEDOWNLOAD@$'), array('', '/', ''), $match);
+            $file = str_replace(array('$@FILEPHP@$', '$@SLASH@$', '$@FORCEDOWNLOAD@$'), array('', '/', ''), $match);
+            $files[] = urldecode($file);
         }
 
         return array_unique($files);
index a97720e..20aca62 100644 (file)
@@ -449,6 +449,19 @@ as it is parsed from the backup file. <br /><br /><img border="0" width="110" vs
     <br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />');
     }
 
+    public function test_referenced_files_urlencoded() {
+        // This test covers MDL-36204
+        $text = 'This is a text containing links to file.php
+as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif" /><a href="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif$@FORCEDOWNLOAD@$">no space</a><br />
+    <br /><a href=\'$@FILEPHP@$$@SLASH@$pics$@SLASH@$news%20with%20spaces.gif$@FORCEDOWNLOAD@$\'>with urlencoded spaces</a><br />';
+
+        $files = moodle1_converter::find_referenced_files($text);
+        $this->assertEquals(gettype($files), 'array');
+        $this->assertEquals(2, count($files));
+        $this->assertTrue(in_array('/pics/news.gif', $files));
+        $this->assertTrue(in_array('/pics/news with spaces.gif', $files));
+    }
+
     public function test_question_bank_conversion() {
         global $CFG;
 
index a82cd02..f2ba2af 100644 (file)
@@ -912,7 +912,7 @@ class backup_gradebook_structure_step extends backup_structure_step {
         $grade_category   = new backup_nested_element('grade_category', array('id'), array(
                 //'courseid',
                 'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh',
-                'dropload', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
+                'droplow', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
                 'timecreated', 'timemodified', 'hidden'));
 
         $letters = new backup_nested_element('grade_letters');
index af81bfa..fe4f504 100644 (file)
@@ -3128,6 +3128,22 @@ class restore_create_categories_and_questions extends restore_structure_step {
                        AND ' . $DB->sql_compare_text('hint', 255) . ' = ' . $DB->sql_compare_text('?', 255);
             $params = array($newquestionid, $data->hint);
             $newitemid = $DB->get_field_sql($sql, $params);
+
+            // Not able to find the hint, let's try cleaning the hint text
+            // of all the question's hints in DB as slower fallback. MDL-33863.
+            if (!$newitemid) {
+                $potentialhints = $DB->get_records('question_hints',
+                        array('questionid' => $newquestionid), '', 'id, hint');
+                foreach ($potentialhints as $potentialhint) {
+                    // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+                    $cleanhint = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $potentialhint->hint); // Clean CTRL chars.
+                    $cleanhint = preg_replace("/\r\n|\r/", "\n", $cleanhint); // Normalize line ending.
+                    if ($cleanhint === $data->hint) {
+                        $newitemid = $data->id;
+                    }
+                }
+            }
+
             // If we haven't found the newitemid, something has gone really wrong, question in DB
             // is missing hints, exception
             if (!$newitemid) {
index 0a391b0..7383658 100644 (file)
@@ -53,10 +53,10 @@ class block_activity_modules extends block_list {
 
         foreach ($modfullnames as $modname => $modfullname) {
             if ($modname === 'resources') {
-                $icon = $OUTPUT->pix_icon(file_extension_icon('.htm'), '', 'moodle', array('class' => 'icon')). '&nbsp;';
+                $icon = $OUTPUT->pix_icon('icon', '', 'mod_page', array('class' => 'icon'));
                 $this->content->items[] = '<a href="'.$CFG->wwwroot.'/course/resources.php?id='.$course->id.'">'.$icon.$modfullname.'</a>';
             } else {
-                $icon = '<img src="'.$OUTPUT->pix_url('icon', $modname) . '" class="icon" alt="" />&nbsp;';
+                $icon = '<img src="'.$OUTPUT->pix_url('icon', $modname) . '" class="icon" alt="" />';
                 $this->content->items[] = '<a href="'.$CFG->wwwroot.'/mod/'.$modname.'/index.php?id='.$course->id.'">'.$icon.$modfullname.'</a>';
             }
         }
index c211342..3702f11 100644 (file)
@@ -72,7 +72,7 @@ class block_community extends block_list {
                     'class' => 'icon', 'alt' => get_string('addcourse', 'block_community')));
         $addcourseurl = new moodle_url('/blocks/community/communitycourse.php',
                         array('add' => true, 'courseid' => $this->page->course->id));
-        $searchlink = html_writer::tag('a', $icon . '&nbsp;' . get_string('addcourse', 'block_community'),
+        $searchlink = html_writer::tag('a', $icon . get_string('addcourse', 'block_community'),
                         array('href' => $addcourseurl->out(false)));
         $this->content->items[] = $searchlink;
 
index 2e6fa7c..540c49a 100644 (file)
@@ -23,7 +23,7 @@ class block_course_list extends block_list {
         $this->content->icons = array();
         $this->content->footer = '';
 
-        $icon  = '<img src="' . $OUTPUT->pix_url('i/course') . '" class="icon" alt="" />&nbsp;';
+        $icon  = '<img src="' . $OUTPUT->pix_url('i/course') . '" class="icon" alt="" />';
 
         $adminseesall = true;
         if (isset($CFG->block_course_list_adminview)) {
@@ -109,7 +109,7 @@ class block_course_list extends block_list {
             return;
         }
 
-        $icon = '<img src="'.$OUTPUT->pix_url('i/mnethost') . '" class="icon" alt="" />&nbsp;';
+        $icon = '<img src="'.$OUTPUT->pix_url('i/mnethost') . '" class="icon" alt="" />';
 
         // shortcut - the rest is only for logged in users!
         if (!isloggedin() || isguestuser()) {
index a83e51f..9e5a93a 100644 (file)
@@ -149,7 +149,7 @@ class block_course_overview_renderer extends plugin_renderer_base {
             $output .= html_writer::start_tag('div', array('class' => 'activity_overview'));
             $url = new moodle_url("/mod/$module/index.php", array('id' => $cid));
             $modulename = get_string('modulename', $module);
-            $icontext = html_writer::link($url, $this->output->pix_icon('icon', $modulename, 'mod_'.$module, array('class'=>'icon')).' ');
+            $icontext = html_writer::link($url, $this->output->pix_icon('icon', $modulename, 'mod_'.$module, array('class'=>'iconlarge')));
             if (get_string_manager()->string_exists("activityoverview", $module)) {
                 $icontext .= get_string("activityoverview", $module);
             } else {
index fe3e0e3..6718d06 100644 (file)
@@ -4,12 +4,15 @@
 }
 
 .block_course_overview .content {
-    margin-left: 20px;
+    margin: 0 20px;
+}
+.block_course_overview .content .notice {
+    margin: 5px 0;
 }
 
 .block_course_overview .coursebox {
-    padding: 15px 0 10px 10px;
-    width: 98%;
+    padding: 15px;
+    width: auto;
 }
 
 .block_course_overview .profilepicture {
@@ -36,8 +39,7 @@
 
 .block_course_overview .content h2.title {
     float: left;
-    margin-bottom: 0;
-    margin-top: 0;
+    margin: 0 0 .5em 0;
     position: relative;
 }
 .dir-rtl .block_course_overview .content h2.title {
 .block_course_overview .activity_overview {
     padding: 2px;
 }
+.block_course_overview .activity_overview img.iconlarge { vertical-align: text-bottom; margin-right: 6px; }
+.dir-rtl .block_course_overview .activity_overview img.iconlarge { margin-left: 6px; margin-right: 0;}
 
 .block_course_overview .singleselect {
     text-align: left;
     border-width: 2px;
     border-style: dashed;
 }
-
-.block_course_overview .collapsibleregioninner .name {margin-right: 20px;}
-.block_course_overview .collapsibleregioninner .info,
-.block_course_overview .collapsibleregioninner .details {margin-right: 25px;}
\ No newline at end of file
index 34a859d..6e56390 100644 (file)
@@ -532,10 +532,16 @@ M.core_dock.fixTitleOrientation = function(item, title, text) {
         'position' : 'relative',
         'fontSize' : fontsize,
         'width' : width,
-        'top' : width/2,
-        'right' : width/2 - height
+        'top' : width/2
     });
 
+    // Positioning is different when in RTL mode.
+    if (right_to_left()) {
+        title.setStyle('left', width/2 - height);
+    } else {
+        title.setStyle('right', width/2 - height);
+    }
+
     // Rotate the text
     title.setStyles({
         'transform' : transform,
@@ -831,7 +837,11 @@ M.core_dock.genericblock.prototype = {
 
         // Must set the image src seperatly of we get an error with XML strict headers
         var moveto = Y.Node.create('<input type="image" class="moveto customcommand requiresjs" alt="'+M.str.block.addtodock+'" title="'+M.str.block.addtodock+'" />');
-        moveto.setAttribute('src', M.util.image_url('t/block_to_dock', 'moodle'));
+        var icon = 't/block_to_dock';
+        if (right_to_left()) {
+            icon = 't/block_to_dock_rtl';
+        }
+        moveto.setAttribute('src', M.util.image_url(icon, 'moodle'));
         moveto.on('movetodock|click', this.move_to_dock, this, commands);
 
         var blockaction = node.one('.block_action');
@@ -897,7 +907,11 @@ M.core_dock.genericblock.prototype = {
 
         // Must set the image src seperatly of we get an error with XML strict headers
         var movetoimg = Y.Node.create('<img alt="'+M.str.block.undockitem+'" title="'+M.str.block.undockitem+'" />');
-        movetoimg.setAttribute('src', M.util.image_url('t/dock_to_block', 'moodle'));
+        var icon = 't/dock_to_block';
+        if (right_to_left()) {
+            icon = 't/dock_to_block_rtl';
+        }
+        movetoimg.setAttribute('src', M.util.image_url(icon, 'moodle'));
         var moveto = Y.Node.create('<a class="moveto customcommand requiresjs"></a>').append(movetoimg);
         if (location.href.match(/\?/)) {
             moveto.set('href', location.href+'&dock='+this.id);
@@ -922,7 +936,7 @@ M.core_dock.genericblock.prototype = {
             }, this);
             // Add a close icon
             // Must set the image src seperatly of we get an error with XML strict headers
-            var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="" style="width:11px;height:11px;cursor:pointer;" /></span>');
+            var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="" /></span>');
             closeicon.one('img').setAttribute('src', M.util.image_url('t/dockclose', 'moodle'));
             closeicon.on('forceclose|click', this.hide, this);
             closeicon.on('dock:actionkey',this.hide, this, {actions:{enter:true,toggle:true}});
index 0128f1b..916780d 100644 (file)
@@ -129,11 +129,6 @@ class block_glossary_random extends block_base {
         $course = $this->page->course;
         $modinfo = get_fast_modinfo($course);
         $glossaryid = $this->config->glossary;
-        $cm = $modinfo->instances['glossary'][$glossaryid];
-
-        if (!has_capability('mod/glossary:view', context_module::instance($cm->id))) {
-            return '';
-        }
 
         if (!isset($modinfo->instances['glossary'][$glossaryid])) {
             // we can get here if the glossary has been deleted, so
@@ -147,6 +142,12 @@ class block_glossary_random extends block_base {
             return $this->content;
         }
 
+        $cm = $modinfo->instances['glossary'][$glossaryid];
+
+        if (!has_capability('mod/glossary:view', context_module::instance($cm->id))) {
+            return '';
+        }
+
         if (empty($this->config->cache)) {
             $this->config->cache = '';
         }
index 6da9053..6d08f5e 100644 (file)
@@ -1,19 +1,23 @@
 /** General display rules **/
 .block_navigation .block_tree {margin:5px;padding-left:0px;overflow:visible;}
 .block_navigation .block_tree li {margin:3px;list-style: none;padding:0;}
-.block_navigation .block_tree li.item_with_icon > p {position:relative;}
-.block_navigation .block_tree li.item_with_icon > p img {vertical-align:middle;position:absolute;left:0;top:3px}
+.block_navigation .block_tree li.item_with_icon > p {position:relative; padding-left: 21px;}
+.block_navigation .block_tree li.item_with_icon > p img,
+.block_navigation .block_tree .type_activity > p.tree_item.active_tree_node img,
+.block_navigation .block_tree li > p.hasicon img {vertical-align:middle;position:absolute;left:0;top:-1px;width:16px;height:16px;}
 .block_navigation .block_tree li.item_with_icon.contains_branch > p img {left:16px;}
-.block_navigation .block_tree li.item_with_icon.contains_branch .tree_item {padding-left:34px;}
+.block_navigation .block_tree .type_activity > p.branch.hasicon,
+.block_navigation .block_tree li.item_with_icon.contains_branch > .tree_item {padding-left:37px;}
 
 .block_navigation .block_tree li ul {padding-left:0;margin:0;}
 .block_navigation .block_tree li.depth_2 ul {padding-left:16px;margin:0;}
-.block_navigation .block_tree .tree_item {padding-left: 18px;margin:3px 0px;text-align:left;}
+.block_navigation .block_tree .type_activity > p.tree_item.branch.hasicon.active_tree_node,
+.block_navigation .block_tree .tree_item {padding-left: 21px;margin:3px 0px;text-align:left;}
 
-.block_navigation .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
+.block_navigation .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 0;background-repeat: no-repeat;}
 .block_navigation .block_tree .tree_item.branch.navigation_node {background-image:none;padding-left:0;}
 .block_navigation .block_tree .type_activity > .tree_item.branch {background-image:none;position:relative;}
-.block_navigation .block_tree .type_activity > .tree_item.branch img {position:absolute;left:0;}
+.block_navigation .block_tree .type_activity > .tree_item.branch img {left: 16px;}
 .block_navigation .block_tree .root_node.leaf {padding-left:0px;}
 .block_navigation .block_tree .active_tree_node {font-weight:bold;}
 .block_navigation .block_tree .depth_1.current_branch ul {font-weight:normal;}
@@ -21,8 +25,9 @@
 .dock .block_navigation .tree_item {white-space: nowrap;}
 
 .jsenabled .block_navigation .block_tree .tree_item.branch {cursor:pointer;}
-.jsenabled .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: 0% 5%;background-repeat: no-repeat;}
+.jsenabled .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: 0 0;background-repeat: no-repeat;}
 .jsenabled .block_navigation .block_tree .collapsed ul {display: none;}
+.jsenabled .block_navigation .block_tree .type_activity > .tree_item.branch {background-image: url([[pix:t/expanded]]);}
 .jsenabled .block_navigation .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}
 .jsenabled .block_navigation .block_tree .tree_item.branch.loadingbranch {background-image:url([[pix:i/loading_small]]);}
 
@@ -35,8 +40,9 @@
 .ie6 .block_navigation .block_tree .tree_item {width:100%;}
 
 /** Overide for RTL layout **/
-.dir-rtl .block_navigation .block_tree li.depth_2 ul {padding-left:0;padding-right: 7px;}
-.dir-rtl .block_navigation .block_tree .tree_item {padding-right: 18px;text-align:right;}
+.dir-rtl .block_navigation .block_tree li.depth_2 ul {padding-left:0;padding-right: 16px; padding-left: 0;}
+.dir-rtl .block_navigation .block_tree .type_activity > p.tree_item.branch.hasicon.active_tree_node,
+.dir-rtl .block_navigation .block_tree .tree_item {padding-right: 21px;text-align:right;}
 
 .dir-rtl .block_navigation .block_tree .tree_item.branch {background-position: center right;}
 
 .dir-rtl .block_navigation .block_tree .root_node.leaf {padding-right:0;}
 
 .dir-rtl .block_navigation .block_tree li.item_with_icon > p img,
-.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {right:0;left:auto;}
+.dir-rtl .block_navigation .block_tree .type_activity > p.tree_item.active_tree_node img,
+.dir-rtl .block_navigation .block_tree li > p.hasicon img {left:auto; right:0;}
+.dir-rtl .block_navigation .block_tree li.item_with_icon.contains_branch > p img {left: auto; right:16px;}
+.dir-rtl .block_navigation .block_tree .type_activity > p.branch.hasicon,
+.dir-rtl .block_navigation .block_tree li.item_with_icon.contains_branch > .tree_item {padding-right:37px; padding-left: 0;}
+.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {right: 16px; left: auto;}
 
 .jsenabled.dir-rtl .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty_rtl]]);background-position: center right;}
 .jsenabled.dir-rtl .block_navigation .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);}
index c46a5aa..82889f8 100644 (file)
@@ -37,7 +37,7 @@ class block_participants extends block_list {
             }
         }
 
-        $icon = '<img src="'.$OUTPUT->pix_url('i/users') . '" class="icon" alt="" />&nbsp;';
+        $icon = '<img src="'.$OUTPUT->pix_url('i/users') . '" class="icon" alt="" />';
         $this->content->items[] = '<a title="'.get_string('listofallpeople').'" href="'.
                                   $CFG->wwwroot.'/user/index.php?contextid='.$currentcontext->id.'">'.$icon.get_string('participants').'</a>';
 
index e931219..f84d2d7 100644 (file)
@@ -66,13 +66,13 @@ class block_private_files_renderer extends plugin_renderer_base {
         $result = '<ul>';
         foreach ($dir['subdirs'] as $subdir) {
             $image = $this->output->pix_icon(file_folder_icon(), $subdir['dirname'], 'moodle', array('class'=>'icon'));
-            $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.$image.' '.s($subdir['dirname']).'</div> '.$this->htmllize_tree($tree, $subdir).'</li>';
+            $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.$image.s($subdir['dirname']).'</div> '.$this->htmllize_tree($tree, $subdir).'</li>';
         }
         foreach ($dir['files'] as $file) {
             $url = file_encode_url("$CFG->wwwroot/pluginfile.php", '/'.$tree->context->id.'/user/private'.$file->get_filepath().$file->get_filename(), true);
             $filename = $file->get_filename();
             $image = $this->output->pix_icon(file_file_icon($file), $filename, 'moodle', array('class'=>'icon'));
-            $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.html_writer::link($url, $image.'&nbsp;'.$filename).'</div></li>';
+            $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.html_writer::link($url, $image.$filename).'</div></li>';
         }
         $result .= '</ul>';
 
index cfa9ab8..2c6e451 100644 (file)
@@ -6,12 +6,12 @@
 /** General display rules **/
 .block_settings .block_tree {margin:5px;padding-left:0px;overflow:visible;}
 .block_settings .block_tree li {margin:0;list-style: none;}
-.block_settings .block_tree li ul {padding-left:16px;margin:0;}
+.block_settings .block_tree li ul {padding-left:18px;margin:0;}
 
 .block_settings .block_tree li.item_with_icon > p {position:relative;}
-.block_settings .block_tree li.item_with_icon > p img {vertical-align:middle;position:absolute;left:0;top:-1px}
+.block_settings .block_tree li.item_with_icon > p img {vertical-align:middle;position:absolute;left:0;top:-1px; width: 16px; height: 16px;}
 
-.block_settings .block_tree .tree_item {padding-left: 18px;margin:3px 0px;text-align:left;}
+.block_settings .block_tree .tree_item {padding-left: 21px;margin:3px 0px;text-align:left;}
 
 .block_settings .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
 .block_settings .block_tree .root_node.leaf {padding-left:0px;}
 
 /** Overide for RTL layout **/
 .dir-rtl .block_settings .block_tree {padding-right:0px;}
-.dir-rtl .block_settings .block_tree li ul {padding-left:0;padding-right: 7px;}
-.dir-rtl .block_settings .block_tree li.item_with_icon > p img,
-.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {left:auto;right:0;}
-.dir-rtl .block_settings .block_tree .tree_item {padding-right: 18px;text-align:right;}
+.dir-rtl .block_settings .block_tree li ul {padding-left:0;padding-right: 18px;}
+.dir-rtl .block_settings .block_tree .tree_item {padding-right: 21px; padding-left: 0; text-align:right;}
 .dir-rtl .block_settings .block_tree .tree_item.branch {background-position: center right;}
 .dir-rtl .block_settings .block_tree .root_node.leaf {padding-right:0px;}
+.dir-rtl .block_settings .block_tree li.item_with_icon > p img { right: 0; left: auto;}
 
 .jsenabled.dir-rtl .block_settings .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty_rtl]]);background-position: center right;}
-.jsenabled.dir-rtl .block_settings .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);}
\ No newline at end of file
+.jsenabled.dir-rtl .block_settings .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);}
index 39a550e..d4374bc 100644 (file)
@@ -50,7 +50,7 @@ class block_site_main_menu extends block_list {
                     } else {
                         $linkcss = $cm->visible ? '' : ' class="dimmed" ';
                         //Accessibility: incidental image - should be empty Alt text
-                        $icon = '<img src="' . $cm->get_icon_url() . '" class="icon" alt="" />&nbsp;';
+                        $icon = '<img src="' . $cm->get_icon_url() . '" class="icon" alt="" />';
                         $this->content->items[] = '<a title="'.$cm->modplural.'" '.$linkcss.' '.$cm->extra.
                                 ' href="' . $url . '">' . $icon . $instancename . '</a>';
                     }
@@ -120,7 +120,7 @@ class block_site_main_menu extends block_list {
                         $this->content->icons[] = '';
                     } else {
                         //Accessibility: incidental image - should be empty Alt text
-                        $icon = '<img src="' . $mod->get_icon_url() . '" class="icon" alt="" />&nbsp;';
+                        $icon = '<img src="' . $mod->get_icon_url() . '" class="icon" alt="" />';
                         $this->content->items[] = '<a title="' . $mod->modfullname . '" ' . $linkcss . ' ' . $mod->extra .
                             ' href="' . $url . '">' . $icon . $instancename . '</a>' . $editbuttons;
                     }
diff --git a/blocks/site_main_menu/styles.css b/blocks/site_main_menu/styles.css
new file mode 100644 (file)
index 0000000..271eca5
--- /dev/null
@@ -0,0 +1,7 @@
+.block_site_main_menu li { clear: both; }
+.block_site_main_menu li .column { width: 100%; }
+.block_site_main_menu li .buttons { float: right; margin-top: 3px;}
+.dir-rtl .block_site_main_menu li .buttons { float: left; }
+.block_site_main_menu li .buttons a img{ vertical-align: text-bottom; margin: 0 3px;}
+.block_site_main_menu .footer { margin-top: 1em; }
+.block_site_main_menu .section_add_menus noscript div { display: inline;}
index 682ef18..da3b966 100644 (file)
@@ -344,6 +344,61 @@ class cache_config {
         return $this->configdefinitions;
     }
 
+    /**
+     * Returns the definitions mapped into the given store name.
+     *
+     * @param string $storename
+     * @return array Associative array of definitions, id=>definition
+     */
+    public static function get_definitions_by_store($storename) {
+        $definitions = array();
+
+        $config = cache_config::instance();
+        $stores = $config->get_all_stores();
+        if (!array_key_exists($storename, $stores)) {
+            // The store does not exist.
+            return false;
+        }
+
+        $defmappings = $config->get_definition_mappings();
+        // Create an associative array for the definition mappings.
+        $thedefmappings = array();
+        foreach ($defmappings as $defmapping) {
+            $thedefmappings[$defmapping['definition']] = $defmapping;
+        }
+
+        // Search for matches in default mappings.
+        $defs = $config->get_definitions();
+        foreach($config->get_mode_mappings() as $modemapping) {
+            if ($modemapping['store'] !== $storename) {
+                continue;
+            }
+            foreach($defs as $id => $definition) {
+                if ($definition['mode'] !== $modemapping['mode']) {
+                    continue;
+                }
+                // Exclude custom definitions mapping: they will be managed few lines below.
+                if (array_key_exists($id, $thedefmappings)) {
+                    continue;
+                }
+                $definitions[$id] = $definition;
+            }
+        }
+
+        // Search for matches in the custom definitions mapping
+        foreach ($defmappings as $defmapping) {
+            if ($defmapping['store'] !== $storename) {
+                continue;
+            }
+            $definition = $config->get_definition_by_id($defmapping['definition']);
+            if ($definition) {
+                $definitions[$defmapping['definition']] = $definition;
+            }
+        }
+
+        return $definitions;
+    }
+
     /**
      * Returns all of the stores that are suitable for the given mode and requirements.
      *
index d02e082..607f074 100644 (file)
@@ -290,10 +290,10 @@ class cache_definition {
             throw new coding_exception('You must provide a mode when creating a cache definition');
         }
         if (!array_key_exists('component', $definition)) {
-            throw new coding_exception('You must provide a mode when creating a cache definition');
+            throw new coding_exception('You must provide a component when creating a cache definition');
         }
         if (!array_key_exists('area', $definition)) {
-            throw new coding_exception('You must provide a mode when creating a cache definition');
+            throw new coding_exception('You must provide an area when creating a cache definition');
         }
         $mode = (int)$definition['mode'];
         $component = (string)$definition['component'];
@@ -457,20 +457,31 @@ class cache_definition {
      * @param int $mode One of cache_store::MODE_*
      * @param string $component The component this definition relates to.
      * @param string $area The area this definition relates to.
-     * @param string $overrideclass The class to use as the loader.
-     * @param bool $persistent If this cache should be persistent.
+     * @param array $options An array of options, available options are:
+     *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
+     *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
+     *   - overrideclass : The class to use as the loader.
+     *   - persistent : If set to true the cache will persist construction requests.
      * @return cache_application|cache_session|cache_request
      */
-    public static function load_adhoc($mode, $component, $area, $overrideclass = null, $persistent = false) {
+    public static function load_adhoc($mode, $component, $area, array $options = array()) {
         $id = 'adhoc/'.$component.'_'.$area;
         $definition = array(
             'mode' => $mode,
             'component' => $component,
             'area' => $area,
-            'persistent' => $persistent
         );
-        if (!is_null($overrideclass)) {
-            $definition['overrideclass'] = $overrideclass;
+        if (!empty($options['simplekeys'])) {
+            $definition['simplekeys'] = $options['simplekeys'];
+        }
+        if (!empty($options['simpledata'])) {
+            $definition['simpledata'] = $options['simpledata'];
+        }
+        if (!empty($options['persistent'])) {
+            $definition['persistent'] = $options['persistent'];
+        }
+        if (!empty($options['overrideclass'])) {
+            $definition['overrideclass'] = $options['overrideclass'];
         }
         return self::load($id, $definition, null);
     }
@@ -638,7 +649,7 @@ class cache_definition {
      */
     public function get_data_source() {
         if (!$this->has_data_source()) {
-            throw new coding_exception('This cache does not use a datasource.');
+            throw new coding_exception('This cache does not use a data source.');
         }
         return forward_static_call(array($this->datasource, 'get_instance_for_cache'), $this);
     }
index 870d960..d44dc8c 100644 (file)
@@ -147,7 +147,7 @@ class cachestore_dummy implements cache_store {
      * Returns true if this store supports multiple identifiers.
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return false;
     }
 
@@ -264,7 +264,7 @@ class cachestore_dummy implements cache_store {
     public static function initialise_test_instance(cache_definition $definition) {
         $cache = new cachestore_dummy('Dummy store test');
         $cache->initialise($definition);
-        return $cache;;
+        return $cache;
     }
 
     /**
@@ -274,4 +274,4 @@ class cachestore_dummy implements cache_store {
     public function my_name() {
         return $this->name;
     }
-}
\ No newline at end of file
+}
index ddf4e8d..9a588df 100644 (file)
@@ -151,16 +151,19 @@ class cache_factory {
      * @param string $component
      * @param string $area
      * @param array $identifiers
-     * @param bool $persistent
+     * @param array $options An array of options, available options are:
+     *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
+     *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
+     *   - persistent : If set to true the cache will persist construction requests.
      * @return cache_application|cache_session|cache_request
      */
-    public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), $persistent = false) {
+    public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
         $key = "{$mode}_{$component}_{$area}";
         if (array_key_exists($key, $this->cachesfromparams)) {
             return $this->cachesfromparams[$key];
         }
         // Get the class. Note this is a late static binding so we need to use get_called_class.
-        $definition = cache_definition::load_adhoc($mode, $component, $area, null, $persistent);
+        $definition = cache_definition::load_adhoc($mode, $component, $area, $options);
         $definition->set_identifiers($identifiers);
         $cache = $this->create_cache($definition, $identifiers);
         if ($definition->should_be_persistent()) {
index 154d9d8..4439a56 100644 (file)
@@ -270,6 +270,8 @@ class cache_helper {
     /**
      * Purges the cache for a specific definition.
      *
+     * @todo MDL-36660: Change the signature: $aggregate must be added.
+     *
      * @param string $component
      * @param string $area
      * @param array $identifiers
@@ -278,6 +280,14 @@ class cache_helper {
     public static function purge_by_definition($component, $area, array $identifiers = array()) {
         // Create the cache.
         $cache = cache::make($component, $area, $identifiers);
+        // Initialise, in case of a store.
+        if ($cache instanceof cache_store) {
+            $factory = cache_factory::instance();
+            // TODO MDL-36660: Providing $aggregate is required for purging purposes: $definition->get_id()
+            $definition = $factory->create_definition($component, $area, null);
+            $definition->set_identifiers($identifiers);
+            $cache->initialise($definition);
+        }
         // Purge baby, purge.
         $cache->purge();
         return true;
@@ -295,8 +305,13 @@ class cache_helper {
         foreach ($instance->get_definitions() as $name => $definitionarr) {
             $definition = cache_definition::load($name, $definitionarr);
             if ($definition->invalidates_on_event($event)) {
-                // Purge the cache.
+                // Create the cache.
                 $cache = $factory->create_cache($definition);
+                // Initialise, in case of a store.
+                if ($cache instanceof cache_store) {
+                    $cache->initialise($definition);
+                }
+                // Purge the cache.
                 $cache->purge();
 
                 // We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
@@ -389,16 +404,9 @@ class cache_helper {
      */
     public static function purge_all() {
         $config = cache_config::instance();
-        $stores = $config->get_all_stores();
-        $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'core', 'cache_purge');
-        foreach ($stores as $store) {
-            $class = $store['class'];
-            $instance = new $class($store['name'], $store['configuration']);
-            if (!$instance->is_ready()) {
-                continue;
-            }
-            $instance->initialise($definition);
-            $instance->purge();
+
+        foreach ($config->get_all_stores() as $store) {
+            self::purge_store($store['name']);
         }
     }
 
@@ -410,21 +418,32 @@ class cache_helper {
      */
     public static function purge_store($storename) {
         $config = cache_config::instance();
-        foreach ($config->get_all_stores() as $store) {
-            if ($store['name'] !== $storename) {
-                continue;
-            }
-            $class = $store['class'];
+
+        $stores = $config->get_all_stores();
+        if (!array_key_exists($storename, $stores)) {
+            // The store does not exist.
+            return false;
+        }
+
+        $store = $stores[$storename];
+        $class = $store['class'];
+
+        // Found the store: is it ready?
+        $instance = new $class($store['name'], $store['configuration']);
+        if (!$instance->is_ready()) {
+            unset($instance);
+            return false;
+        }
+
+        foreach ($config->get_definitions_by_store($storename) as $id => $definition) {
+            $definition = cache_definition::load($id, $definition);
             $instance = new $class($store['name'], $store['configuration']);
-            if (!$instance->is_ready()) {
-                continue;
-            }
-            $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'core', 'cache_purge');
             $instance->initialise($definition);
             $instance->purge();
-            return true;
+            unset($instance);
         }
-        return false;
+
+        return true;
     }
 
     /**
@@ -453,6 +472,9 @@ class cache_helper {
      */
     public static function hash_key($key, cache_definition $definition) {
         if ($definition->uses_simple_keys()) {
+            if (debugging() && preg_match('#[^a-zA-Z0-9_]#', $key)) {
+                throw new coding_exception('Cache definition '.$definition->get_id().' requires simple keys. Invalid key provided.', $key);
+            }
             // We put the key first so that we can be sure the start of the key changes.
             return (string)$key . '-' . $definition->generate_single_key_prefix();
         }
index 1f96fa0..983bc6b 100644 (file)
@@ -194,8 +194,8 @@ interface cache_loader_with_locking {
      *
      * Please note that this happens automatically if the cache definition requires locking.
      * it is still made a public method so that adhoc caches can use it if they choose.
-     * However this doesn't guarantee consistent access. It will become the reponsiblity of the calling code to ensure locks
-     * are acquired, checked, and released.
+     * However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
+     * locks are acquired, checked, and released.
      *
      * @param string|int $key
      * @return bool True if the lock could be acquired, false otherwise.
@@ -207,8 +207,8 @@ interface cache_loader_with_locking {
      *
      * Please note that this happens automatically if the cache definition requires locking.
      * it is still made a public method so that adhoc caches can use it if they choose.
-     * However this doesn't guarantee consistent access. It will become the reponsiblity of the calling code to ensure locks
-     * are acquired, checked, and released.
+     * However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
+     * locks are acquired, checked, and released.
      *
      * @param string|int $key
      * @return bool True if this code has the lock, false if there is a lock but this code doesn't have it,
@@ -221,8 +221,8 @@ interface cache_loader_with_locking {
      *
      * Please note that this happens automatically if the cache definition requires locking.
      * it is still made a public method so that adhoc caches can use it if they choose.
-     * However this doesn't guarantee consistent access. It will become the reponsiblity of the calling code to ensure locks
-     * are acquired, checked, and released.
+     * However this doesn't guarantee consistent access. It will become the responsibility of the calling code to ensure
+     * locks are acquired, checked, and released.
      *
      * @param string|int $key
      * @return bool True if the lock has been released, false if there was a problem releasing the lock.
@@ -314,7 +314,7 @@ interface cache_store {
      *
      * @return bool
      */
-    public function supports_multiple_indentifiers();
+    public function supports_multiple_identifiers();
 
     /**
      * Returns true if this cache store instance promotes data guarantee.
index d0b3a4d..433e9b7 100644 (file)
@@ -18,7 +18,7 @@
  * Cache loaders
  *
  * This file is part of Moodle's cache API, affectionately called MUC.
- * It contains the components that are requried in order to use caching.
+ * It contains the components that are required in order to use caching.
  *
  * @package    core
  * @category   cache
@@ -176,12 +176,15 @@ class cache implements cache_loader {
      * @param string $component The component this cache relates to.
      * @param string $area The area this cache relates to.
      * @param array $identifiers Any additional identifiers that should be provided to the definition.
-     * @param bool $persistent If set to true the cache will persist construction requests.
+     * @param array $options An array of options, available options are:
+     *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
+     *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
+     *   - persistent : If set to true the cache will persist construction requests.
      * @return cache_application|cache_session|cache_store
      */
-    public static function make_from_params($mode, $component, $area, array $identifiers = array(), $persistent = false) {
+    public static function make_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
         $factory = cache_factory::instance();
-        return $factory->create_cache_from_params($mode, $component, $area, $identifiers, $persistent);
+        return $factory->create_cache_from_params($mode, $component, $area, $identifiers, $options);
     }
 
     /**
@@ -272,11 +275,11 @@ class cache implements cache_loader {
         // 1. Parse the key.
         $parsedkey = $this->parse_key($key);
         // 2. Get it from the persist cache if we can (only when persist is enabled and it has already been requested/set).
-        $result = $this->get_from_persist_cache($parsedkey);
+        $result = false;
+        if ($this->is_using_persist_cache()) {
+            $result = $this->get_from_persist_cache($parsedkey);
+        }
         if ($result !== false) {
-            if ($this->perfdebug) {
-                cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
-            }
             if (!is_scalar($result)) {
                 // If data is an object it will be a reference.
                 // If data is an array if may contain references.
@@ -285,8 +288,6 @@ class cache implements cache_loader {
                 $result = $this->unref($result);
             }
             return $result;
-        } else if ($this->perfdebug) {
-            cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
         }
         // 3. Get it from the store. Obviously wasn't in the persist cache.
         $result = $this->store->get($parsedkey);
@@ -795,7 +796,7 @@ class cache implements cache_loader {
      */
     protected function parse_key($key) {
         // First up if the store supports multiple keys we'll go with that.
-        if ($this->store->supports_multiple_indentifiers()) {
+        if ($this->store->supports_multiple_identifiers()) {
             $result = $this->definition->generate_multi_key_parts();
             $result['key'] = $key;
             return $result;
@@ -906,23 +907,34 @@ class cache implements cache_loader {
             $key = $key['key'];
         }
         if (!$this->persist || !array_key_exists($key, $this->persistcache)) {
-            return false;
-        }
-        $data = $this->persistcache[$key];
-        if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
-            if ($data instanceof cache_cached_object) {
-                $data = $data->restore_object();
+            $result = false;
+        } else {
+            $data = $this->persistcache[$key];
+            if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
+                if ($data instanceof cache_cached_object) {
+                    $data = $data->restore_object();
+                }
+                $result = $data;
+            } else if ($data->has_expired()) {
+                $this->delete_from_persist_cache($key);
+                $result = false;
+            } else {
+                if ($data instanceof cache_cached_object) {
+                    $data = $data->restore_object();
+                }
+                $result = $data->data;
             }
-            return $data;
         }
-        if ($data->has_expired()) {
-            $this->delete_from_persist_cache($key);
-            return false;
+        if ($result) {
+            if ($this->perfdebug) {
+                cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
+            }
+            return $result;
         } else {
-            if ($data instanceof cache_cached_object) {
-                $data = $data->restore_object();
+            if ($this->perfdebug) {
+                cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
             }
-            return $data->data;
+            return false;
         }
     }
 
index fc927e0..e8e43a3 100644 (file)
@@ -518,7 +518,7 @@ abstract class cache_administration_helper extends cache_helper {
                         ($store->get_supported_modes($return) & cache_store::MODE_REQUEST) == cache_store::MODE_REQUEST,
                 ),
                 'supports' => array(
-                    'multipleidentifiers' => $store->supports_multiple_indentifiers(),
+                    'multipleidentifiers' => $store->supports_multiple_identifiers(),
                     'dataguarantee' => $store->supports_data_guarantee(),
                     'nativettl' => $store->supports_native_ttl(),
                     'nativelocking' => ($store instanceof cache_is_lockable),
index 0aa3f48..19fdfb6 100644 (file)
@@ -209,7 +209,7 @@ class cachestore_file implements cache_store, cache_is_key_aware {
      *
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return false;
     }
 
@@ -255,8 +255,11 @@ class cachestore_file implements cache_store, cache_is_key_aware {
      * Pre-scan the cache to see which keys are present.
      */
     protected function prescan_keys() {
-        foreach (glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT) as $filename) {
-            $this->keys[basename($filename)] = filemtime($filename);
+        $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
+        if (is_array($files)) {
+            foreach ($files as $filename) {
+                $this->keys[basename($filename)] = filemtime($filename);
+            }
         }
     }
 
@@ -370,9 +373,13 @@ class cachestore_file implements cache_store, cache_is_key_aware {
     public function delete($key) {
         $filename = $key.'.cache';
         $file = $this->file_path_for_key($key);
-        $result = @unlink($file);
-        unset($this->keys[$filename]);
-        return $result;
+
+        if (@unlink($file)) {
+            unset($this->keys[$filename]);
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -510,8 +517,11 @@ class cachestore_file implements cache_store, cache_is_key_aware {
      * @return boolean True on success. False otherwise.
      */
     public function purge() {
-        foreach (glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT) as $filename) {
-            @unlink($filename);
+        $files = glob($this->glob_keys_pattern(), GLOB_MARK | GLOB_NOSORT);
+        if (is_array($files)) {
+            foreach ($files as $filename) {
+                @unlink($filename);
+            }
         }
         $this->keys = array();
         return true;
@@ -676,4 +686,4 @@ class cachestore_file implements cache_store, cache_is_key_aware {
     public function my_name() {
         return $this->name;
     }
-}
\ No newline at end of file
+}
index d684403..d62fac7 100644 (file)
@@ -178,7 +178,7 @@ class cachestore_memcache implements cache_store {
      *
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return false;
     }
 
index 527a5ca..419e640 100644 (file)
@@ -204,7 +204,7 @@ class cachestore_memcached implements cache_store {
      *
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return false;
     }
 
index 4bd4229..1931bdb 100644 (file)
@@ -230,7 +230,7 @@ class cachestore_mongodb implements cache_store {
      * Returns true if this store is making use of multiple identifiers.
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return $this->extendedmode;
     }
 
@@ -239,7 +239,7 @@ class cachestore_mongodb implements cache_store {
      * @return bool
      */
     public function supports_native_ttl() {
-        return false;;
+        return false;
     }
 
     /**
@@ -517,4 +517,4 @@ class cachestore_mongodb implements cache_store {
     public function my_name() {
         return $this->name;
     }
-}
\ No newline at end of file
+}
index bd9d0a0..ba82c17 100644 (file)
@@ -127,7 +127,7 @@ class cachestore_session extends session_data_store implements cache_store, cach
      *
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return false;
     }
 
index 8e0f41c..7a7bd5a 100644 (file)
@@ -127,7 +127,7 @@ class cachestore_static extends static_data_store implements cache_store, cache_
      *
      * @return bool
      */
-    public function supports_multiple_indentifiers() {
+    public function supports_multiple_identifiers() {
         return false;
     }
 
@@ -360,7 +360,7 @@ class cachestore_static extends static_data_store implements cache_store, cache_
         // Do something here perhaps.
         $cache = new cachestore_static('Static store');
         $cache->initialise($definition);
-        return $cache;;
+        return $cache;
     }
 
     /**
@@ -422,4 +422,4 @@ abstract class static_data_store {
             self::$staticstore[$id] = array();
         }
     }
-}
\ No newline at end of file
+}
index dc273ca..2d22751 100644 (file)
@@ -47,9 +47,9 @@ $sessiontable = clone($applicationtable);
 $requesttable = clone($applicationtable);
 
 
-$application = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cache', 'applicationtest', null, false);
-$session = cache_definition::load_adhoc(cache_store::MODE_SESSION, 'cache', 'sessiontest', null, false);
-$request = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'cache', 'requesttest', null, false);
+$application = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cache', 'applicationtest');
+$session = cache_definition::load_adhoc(cache_store::MODE_SESSION, 'cache', 'sessiontest');
+$request = cache_definition::load_adhoc(cache_store::MODE_REQUEST, 'cache', 'requesttest');
 
 $strinvalidplugin = new lang_string('invalidplugin', 'cache');
 $strunsupportedmode = new lang_string('unsupportedmode', 'cache');
index ba467e2..3e6ba79 100644 (file)
@@ -422,4 +422,53 @@ class cache_administration_helper_phpunit_tests extends advanced_testcase {
             $this->assertInstanceOf('coding_exception', $e);
         }
     }
-}
\ No newline at end of file
+
+    /**
+     * Test the hash_key functionality.
+     */
+    public function test_hash_key() {
+        global $CFG;
+
+        $currentdebugging = $CFG->debug;
+
+        $CFG->debug = E_ALL;
+
+        // First with simplekeys
+        $instance = cache_config_phpunittest::instance(true);
+        $instance->phpunit_add_definition('phpunit/hashtest', array(
+            'mode' => cache_store::MODE_APPLICATION,
+            'component' => 'phpunit',
+            'area' => 'hashtest',
+            'simplekeys' => true
+        ));
+        $factory = cache_factory::instance();
+        $definition = $factory->create_definition('phpunit', 'hashtest');
+
+        $result = cache_helper::hash_key('test', $definition);
+        $this->assertEquals('test-'.$definition->generate_single_key_prefix(), $result);
+
+        try {
+            cache_helper::hash_key('test/test', $definition);
+            $this->fail('Invalid key was allowed, you should see this.');
+        } catch (coding_exception $e) {
+            $this->assertEquals('test/test', $e->debuginfo);
+        }
+
+        // Second without simple keys
+        $instance->phpunit_add_definition('phpunit/hashtest2', array(
+            'mode' => cache_store::MODE_APPLICATION,
+            'component' => 'phpunit',
+            'area' => 'hashtest2',
+            'simplekeys' => false
+        ));
+        $definition = $factory->create_definition('phpunit', 'hashtest2');
+
+        $result = cache_helper::hash_key('test', $definition);
+        $this->assertEquals(sha1($definition->generate_single_key_prefix().'-test'), $result);
+
+        $result = cache_helper::hash_key('test/test', $definition);
+        $this->assertEquals(sha1($definition->generate_single_key_prefix().'-test/test'), $result);
+
+        $CFG->debug = $currentdebugging;
+    }
+}
index 698f403..14b4999 100644 (file)
@@ -1465,6 +1465,11 @@ function calendar_edit_event_allowed($event) {
         return false;
     }
 
+    // You cannot edit calendar subscription events presently.
+    if (!empty($event->subscriptionid)) {
+        return false;
+    }
+
     $sitecontext = context_system::instance();
     // if user has manageentries at site level, return true
     if (has_capability('moodle/calendar:manageentries', $sitecontext)) {
@@ -2107,24 +2112,22 @@ class calendar_event {
             if ($usingeditor) {
                 switch ($this->properties->eventtype) {
                     case 'user':
-                        $this->editorcontext = $this->properties->context;
                         $this->properties->courseid = 0;
+                        $this->properties->course = 0;
                         $this->properties->groupid = 0;
                         $this->properties->userid = $USER->id;
                         break;
                     case 'site':
-                        $this->editorcontext = $this->properties->context;
                         $this->properties->courseid = SITEID;
+                        $this->properties->course = SITEID;
                         $this->properties->groupid = 0;
                         $this->properties->userid = $USER->id;
                         break;
                     case 'course':
-                        $this->editorcontext = $this->properties->context;
                         $this->properties->groupid = 0;
                         $this->properties->userid = $USER->id;
                         break;
                     case 'group':
-                        $this->editorcontext = $this->properties->context;
                         $this->properties->userid = $USER->id;
                         break;
                     default:
@@ -2134,6 +2137,13 @@ class calendar_event {
                         break;
                 }
 
+                // If we are actually using the editor, we recalculate the context because some default values
+                // were set when calculate_context() was called from the constructor.
+                if ($usingeditor) {
+                    $this->properties->context = $this->calculate_context($this->properties);
+                    $this->editorcontext = $this->properties->context;
+                }
+
                 $editor = $this->properties->description;
                 $this->properties->format = $this->properties->description['format'];
                 $this->properties->description = $this->properties->description['text'];
@@ -2152,7 +2162,6 @@ class calendar_event {
                                                 $this->editoroptions,
                                                 $editor['text'],
                                                 $this->editoroptions['forcehttps']);
-
                 $DB->set_field('event', 'description', $this->properties->description, array('id'=>$this->properties->id));
             }
 
@@ -2690,7 +2699,7 @@ function calendar_get_eventtype_choices($courseid) {
         $choices[0] = get_string('userevents', 'calendar');
     }
     if ($allowed->site) {
-        $choices[SITEID] = get_string('globalevents', 'calendar');
+        $choices[SITEID] = get_string('siteevents', 'calendar');
     }
     if (!empty($allowed->courses)) {
         $choices[$courseid] = get_string('courseevents', 'calendar');
@@ -2868,8 +2877,10 @@ function calendar_get_icalendar($url) {
     require_once($CFG->libdir.'/filelib.php');
 
     $curl = new curl();
+    $curl->setopt(array('CURLOPT_FOLLOWLOCATION' => 1, 'CURLOPT_MAXREDIRS' => 5));
     $calendar = $curl->get($url);
-    if (!$calendar) {
+    // Http code validation should actually be the job of curl class.
+    if (!$calendar || $curl->info['http_code'] != 200 || !empty($curl->errorno)) {
         throw new moodle_exception('errorinvalidicalurl', 'calendar');
     }
 
index 12c3135..731bbd3 100644 (file)
@@ -58,13 +58,8 @@ class calendar_addsubscription_form extends moodleform {
 
         // URL.
         $mform->addElement('text', 'url', get_string('importfromurl', 'calendar'), array('maxsize' => '255', 'size' => '50'));
-        $mform->setType('url', PARAM_URL);
-
-        // Import file
-        $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar'));
-
-        $mform->disabledIf('url',  'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
-        $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL);
+        // Cannot set as PARAM_URL since we need to allow webcal:// protocol.
+        $mform->setType('url', PARAM_RAW);
 
         // Poll interval
         $choices = calendar_get_pollinterval_choices();
@@ -73,6 +68,14 @@ class calendar_addsubscription_form extends moodleform {
         $mform->addHelpButton('pollinterval', 'pollinterval', 'calendar');
         $mform->setType('pollinterval', PARAM_INT);
 
+        // Import file
+        $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar'));
+
+        // Disable appropriate elements depending on import from value.
+        $mform->disabledIf('pollinterval', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
+        $mform->disabledIf('url',  'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE);
+        $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL);
+
         // Eventtype: 0 = user, 1 = global, anything else = course ID.
         list($choices, $groups) = calendar_get_eventtype_choices($courseid);
         $mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $choices);
@@ -103,13 +106,39 @@ class calendar_addsubscription_form extends moodleform {
      */
     public function validation($data, $files) {
         $errors = parent::validation($data, $files);
+
         if (empty($data['url']) && empty($data['importfile'])) {
             if (!empty($data['importfrom']) && $data['importfrom'] == CALENDAR_IMPORT_FROM_FILE) {
                 $errors['importfile'] = get_string('errorrequiredurlorfile', 'calendar');
             } else {
                 $errors['url'] = get_string('errorrequiredurlorfile', 'calendar');
             }
+        } else if (!empty($data['url'])) {
+            if (clean_param($data['url'], PARAM_URL) !== $data['url']) {
+                $errors['url']  = get_string('invalidurl', 'error');
+            }
         }
         return $errors;
     }
+
+    public function definition_after_data() {
+        $mform =& $this->_form;
+
+        $mform->applyFilter('url', 'calendar_addsubscription_form::strip_webcal');
+        $mform->applyFilter('url', 'trim');
+    }
+
+    /**
+     * Replace webcal:// urls with http:// as
+     * curl does not understand this protocol
+     *
+     * @param string @url url to examine
+     * @return string url with webcal:// replaced
+     */
+    public static function strip_webcal($url) {
+        if (strpos($url, 'webcal://') === 0) {
+            $url = str_replace('webcal://', 'http://', $url);
+        }
+        return $url;
+    }
 }
index 842ecc4..5a18073 100644 (file)
@@ -800,6 +800,7 @@ class core_calendar_renderer extends plugin_renderer_base {
                 if ($k == $subscription->pollinterval) {
                     $attributes['selected'] = 'selected';
                 }
+                $attributes['value'] = $k;
                 $html .= html_writer::tag('option', $v, $attributes);
             }
             $html .= html_writer::end_tag('select');
index 0d6c83a..2da394d 100644 (file)
@@ -68,8 +68,8 @@ echo $OUTPUT->heading(get_string('assignto', 'cohort', format_string($cohort->na
 echo $OUTPUT->notification(get_string('removeuserwarning', 'core_cohort'));
 
 // Get the user_selector we will need.
-$potentialuserselector = new cohort_candidate_selector('addselect', array('cohortid'=>$cohort->id));
-$existinguserselector = new cohort_existing_selector('removeselect', array('cohortid'=>$cohort->id));
+$potentialuserselector = new cohort_candidate_selector('addselect', array('cohortid'=>$cohort->id, 'accesscontext'=>$context));
+$existinguserselector = new cohort_existing_selector('removeselect', array('cohortid'=>$cohort->id, 'accesscontext'=>$context));
 
 // Process incoming user assignments to the cohort
 
index e363e41..43b1132 100644 (file)
@@ -368,7 +368,7 @@ if (!$courses) {
             // role assignment link
             if (has_capability('moodle/course:enrolreview', $coursecontext)) {
                 $url = new moodle_url('/enrol/users.php', array('id' => $acourse->id));
-                echo $OUTPUT->action_icon($url, new pix_icon('i/users', get_string('enrolledusers', 'enrol')));
+                echo $OUTPUT->action_icon($url, new pix_icon('t/enrolusers', get_string('enrolledusers', 'enrol')));
             }
 
             if (can_delete_course($acourse->id)) {
index 2dcaa13..e1d1b11 100644 (file)
@@ -524,6 +524,7 @@ M.course_dndupload = {
         preview.li.appendChild(preview.div);
 
         preview.icon.src = M.util.image_url('t/addfile');
+        preview.icon.className = 'icon';
         preview.div.appendChild(preview.icon);
 
         preview.div.appendChild(document.createTextNode(' '));
index 1856c62..befde23 100644 (file)
@@ -245,7 +245,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                 $strmoveup = get_string('moveup');
 
                 $controls[] = html_writer::link($url,
-                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/up'),
+                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/up'),
                     'class' => 'icon up', 'alt' => $strmoveup)),
                     array('title' => $strmoveup, 'class' => 'moveup'));
             }
@@ -257,7 +257,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                 $strmovedown =  get_string('movedown');
 
                 $controls[] = html_writer::link($url,
-                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/down'),
+                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/down'),
                     'class' => 'icon down', 'alt' => $strmovedown)),
                     array('title' => $strmovedown, 'class' => 'movedown'));
             }
index 7f0426e..3460a0a 100644 (file)
@@ -1,6 +1,7 @@
 .course-content ul.topics {margin:0;}
 .course-content ul.topics li.section {list-style: none;margin:5px 0 0 0;padding:0;}
 .course-content ul.topics li.section .content {margin:0 40px;}
-.course-content ul.topics li.section .left {width:40px;float:left;text-align:center;}
+.course-content ul.topics li.section .left {width:40px;float:left;text-align:center;padding-top: 4px;}
 .course-content ul.topics li.section .right {width:40px;float:right;text-align:center;padding-top: 4px;}
-.jumpmenu {text-align:center;}
\ No newline at end of file
+.course-content ul.topics li.section .left .section-handle img.icon { padding:0; vertical-align: baseline; }
+.jumpmenu {text-align:center;}
index fc87f3c..17cf4cd 100644 (file)
@@ -1,6 +1,7 @@
 .course-content ul.weeks {margin:0;}
 .course-content ul.weeks li.section {list-style: none;margin:5px 0 0 0;padding:0;}
 .course-content ul.weeks li.section .content {margin:0 40px;}
-.course-content ul.weeks li.section .left {width:40px;float:left;text-align:center;}
+.course-content ul.weeks li.section .left {width:40px;float:left;text-align:center;padding-top: 4px;}
 .course-content ul.weeks li.section .right {width:40px;float:right;text-align:center;padding-top: 4px;}
+.course-content ul.weeks li.section .left .section-handle img.icon { padding:0; vertical-align: baseline; }
 .jumpmenu {text-align:center;}
\ No newline at end of file
index 66435ef..a1a5e56 100644 (file)
@@ -254,7 +254,7 @@ $parentlist = array();
 $displaylist[0] = get_string('top');
 make_categories_list($displaylist, $parentlist);
 
-echo '<table class="generalbox editcourse boxaligncenter"><tr class="header">';
+echo '<table class="generaltable editcourse boxaligncenter"><tr class="header">';
 echo '<th class="header" scope="col">'.$strcategories.'</th>';
 echo '<th class="header" scope="col">'.$strcourses.'</th>';
 echo '<th class="header" scope="col">'.$stredit.'</th>';
@@ -340,7 +340,7 @@ function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $
 
             if (has_capability('moodle/cohort:manage', $category->context) or has_capability('moodle/cohort:view', $category->context)) {
                 echo '<a title="'.$str->cohorts.'" href="'.$CFG->wwwroot.'/cohort/index.php?contextid='.$category->context->id.'"><img'.
-                     ' src="'.$OUTPUT->pix_url('i/cohort') . '" class="iconsmall" alt="'.$str->cohorts.'" /></a> ';
+                     ' src="'.$OUTPUT->pix_url('t/cohort') . '" class="iconsmall" alt="'.$str->cohorts.'" /></a> ';
             }
 
             if ($up) {
index 2fc4b68..d00d393 100644 (file)
@@ -1252,6 +1252,7 @@ function get_module_types_names($plural = false) {
 function course_set_marker($courseid, $marker) {
     global $DB;
     $DB->set_field("course", "marker", $marker, array('id' => $courseid));
+    format_base::reset_course_cache($courseid);
 }
 
 /**
@@ -1272,7 +1273,16 @@ function set_section_visible($courseid, $sectionnumber, $visibility) {
         if (!empty($section->sequence)) {
             $modules = explode(",", $section->sequence);
             foreach ($modules as $moduleid) {
-                set_coursemodule_visible($moduleid, $visibility, true);
+                if ($cm = $DB->get_record('course_modules', array('id' => $moduleid), 'visible, visibleold')) {
+                    if ($visibility) {
+                        // As we unhide the section, we use the previously saved visibility stored in visibleold.
+                        set_coursemodule_visible($moduleid, $cm->visibleold);
+                    } else {
+                        // We hide the section, so we hide the module but we store the original state in visibleold.
+                        set_coursemodule_visible($moduleid, 0);
+                        $DB->set_field('course_modules', 'visibleold', $cm->visible, array('id' => $moduleid));
+                    }
+                }
             }
         }
         rebuild_course_cache($courseid, true);
@@ -1417,15 +1427,16 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
             $modcontext = context_module::instance($mod->id);
             $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext);
             $accessiblebutdim = false;
+            $conditionalhidden = false;
             if ($canviewhidden) {
                 $accessiblebutdim = !$mod->visible;
                 if (!empty($CFG->enableavailability)) {
-                    $accessiblebutdim = $accessiblebutdim ||
-                        $mod->availablefrom > time() ||
+                    $conditionalhidden = $mod->availablefrom > time() ||
                         ($mod->availableuntil && $mod->availableuntil < time()) ||
                         count($mod->conditionsgrade) > 0 ||
                         count($mod->conditionscompletion) > 0;
                 }
+                $accessiblebutdim = $conditionalhidden || $accessiblebutdim;
             }
 
             $liclasses = array();
@@ -1481,17 +1492,21 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                 $linkclasses = '';
                 $textclasses = '';
                 if ($accessiblebutdim) {
-                    $linkclasses .= ' dimmed conditionalhidden';
-                    $textclasses .= ' dimmed_text conditionalhidden';
+                    $linkclasses .= ' dimmed';
+                    $textclasses .= ' dimmed_text';
+                    if ($conditionalhidden) {
+                        $linkclasses .= ' conditionalhidden';
+                        $textclasses .= ' conditionalhidden';
+                    }
                     $accesstext = '<span class="accesshide">'.
                         get_string('hiddenfromstudents').': </span>';
                 } else {
                     $accesstext = '';
                 }
                 if ($linkclasses) {
-                    $linkcss = 'class="' . trim($linkclasses) . '" ';
+                    $linkcss = 'class="activityinstance ' . trim($linkclasses) . '" ';
                 } else {
-                    $linkcss = '';
+                    $linkcss = 'class="activityinstance"';
                 }
                 if ($textclasses) {
                     $textcss = 'class="' . trim($textclasses) . '" ';
@@ -1509,7 +1524,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     // Display link itself
                     echo '<a ' . $linkcss . $mod->extra . $onclick .
                             ' href="' . $url . '"><img src="' . $mod->get_icon_url() .
-                            '" class="activityicon" alt="' . $mod->modfullname . '" /> ' .
+                            '" class="iconlarge activityicon" alt="' . $mod->modfullname . '" />' .
                             $accesstext . '<span class="instancename">' .
                             $instancename . $altname . '</span></a>';
 
@@ -1577,7 +1592,6 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                 } else {
                     $mod->groupmode = false;
                 }
-                echo '&nbsp;&nbsp;';
                 echo make_editing_buttons($mod, $absolute, true, $mod->indent, $sectionreturn);
                 echo $mod->get_after_edit_icons();
             }
@@ -2806,16 +2820,26 @@ function set_coursemodule_idnumber($id, $idnumber) {
 }
 
 /**
-* $prevstateoverrides = true will set the visibility of the course module
-* to what is defined in visibleold. This enables us to remember the current
-* visibility when making a whole section hidden, so that when we toggle
-* that section back to visible, we are able to return the visibility of
-* the course module back to what it was originally.
-*/
-function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
+ * Set the visibility of a module and inherent properties.
+ *
+ * From 2.4 the parameter $prevstateoverrides has been removed, the logic it triggered
+ * has been moved to {@link set_section_visible()} which was the only place from which
+ * the parameter was used.
+ *
+ * @param int $id of the module
+ * @param int $visible state of the module
+ * @return bool false when the module was not found, true otherwise
+ */
+function set_coursemodule_visible($id, $visible) {
     global $DB, $CFG;
     require_once($CFG->libdir.'/gradelib.php');
 
+    // Trigger developer's attention when using the previously removed argument.
+    if (func_num_args() > 2) {
+        debugging('Wrong number of arguments passed to set_coursemodule_visible(), $prevstateoverrides
+            has been removed.', DEBUG_DEVELOPER);
+    }
+
     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
         return false;
     }
@@ -2840,17 +2864,14 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
         }
     }
 
-    if ($prevstateoverrides) {
-        if ($visible == '0') {
-            // Remember the current visible state so we can toggle this back.
-            $DB->set_field('course_modules', 'visibleold', $cm->visible, array('id'=>$id));
-        } else {
-            // Get the previous saved visible states.
-            $DB->set_field('course_modules', 'visible', $cm->visibleold, array('id'=>$id));
-        }
-    } else {
-        $DB->set_field("course_modules", "visible", $visible, array("id"=>$id));
-    }
+    // Updating visible and visibleold to keep them in sync. Only changing a section visibility will
+    // affect visibleold to allow for an original visibility restore. See set_section_visible().
+    $cminfo = new stdClass();
+    $cminfo->id = $id;
+    $cminfo->visible = $visible;
+    $cminfo->visibleold = $visible;
+    $DB->update_record('course_modules', $cminfo);
+
     rebuild_course_cache($cm->course, true);
     return true;
 }
@@ -3316,7 +3337,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
     if (has_capability('moodle/role:assign', $modcontext)){
         $actions[] = new action_link(
             new moodle_url('/'.$CFG->admin.'/roles/assign.php', array('contextid' => $modcontext->id)),
-            new pix_icon('i/roles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')),
+            new pix_icon('t/assignroles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')),
             null,
             array('class' => 'editing_assign', 'title' => $str->assign)
         );
index bce30df..bbb761e 100644 (file)
@@ -233,17 +233,19 @@ class core_course_renderer extends plugin_renderer_base {
         // Put all options into one tag 'alloptions' to allow us to handle scrolling
         $formcontent .= html_writer::start_tag('div', array('class' => 'alloptions'));
 
-        // Activities
-        $activities = array_filter($modules,
-                create_function('$mod', 'return ($mod->archetype !== MOD_CLASS_RESOURCE);'));
+         // Activities
+        $activities = array_filter($modules, function($mod) {
+            return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM);
+        });
         if (count($activities)) {
             $formcontent .= $this->course_modchooser_title('activities');
             $formcontent .= $this->course_modchooser_module_types($activities);
         }
 
         // Resources
-        $resources = array_filter($modules,
-                create_function('$mod', 'return ($mod->archetype === MOD_CLASS_RESOURCE);'));
+        $resources = array_filter($modules, function($mod) {
+            return ($mod->archetype === MOD_ARCHETYPE_RESOURCE);
+        });
         if (count($resources)) {
             $formcontent .= $this->course_modchooser_title('resources');
             $formcontent .= $this->course_modchooser_module_types($resources);
index 8c9f85c..393ab0b 100644 (file)
@@ -336,7 +336,7 @@ if ($courses) {
             // checks whether user can do role assignment
             if (has_capability('moodle/course:enrolreview', $coursecontext)) {
                 echo'<a title="'.get_string('enrolledusers', 'enrol').'" href="'.$CFG->wwwroot.'/enrol/users.php?id='.$course->id.'">';
-                echo '<img src="'.$OUTPUT->pix_url('i/users') . '" class="iconsmall" alt="'.get_string('enrolledusers', 'enrol').'" /></a> ' . "\n";
+                echo '<img src="'.$OUTPUT->pix_url('i/enrolusers') . '" class="iconsmall" alt="'.get_string('enrolledusers', 'enrol').'" /></a> ' . "\n";
             }
 
             // checks whether user can delete course
index c964414..a59351b 100644 (file)
@@ -314,4 +314,125 @@ class courselib_testcase extends advanced_testcase {
         $this->assertTrue(empty($modinfo->sections[0]));
         $this->assertFalse(empty($modinfo->sections[3]));
     }
+
+    public function test_module_visibility() {
+        $this->setAdminUser();
+        $this->resetAfterTest(true);
+
+        // Create course and modules.
+        $course = $this->getDataGenerator()->create_course(array('numsections' => 5));
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id));
+        $modules = compact('forum', 'assign');
+
+        // Hiding the modules.
+        foreach ($modules as $mod) {
+            set_coursemodule_visible($mod->cmid, 0);
+            $this->check_module_visibility($mod, 0, 0);
+        }
+
+        // Showing the modules.
+        foreach ($modules as $mod) {
+            set_coursemodule_visible($mod->cmid, 1);
+            $this->check_module_visibility($mod, 1, 1);
+        }
+    }
+
+    public function test_section_visibility() {
+        $this->setAdminUser();
+        $this->resetAfterTest(true);
+
+        // Create course.
+        $course = $this->getDataGenerator()->create_course(array('numsections' => 3), array('createsections' => true));
+
+        // Testing an empty section.
+        $sectionnumber = 1;
+        set_section_visible($course->id, $sectionnumber, 0);
+        $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+        $this->assertEquals($section_info->visible, 0);
+        set_section_visible($course->id, $sectionnumber, 1);
+        $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+        $this->assertEquals($section_info->visible, 1);
+
+        // Testing a section with visible modules.
+        $sectionnumber = 2;
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
+                array('section' => $sectionnumber));
+        $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(),
+                'course' => $course->id), array('section' => $sectionnumber));
+        $modules = compact('forum', 'assign');
+        set_section_visible($course->id, $sectionnumber, 0);
+        $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+        $this->assertEquals($section_info->visible, 0);
+        foreach ($modules as $mod) {
+            $this->check_module_visibility($mod, 0, 1);
+        }
+        set_section_visible($course->id, $sectionnumber, 1);
+        $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+        $this->assertEquals($section_info->visible, 1);
+        foreach ($modules as $mod) {
+            $this->check_module_visibility($mod, 1, 1);
+        }
+
+        // Testing a section with hidden modules, which should stay hidden.
+        $sectionnumber = 3;
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
+                array('section' => $sectionnumber));
+        $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(),
+                'course' => $course->id), array('section' => $sectionnumber));
+        $modules = compact('forum', 'assign');
+        foreach ($modules as $mod) {
+            set_coursemodule_visible($mod->cmid, 0);
+            $this->check_module_visibility($mod, 0, 0);
+        }
+        set_section_visible($course->id, $sectionnumber, 0);
+        $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+        $this->assertEquals($section_info->visible, 0);
+        foreach ($modules as $mod) {
+            $this->check_module_visibility($mod, 0, 0);
+        }
+        set_section_visible($course->id, $sectionnumber, 1);
+        $section_info = get_fast_modinfo($course->id)->get_section_info($sectionnumber);
+        $this->assertEquals($section_info->visible, 1);
+        foreach ($modules as $mod) {
+            $this->check_module_visibility($mod, 0, 0);
+        }
+    }
+
+    /**
+     * Helper function to assert that a module has correctly been made visible, or hidden.
+     *
+     * @param stdClass $mod module information
+     * @param int $visibility the current state of the module
+     * @param int $visibleold the current state of the visibleold property
+     * @return void
+     */
+    public function check_module_visibility($mod, $visibility, $visibleold) {
+        global $DB;
+        $cm = get_fast_modinfo($mod->course)->get_cm($mod->cmid);
+        $this->assertEquals($visibility, $cm->visible);
+        $this->assertEquals($visibleold, $cm->visibleold);
+
+        // Check the module grade items.
+        $grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $cm->modname,
+                'iteminstance' => $cm->instance, 'courseid' => $cm->course));
+        if ($grade_items) {
+            foreach ($grade_items as $grade_item) {
+                if ($visibility) {
+                    $this->assertFalse($grade_item->is_hidden(), "$cm->modname grade_item not visible");
+                } else {
+                    $this->assertTrue($grade_item->is_hidden(), "$cm->modname grade_item not hidden");
+                }
+            }
+        }
+
+        // Check the events visibility.
+        if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $cm->modname))) {
+            foreach ($events as $event) {
+                $calevent = new calendar_event($event);
+                $this->assertEquals($visibility, $calevent->visible, "$cm->modname calendar_event visibility");
+            }
+        }
+    }
+
 }
index 069dbcb..96b8f1b 100644 (file)
@@ -87,8 +87,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
 
                     if ((movedown || moveup) && cssleft) {
                         cssleft.setStyle('cursor', 'move');
-                        cssleft.appendChild(Y.Node.create('<br />'));
-                        cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE));
+                        cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true));
 
                         if (moveup) {
                             moveup.remove();
@@ -267,7 +266,8 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                 });
                 del.dd.plug(Y.Plugin.DDProxy, {
                     // Don't move the node at the end of the drag
-                    moveOnEnd: false
+                    moveOnEnd: false,
+                    cloneNode: true
                 });
                 del.dd.plug(Y.Plugin.DDConstrained, {
                     // Keep it inside the .course-content
index b3eb066..eca0983 100644 (file)
@@ -488,6 +488,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
         edit_resource_title : function(e) {
             // Get the element we're working on
             var element = e.target.ancestor(CSS.ACTIVITYLI);
+            var elementdiv = element.one('div');
             var instancename  = element.one(CSS.INSTANCENAME);
             var currenttitle = instancename.get('firstChild');
             var oldtitle = currenttitle.get('data');
@@ -522,19 +523,19 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 })
                 .addClass('titleeditor');
             var editform = Y.Node.create('<form />')
-                .setStyle('padding', '0')
-                .setStyle('display', 'inline')
+                .addClass('activityinstance')
                 .setAttribute('action', '#');
-
             var editinstructions = Y.Node.create('<span />')
                 .addClass('editinstructions')
                 .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
+            var activityicon = element.one('img.activityicon').cloneNode();
 
             // Clear the existing content and put the editor in
             currenttitle.set('data', '');
+            editform.appendChild(activityicon);
             editform.appendChild(editor);
             anchor.replace(editform);
-            element.appendChild(editinstructions);
+            elementdiv.appendChild(editinstructions);
             e.preventDefault();
 
             // Focus and select the editor text
index 3c839d0..7e01825 100644 (file)
@@ -151,7 +151,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
             if(! @unlink($filename)) {
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
-                $eventdata->component         = 'course';
+                $eventdata->component         = 'enrol_flatfile';
                 $eventdata->name              = 'flatfile_enrolment';
                 $eventdata->userfrom          = get_admin();
                 $eventdata->userto            = get_admin();
@@ -169,7 +169,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
                 // Send mail to admin
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
-                $eventdata->component         = 'course';
+                $eventdata->component         = 'enrol_flatfile';
                 $eventdata->name              = 'flatfile_enrolment';
                 $eventdata->userfrom          = get_admin();
                 $eventdata->userto            = get_admin();
@@ -280,7 +280,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
 
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
-                $eventdata->component         = 'course';
+                $eventdata->component         = 'enrol_flatfile';
                 $eventdata->name              = 'flatfile_enrolment';
                 $eventdata->userfrom          = $teacher;
                 $eventdata->userto            = $user;
@@ -303,7 +303,7 @@ class enrol_flatfile_plugin extends enrol_plugin {
 
                     $eventdata = new stdClass();
                     $eventdata->modulename        = 'moodle';
-                    $eventdata->component         = 'course';
+                    $eventdata->component         = 'enrol_flatfile';
                     $eventdata->name              = 'flatfile_enrolment';
                     $eventdata->userfrom          = $user;
                     $eventdata->userto            = $teacher;
index ee17fa9..94b89dc 100644 (file)
@@ -113,7 +113,7 @@ class enrol_manual_plugin extends enrol_plugin {
 
         if (has_capability('enrol/manual:manage', $context)) {
             $managelink = new moodle_url("/enrol/manual/manage.php", array('enrolid'=>$instance->id));
-            $icons[] = $OUTPUT->action_icon($managelink, new pix_icon('i/users', get_string('enrolusers', 'enrol_manual'), 'core', array('class'=>'iconsmall')));
+            $icons[] = $OUTPUT->action_icon($managelink, new pix_icon('t/enrolusers', get_string('enrolusers', 'enrol_manual'), 'core', array('class'=>'iconsmall')));
         }
         if (has_capability('enrol/manual:config', $context)) {
             $editlink = new moodle_url("/enrol/manual/edit.php", array('courseid'=>$instance->courseid));
index d630884..05e43f5 100644 (file)
@@ -431,7 +431,7 @@ class course_enrolment_table extends html_table implements renderable {
 
         $this->page           = optional_param(self::PAGEVAR, 0, PARAM_INT);
         $this->perpage        = optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT);
-        $this->sort           = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHA);
+        $this->sort           = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHANUM);
         $this->sortdirection  = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA);
 
         $this->attributes = array('class'=>'userenrolment');
@@ -512,7 +512,7 @@ class course_enrolment_table extends html_table implements renderable {
                     } else {
                         $link = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n)), $fields[$name][$n]);
                         if ($this->sort == $n) {
-                            $link .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
+                            $link .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$n, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($n))), $this->get_direction_icon($output, $n));
                         }
                         $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n));
 
@@ -525,7 +525,7 @@ class course_enrolment_table extends html_table implements renderable {
                 } else {
                     $newlabel  = html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name)), $fields[$name]);
                     if ($this->sort == $name) {
-                        $newlabel .= ' '.html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
+                        $newlabel .= html_writer::link(new moodle_url($url, array(self::SORTVAR=>$name, self::SORTDIRECTIONVAR=>$this->get_field_sort_direction($name))), $this->get_direction_icon($output, $name));
                     }
                 }
             }
@@ -633,9 +633,11 @@ class course_enrolment_table extends html_table implements renderable {
             $direction = $this->sortdirection;
         }
         if ($direction === 'ASC') {
-            return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/down')));
+            return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
+                'src' => $output->pix_url('t/sort_asc')));
         } else {
-            return html_writer::empty_tag('img', array('alt'=>'', 'src'=>$output->pix_url('t/up')));
+            return html_writer::empty_tag('img', array('alt' => '', 'class' => 'iconsort',
+                'src' => $output->pix_url('t/sort_desc')));
         }
     }
 
index ff89761..21e2d7d 100644 (file)
@@ -48,7 +48,7 @@ require_capability('moodle/grade:manage', $context);
 
 // default return url
 $gpr = new grade_plugin_return();
-$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report.php?id='.$course->id);
+$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report/index.php?id='.$course->id);
 
 if (!$grade_item = grade_item::fetch(array('id'=>$id, 'courseid'=>$course->id))) {
     print_error('invaliditemid');
index c3c8a0a..8850622 100644 (file)
@@ -57,7 +57,7 @@ if (!has_capability('moodle/grade:manage', $context)) {
 
 // default return url
 $gpr = new grade_plugin_return();
-$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report.php?id='.$course->id);
+$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report/index.php?id='.$course->id);
 
 // security checks!
 if (!empty($id)) {
index 7896f39..36784b3 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-require_once '../../../config.php';
-require_once $CFG->libdir.'/gradelib.php';
-require_once $CFG->dirroot.'/grade/lib.php';
-require_once '../grade_import_form.php';
-require_once '../lib.php';
+require_once("../../../config.php");
+require_once($CFG->libdir.'/gradelib.php');
+require_once($CFG->dirroot.'/grade/lib.php');
+require_once($CFG->dirroot. '/grade/import/grade_import_form.php');
+require_once($CFG->dirroot.'/grade/import/lib.php');
+require_once($CFG->libdir . '/csvlib.class.php');
 
 $id            = required_param('id', PARAM_INT); // course id
 $separator     = optional_param('separator', '', PARAM_ALPHA);
 $verbosescales = optional_param('verbosescales', 1, PARAM_BOOL);
+$iid           = optional_param('iid', null, PARAM_INT);
+$importcode    = optional_param('importcode', '', PARAM_FILE);
 
 $url = new moodle_url('/grade/import/csv/index.php', array('id'=>$id));
 if ($separator !== '') {
@@ -34,8 +37,6 @@ if ($verbosescales !== 1) {
 }
 $PAGE->set_url($url);
 
-define('GRADE_CSV_LINE_LENGTH', 4096);
-
 if (!$course = $DB->get_record('course', array('id'=>$id))) {
     print_error('nocourseid');
 }
@@ -48,33 +49,14 @@ require_capability('gradeimport/csv:view', $context);
 $separatemode = (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
 $currentgroup = groups_get_course_group($course);
 
-// sort out delimiter
-if (isset($CFG->CSV_DELIMITER)) {
-    $csv_delimiter = $CFG->CSV_DELIMITER;
-
-    if (isset($CFG->CSV_ENCODE)) {
-        $csv_encode = '/\&\#' . $CFG->CSV_ENCODE . '/';
-    }
-} else if ($separator == 'tab') {
-    $csv_delimiter = "\t";
-    $csv_encode = "";
-} else {
-    $csv_delimiter = ",";
-    $csv_encode = '/\&\#44/';
-}
-
 print_grade_page_head($course->id, 'import', 'csv', get_string('importcsv', 'grades'));
 
-// set up import form
-$mform = new grade_import_form(null, array('includeseparator'=>!isset($CFG->CSV_DELIMITER), 'verbosescales'=>true));
-
-// set up grade import mapping form
-$header = '';
+// Set up the grade import mapping form.
 $gradeitems = array();
 if ($id) {
     if ($grade_items = grade_item::fetch_all(array('courseid'=>$id))) {
         foreach ($grade_items as $grade_item) {
-            // skip course type and category type
+            // Skip course type and category type.
             if ($grade_item->itemtype == 'course' || $grade_item->itemtype == 'category') {
                 continue;
             }
@@ -90,96 +72,84 @@ if ($id) {
     }
 }
 
-if ($importcode = optional_param('importcode', '', PARAM_FILE)) {
-    $filename = $CFG->tempdir.'/gradeimport/cvs/'.$USER->id.'/'.$importcode;
-    $fp = fopen($filename, "r");
-    $headers = fgets($fp, GRADE_CSV_LINE_LENGTH);
-    $header = explode($csv_delimiter, $headers);
-    fclose($fp);
-}
+// Set up the import form.
+$mform = new grade_import_form(null, array('includeseparator'=>true, 'verbosescales'=>true));
 
-$mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
+// If the csv file hasn't been imported yet then look for a form submission or
+// show the initial submission form.
+if (!$iid) {
+    // If the import form has been submitted.
+    if ($formdata = $mform->get_data()) {
 
-// if import form is submitted
-if ($formdata = $mform->get_data()) {
+        // Large files are likely to take their time and memory. Let PHP know
+        // that we'll take longer, and that the process should be recycled soon
+        // to free up memory.
+        @set_time_limit(0);
+        raise_memory_limit(MEMORY_EXTRA);
 
-    // Large files are likely to take their time and memory. Let PHP know
-    // that we'll take longer, and that the process should be recycled soon
-    // to free up memory.
-    @set_time_limit(0);
-    raise_memory_limit(MEMORY_EXTRA);
+        // Use current (non-conflicting) time stamp.
+        $importcode = get_new_importcode();
 
-    // use current (non-conflicting) time stamp
-    $importcode = get_new_importcode();
-    $filename = make_temp_directory('gradeimport/cvs/'.$USER->id);
-    $filename = $filename.'/'.$importcode;
-
-    $text = $mform->get_file_content('userfile');
-    // trim utf-8 bom
-    /// normalize line endings and do the encoding conversion
-    $text = textlib::convert($text, $formdata->encoding);
-    $text = textlib::trim_utf8_bom($text);
-    // Fix mac/dos newlines
-    $text = preg_replace('!\r\n?!',"\n",$text);
-    $fp = fopen($filename, "w");
-    fwrite($fp,$text);
-    fclose($fp);
-
-    if (!$fp = fopen($filename, "r")) {
-        print_error('cannotopenfile');
-    }
+        $text = $mform->get_file_content('userfile');
+        $iid = csv_import_reader::get_new_iid('grade');
+        $csvimport = new csv_import_reader($iid, 'grade');
 
-    // --- get header (field names) ---
-    $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+        $csvimport->load_csv_content($text, $formdata->encoding, $separator);
 
-    // print some preview
-    $numlines = 0; // 0 preview lines displayed
+        // --- get header (field names) ---
+        $header = $csvimport->get_columns();
 
-    echo $OUTPUT->heading(get_string('importpreview', 'grades'));
-    echo '<table>';
-    echo '<tr>';
-    foreach ($header as $h) {
-        $h = clean_param($h, PARAM_RAW);
-        echo '<th>'.$h.'</th>';
-    }
-    echo '</tr>';
-    while (!feof ($fp) && $numlines <= $formdata->previewrows) {
-        $lines = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
-        echo '<tr>';
-        foreach ($lines as $line) {
-            echo '<td>'.$line.'</td>';
-        }
-        $numlines ++;
-        echo '</tr>';
-    }
-    echo '</table>';
+        // Print a preview of the data.
+        $numlines = 0; // 0 lines previewed so far.
 
-    // display the mapping form with header info processed
-    $mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
-    $mform2->set_data(array('importcode'=>$importcode, 'id'=>$id, 'verbosescales'=>$verbosescales, 'separator'=>$separator));
-    $mform2->display();
+        echo $OUTPUT->heading(get_string('importpreview', 'grades'));
 
-//} else if (($formdata = data_submitted()) && !empty($formdata->map)) {
+        foreach ($header as $i => $h) {
+            $h = trim($h); // Remove whitespace.
+            $h = clean_param($h, PARAM_RAW); // Clean the header.
+            $header[$i] = $h;
+        }
 
-// else if grade import mapping form is submitted
-} else if ($formdata = $mform2->get_data()) {
+        $table = new html_table();
+        $table->head = $header;
+        $csvimport->init();
+        $previewdata = array();
+        while ($numlines <= $formdata->previewrows) {
+            $lines = $csvimport->next();
+            if ($lines) {
+                $previewdata[] = $lines;
+            }
+            $numlines ++;
+        }
+        $table->data = $previewdata;
+        echo html_writer::table($table);
+    } else {
+        // Display the standard upload file form.
+        groups_print_course_menu($course, 'index.php?id='.$id);
+        echo html_writer::start_tag('div', array('class' => 'clearer'));
+        echo html_writer::end_tag('div');
+
+        $mform->display();
+        echo $OUTPUT->footer();
+        die();
+    }
+}
 
-    $importcode = clean_param($formdata->importcode, PARAM_FILE);
-    $filename = $CFG->tempdir.'/gradeimport/cvs/'.$USER->id.'/'.$importcode;
+// Data has already been submitted so we can use the $iid to retrieve it.
+$csvimport = new csv_import_reader($iid, 'grade');
+$header = $csvimport->get_columns();
 
-    if (!file_exists($filename)) {
-        print_error('cannotuploadfile');
-    }
+// we create a form to handle mapping data from the file to the database.
+$mform2 = new grade_import_mapping_form(null, array('gradeitems'=>$gradeitems, 'header'=>$header));
+$mform2->set_data(array('iid' => $iid, 'id' => $id, 'importcode'=>$importcode, 'verbosescales' => $verbosescales));
 
-    if ($fp = fopen($filename, "r")) {
-        // --- get header (field names) ---
-        $header = explode($csv_delimiter, clean_param(fgets($fp,GRADE_CSV_LINE_LENGTH), PARAM_RAW));
+// Here, if we have data, we process the fields and enter the information into the database.
+if ($formdata = $mform2->get_data()) {
 
-        foreach ($header as $i => $h) {
-            $h = trim($h); $header[$i] = $h; // remove whitespace
-        }
-    } else {
-        print_error('cannotopenfile');
+    foreach ($header as $i => $h) {
+        $h = trim($h); // Remove whitespace.
+        $h = clean_param($h, PARAM_RAW); // Clean the header.
+        $header[$i] = $h;
     }
 
     $map = array();
@@ -204,8 +174,6 @@ if ($formdata = $mform->get_data()) {
                 $maperrors[$j] = true;
             } else {
                 // collision
-                fclose($fp);
-                unlink($filename); // needs to be uploaded again, sorry
                 print_error('cannotmapfield', '', '', $j);
             }
         }
@@ -217,186 +185,160 @@ if ($formdata = $mform->get_data()) {
     @set_time_limit(0);
     raise_memory_limit(MEMORY_EXTRA);
 
-    // we only operate if file is readable
-    if ($fp = fopen($filename, "r")) {
-
-        // read the first line makes sure this doesn't get read again
-        $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+    $csvimport->init();
 
-        $newgradeitems = array(); // temporary array to keep track of what new headers are processed
-        $status = true;
+    $newgradeitems = array(); // temporary array to keep track of what new headers are processed
+    $status = true;
 
-        while (!feof ($fp)) {
-            // add something
-            $line = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
+    while ($line = $csvimport->next()) {
+        if(count($line) <= 1){
+            // there is no data on this line, move on
+            continue;
+        }
 
-            if(count($line) <= 1){
-                // there is no data on this line, move on
-                continue;
+        // array to hold all grades to be inserted
+        $newgrades = array();
+        // array to hold all feedback
+        $newfeedbacks = array();
+        // each line is a student record
+        foreach ($line as $key => $value) {
+
+            $value = clean_param($value, PARAM_RAW);
+            $value = trim($value);
+
+            /*
+             * the options are
+             * 1) userid, useridnumber, usermail, username - used to identify user row
+             * 2) new - new grade item
+             * 3) id - id of the old grade item to map onto
+             * 3) feedback_id - feedback for grade item id
+             */
+
+            $t = explode("_", $map[$key]);
+            $t0 = $t[0];
+            if (isset($t[1])) {
+                $t1 = (int)$t[1];
+            } else {
+                $t1 = '';
             }
 
-            // array to hold all grades to be inserted
-            $newgrades = array();
-            // array to hold all feedback
-            $newfeedbacks = array();
-            // each line is a student record
-            foreach ($line as $key => $value) {
-                //decode encoded commas
-                $value = clean_param($value, PARAM_RAW);
-                $value = trim($value);
-                if (!empty($csv_encode)) {
-                    $value = preg_replace($csv_encode, $csv_delimiter, $value);
-                }
+            switch ($t0) {
+                case 'userid': //
+                    if (!$user = $DB->get_record('user', array('id' => $value))) {
+                        // user not found, abort whole import
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with id \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $value;
+                break;
+                case 'useridnumber':
+                    if (!$user = $DB->get_record('user', array('idnumber' => $value))) {
+                         // user not found, abort whole import
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with idnumber \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $user->id;
+                break;
+                case 'useremail':
+                    if (!$user = $DB->get_record('user', array('email' => $value))) {
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with email address \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $user->id;
+                break;
+                case 'username':
+                    if (!$user = $DB->get_record('user', array('username' => $value))) {
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification("user mapping error, could not find user with username \"$value\"");
+                        $status = false;
+                        break 3;
+                    }
+                    $studentid = $user->id;
+                break;
+                case 'new':
+                    // first check if header is already in temp database
 
-                /*
-                 * the options are
-                 * 1) userid, useridnumber, usermail, username - used to identify user row
-                 * 2) new - new grade item
-                 * 3) id - id of the old grade item to map onto
-                 * 3) feedback_id - feedback for grade item id
-                 */
-
-                $t = explode("_", $map[$key]);
-                $t0 = $t[0];
-                if (isset($t[1])) {
-                    $t1 = (int)$t[1];
-                } else {
-                    $t1 = '';
-                }
+                    if (empty($newgradeitems[$key])) {
 
-                switch ($t0) {
-                    case 'userid': //
-                        if (!$user = $DB->get_record('user', array('id' => $value))) {
-                            // user not found, abort whole import
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with id \"$value\"");
+                        $newgradeitem = new stdClass();
+                        $newgradeitem->itemname = $header[$key];
+                        $newgradeitem->importcode = $importcode;
+                        $newgradeitem->importer   = $USER->id;
+
+                        // insert into new grade item buffer
+                        $newgradeitems[$key] = $DB->insert_record('grade_import_newitem', $newgradeitem);
+                    }
+                    $newgrade = new stdClass();
+                    $newgrade->newgradeitem = $newgradeitems[$key];
+
+                    // if the user has a grade for this grade item
+                    if (trim($value) != '-') {
+                        // instead of omitting the grade we could insert one with finalgrade set to 0
+                        // we do not have access to grade item min grade
+                        $newgrade->finalgrade   = $value;
+                        $newgrades[] = $newgrade;
+                    }
+                break;
+                case 'feedback':
+                    if ($t1) {
+                        // case of an id, only maps id of a grade_item
+                        // this was idnumber
+                        if (!$gradeitem = new grade_item(array('id'=>$t1, 'courseid'=>$course->id))) {
+                            // supplied bad mapping, should not be possible since user
+                            // had to pick mapping
                             $status = false;
-                            break 3;
-                        }
-                        $studentid = $value;
-                    break;
-                    case 'useridnumber':
-                        if (!$user = $DB->get_record('user', array('idnumber' => $value))) {
-                             // user not found, abort whole import
                             import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with idnumber \"$value\"");
-                            $status = false;
+                            echo $OUTPUT->notification(get_string('importfailed', 'grades'));
                             break 3;
                         }
-                        $studentid = $user->id;
-                    break;
-                    case 'useremail':
-                        if (!$user = $DB->get_record('user', array('email' => $value))) {
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with email address \"$value\"");
+
+                        // t1 is the id of the grade item
+                        $feedback = new stdClass();
+                        $feedback->itemid   = $t1;
+                        $feedback->feedback = $value;
+                        $newfeedbacks[] = $feedback;
+                    }
+                break;
+                default:
+                    // existing grade items
+                    if (!empty($map[$key])) {
+                        // case of an id, only maps id of a grade_item
+                        // this was idnumber
+                        if (!$gradeitem = new grade_item(array('id'=>$map[$key], 'courseid'=>$course->id))) {
+                            // supplied bad mapping, should not be possible since user
+                            // had to pick mapping
                             $status = false;
+                            import_cleanup($importcode);
+                            echo $OUTPUT->notification(get_string('importfailed', 'grades'));
                             break 3;
                         }
-                        $studentid = $user->id;
-                    break;
-                    case 'username':
-                        if (!$user = $DB->get_record('user', array('username' => $value))) {
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification("user mapping error, could not find user with username \"$value\"");
+
+                        // check if grade item is locked if so, abort
+                        if ($gradeitem->is_locked()) {
                             $status = false;
+                            import_cleanup($importcode);
+                            echo $OUTPUT->notification(get_string('gradeitemlocked', 'grades'));
                             break 3;
                         }
-                        $studentid = $user->id;
-                    break;
-                    case 'new':
-                        // first check if header is already in temp database
-
-                        if (empty($newgradeitems[$key])) {
 
-                            $newgradeitem = new stdClass();
-                            $newgradeitem->itemname = $header[$key];
-                            $newgradeitem->importcode = $importcode;
-                            $newgradeitem->importer   = $USER->id;
-
-                            // insert into new grade item buffer
-                            $newgradeitems[$key] = $DB->insert_record('grade_import_newitem', $newgradeitem);
-                        }
                         $newgrade = new stdClass();
-                        $newgrade->newgradeitem = $newgradeitems[$key];
-
-                        // if the user has a grade for this grade item
-                        if (trim($value) != '-') {
-                            // instead of omitting the grade we could insert one with finalgrade set to 0
-                            // we do not have access to grade item min grade
-                            $newgrade->finalgrade   = $value;
-                            $newgrades[] = $newgrade;
-                        }
-                    break;
-                    case 'feedback':
-                        if ($t1) {
-                            // case of an id, only maps id of a grade_item
-                            // this was idnumber
-                            if (!$gradeitem = new grade_item(array('id'=>$t1, 'courseid'=>$course->id))) {
-                                // supplied bad mapping, should not be possible since user
-                                // had to pick mapping
-                                $status = false;
-                                import_cleanup($importcode);
-                                echo $OUTPUT->notification(get_string('importfailed', 'grades'));
-                                break 3;
-                            }
-
-                            // t1 is the id of the grade item
-                            $feedback = new stdClass();
-                            $feedback->itemid   = $t1;
-                            $feedback->feedback = $value;
-                            $newfeedbacks[] = $feedback;
-                        }
-                    break;
-                    default:
-                        // existing grade items
-                        if (!empty($map[$key])) {
-                            // case of an id, only maps id of a grade_item
-                            // this was idnumber
-                            if (!$gradeitem = new grade_item(array('id'=>$map[$key], 'courseid'=>$course->id))) {
-                                // supplied bad mapping, should not be possible since user
-                                // had to pick mapping
-                                $status = false;
-                                import_cleanup($importcode);
-                                echo $OUTPUT->notification(get_string('importfailed', 'grades'));
-                                break 3;
-                            }
-
-                            // check if grade item is locked if so, abort
-                            if ($gradeitem->is_locked()) {
-                                $status = false;
-                                import_cleanup($importcode);
-                                echo $OUTPUT->notification(get_string('gradeitemlocked', 'grades'));
-                                break 3;
-                            }
-
-                            $newgrade = new stdClass();
-                            $newgrade->itemid     = $gradeitem->id;
-                            if ($gradeitem->gradetype == GRADE_TYPE_SCALE and $verbosescales) {
-                                if ($value === '' or $value == '-') {
-                                    $value = null; // no grade
-                                } else {
-                                    $scale = $gradeitem->load_scale();
-                                    $scales = explode(',', $scale->scale);
-                                    $scales = array_map('trim', $scales); //hack - trim whitespace around scale options
-                                    array_unshift($scales, '-'); // scales start at key 1
-                                    $key = array_search($value, $scales);
-                                    if ($key === false) {
-                                        echo "<br/>t0 is $t0";
-                                        echo "<br/>grade is $value";
-                                        $status = false;
-                                        import_cleanup($importcode);
-                                        echo $OUTPUT->notification(get_string('badgrade', 'grades'));
-                                        break 3;
-                                    }
-                                    $value = $key;
-                                }
-                                $newgrade->finalgrade = $value;
+                        $newgrade->itemid     = $gradeitem->id;
+                        if ($gradeitem->gradetype == GRADE_TYPE_SCALE and $verbosescales) {
+                            if ($value === '' or $value == '-') {
+                                $value = null; // no grade
                             } else {
-                                if ($value === '' or $value == '-') {
-                                    $value = null; // no grade
-
-                                } else if (!is_numeric($value)) {
-                                // non numeric grade value supplied, possibly mapped wrong column
+                                $scale = $gradeitem->load_scale();
+                                $scales = explode(',', $scale->scale);
+                                $scales = array_map('trim', $scales); //hack - trim whitespace around scale options
+                                array_unshift($scales, '-'); // scales start at key 1
+                                $key = array_search($value, $scales);
+                                if ($key === false) {
                                     echo "<br/>t0 is $t0";
                                     echo "<br/>grade is $value";
                                     $status = false;
@@ -404,94 +346,98 @@ if ($formdata = $mform->get_data()) {
                                     echo $OUTPUT->notification(get_string('badgrade', 'grades'));
                                     break 3;
                                 }
-                                $newgrade->finalgrade = $value;
+                                $value = $key;
                             }
-                            $newgrades[] = $newgrade;
-                        } // otherwise, we ignore this column altogether
-                          // because user has chosen to ignore them (e.g. institution, address etc)
-                    break;
-                }
-            }
-
-            // no user mapping supplied at all, or user mapping failed
-            if (empty($studentid) || !is_numeric($studentid)) {
-                // user not found, abort whole import
-                $status = false;
-                import_cleanup($importcode);
-                echo $OUTPUT->notification('user mapping error, could not find user!');
+                            $newgrade->finalgrade = $value;
+                        } else {
+                            if ($value === '' or $value == '-') {
+                                $value = null; // no grade
+
+                            } else if (!is_numeric($value)) {
+                            // non numeric grade value supplied, possibly mapped wrong column
+                                echo "<br/>t0 is $t0";
+                                echo "<br/>grade is $value";
+                                $status = false;
+                                import_cleanup($importcode);
+                                echo $OUTPUT->notification(get_string('badgrade', 'grades'));
+                                break 3;
+                            }
+                            $newgrade->finalgrade = $value;
+                        }
+                        $newgrades[] = $newgrade;
+                    } // otherwise, we ignore this column altogether
+                      // because user has chosen to ignore them (e.g. institution, address etc)
                 break;
             }
+        }
 
-            if ($separatemode and !groups_is_member($currentgroup, $studentid)) {
-                // not allowed to import into this group, abort
-                $status = false;
-                import_cleanup($importcode);
-                echo $OUTPUT->notification('user not member of current group, can not update!');
-                break;
-            }
+        // no user mapping supplied at all, or user mapping failed
+        if (empty($studentid) || !is_numeric($studentid)) {
+            // user not found, abort whole import
+            $status = false;
+            import_cleanup($importcode);
+            echo $OUTPUT->notification('user mapping error, could not find user!');
+            break;
+        }
 
-            // insert results of this students into buffer
-            if ($status and !empty($newgrades)) {
+        if ($separatemode and !groups_is_member($currentgroup, $studentid)) {
+            // not allowed to import into this group, abort
+            $status = false;
+            import_cleanup($importcode);
+            echo $OUTPUT->notification('user not member of current group, can not update!');
+            break;
+        }
 
-                foreach ($newgrades as $newgrade) {
+        // insert results of this students into buffer
+        if ($status and !empty($newgrades)) {
 
-                    // check if grade_grade is locked and if so, abort
-                    if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid'=>$newgrade->itemid, 'userid'=>$studentid))) {
-                        if ($grade_grade->is_locked()) {
-                            // individual grade locked
-                            $status = false;
-                            import_cleanup($importcode);
-                            echo $OUTPUT->notification(get_string('gradelocked', 'grades'));
-                            break 2;
-                        }
-                    }
+            foreach ($newgrades as $newgrade) {
 
-                    $newgrade->importcode = $importcode;
-                    $newgrade->userid     = $studentid;
-                    $newgrade->importer   = $USER->id;
-                    $DB->insert_record('grade_import_values', $newgrade);
-                }
-            }
-
-            // updating/inserting all comments here
-            if ($status and !empty($newfeedbacks)) {
-                foreach ($newfeedbacks as $newfeedback) {
-                    $sql = "SELECT *
-                              FROM {grade_import_values}
-                             WHERE importcode=? AND userid=? AND itemid=? AND importer=?";
-                    if ($feedback = $DB->get_record_sql($sql, array($importcode, $studentid, $newfeedback->itemid, $USER->id))) {
-                        $newfeedback->id = $feedback->id;
-                        $DB->update_record('grade_import_values', $newfeedback);
-
-                    } else {
-                        // the grade item for this is not updated
-                        $newfeedback->importcode = $importcode;
-                        $newfeedback->userid     = $studentid;
-                        $newfeedback->importer   = $USER->id;
-                        $DB->insert_record('grade_import_values', $newfeedback);
+                // check if grade_grade is locked and if so, abort
+                if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid'=>$newgrade->itemid, 'userid'=>$studentid))) {
+                    if ($grade_grade->is_locked()) {
+                        // individual grade locked
+                        $status = false;
+                        import_cleanup($importcode);
+                        echo $OUTPUT->notification(get_string('gradelocked', 'grades'));
+                        break 2;
                     }
                 }
+
+                $newgrade->importcode = $importcode;
+                $newgrade->userid     = $studentid;
+                $newgrade->importer   = $USER->id;
+                $DB->insert_record('grade_import_values', $newgrade);
             }
         }
 
-        /// at this stage if things are all ok, we commit the changes from temp table
-        if ($status) {
-            grade_import_commit($course->id, $importcode);
+        // updating/inserting all comments here
+        if ($status and !empty($newfeedbacks)) {
+            foreach ($newfeedbacks as $newfeedback) {
+                $sql = "SELECT *
+                          FROM {grade_import_values}
+                         WHERE importcode=? AND userid=? AND itemid=? AND importer=?";
+                if ($feedback = $DB->get_record_sql($sql, array($importcode, $studentid, $newfeedback->itemid, $USER->id))) {
+                    $newfeedback->id = $feedback->id;
+                    $DB->update_record('grade_import_values', $newfeedback);
+
+                } else {
+                    // the grade item for this is not updated
+                    $newfeedback->importcode = $importcode;
+                    $newfeedback->userid     = $studentid;
+                    $newfeedback->importer   = $USER->id;
+                    $DB->insert_record('grade_import_values', $newfeedback);
+                }
+            }
         }
-        // temporary file can go now
-        fclose($fp);
-        unlink($filename);
-    } else {
-        print_error('cannotreadfile');
     }
 
+    /// at this stage if things are all ok, we commit the changes from temp table
+    if ($status) {
+        grade_import_commit($course->id, $importcode);
+    }
 } else {
-    groups_print_course_menu($course, 'index.php?id='.$id);
-    echo '<div class="clearer"></div>';
-
-    // display the standard upload file form
-    $mform->display();
-}
-
-echo $OUTPUT->footer();
-
+    // If data hasn't been submitted then display the data mapping form.
+    $mform2->display();
+    echo $OUTPUT->footer();
+}
\ No newline at end of file
index 76514b3..9723be2 100644 (file)
@@ -118,11 +118,11 @@ class grade_import_mapping_form extends moodleform {
         $mform->setType('map', PARAM_INT);
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
+        $mform->addElement('hidden', 'iid');
+        $mform->setType('iid', PARAM_INT);
         $mform->addElement('hidden', 'importcode');
         $mform->setType('importcode', PARAM_FILE);
         $mform->addElement('hidden', 'verbosescales', 1);
-        $mform->setType('separator', PARAM_ALPHA);
-        $mform->addElement('hidden', 'separator', 'comma');
         $mform->setType('verbosescales', PARAM_INT);
         $mform->addElement('hidden', 'groupid', groups_get_course_group($COURSE));
         $mform->setType('groupid', PARAM_INT);
index 67e9f70..645d73a 100644 (file)
@@ -2300,14 +2300,14 @@ function grade_extend_settings($plugininfo, $courseid) {
     if ($imports = grade_helper::get_plugins_import($courseid)) {
         $importnode = $gradenode->add($strings['import'], null, navigation_node::TYPE_CONTAINER);
         foreach ($imports as $import) {
-            $importnode->add($import->string, $import->link, navigation_node::TYPE_SETTING, null, $import->id, new pix_icon('i/restore', ''));
+            $importnode->add($import->string, $import->link, navigation_node::TYPE_SETTING, null, $import->id, new pix_icon('i/import', ''));
         }
     }
 
     if ($exports = grade_helper::get_plugins_export($courseid)) {
         $exportnode = $gradenode->add($strings['export'], null, navigation_node::TYPE_CONTAINER);
         foreach ($exports as $export) {
-            $exportnode->add($export->string, $export->link, navigation_node::TYPE_SETTING, null, $export->id, new pix_icon('i/backup', ''));
+            $exportnode->add($export->string, $export->link, navigation_node::TYPE_SETTING, null, $export->id, new pix_icon('i/export', ''));
         }
     }
 
index a26537b..36e493e 100644 (file)
@@ -107,7 +107,7 @@ grade_regrade_final_grades($courseid);
 
 // Perform actions
 if (!empty($target) && !empty($action) && confirm_sesskey()) {
-    grade_report_grader::process_action($target, $action);
+    grade_report_grader::do_process_action($target, $action);
 }
 
 $reportname = get_string('pluginname', 'gradereport_grader');
index fccb042..2f9d0d4 100644 (file)
@@ -1584,13 +1584,17 @@ class grade_report_grader extends grade_report {
         return $icon;
     }
 
+    public function process_action($target, $action) {
+        return self::do_process_action($target, $action);
+    }
+
     /**
      * Processes a single action against a category, grade_item or grade.
      * @param string $target eid ({type}{id}, e.g. c4 for category4)
      * @param string $action Which action to take (edit, delete etc...)
      * @return
      */
-    public function process_action($target, $action) {
+    public static function do_process_action($target, $action) {
         // TODO: this code should be in some grade_tree static method
         $targettype = substr($target, 0, 1);
         $targetid = substr($target, 1);
diff --git a/install/lang/en_fix/langconfig.php b/install/lang/en_fix/langconfig.php
deleted file mode 100644 (file)
index d563203..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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/>.
-
-/**
- * Automatically generated strings for Moodle installer
- *
- * Do not edit this file manually! It contains just a subset of strings
- * needed during the very first steps of installation. This file was
- * generated automatically by export-installer.php (which is part of AMOS
- * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
- * list of strings defined in /install/stringnames.txt.
- *
- * @package   installer
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$string['thislanguage'] = 'English (fixes)';
index 62aec64..17b22ef 100644 (file)
@@ -31,6 +31,6 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['language'] = 'Jezik';
-$string['next'] = 'Nastavi';
+$string['next'] = 'Nastavite';
 $string['previous'] = 'Prethodni';
 $string['reload'] = 'Učitaj ponovno';
diff --git a/install/lang/lt/install.php b/install/lang/lt/install.php
new file mode 100644 (file)
index 0000000..cf54d95
--- /dev/null
@@ -0,0 +1,99 @@
+<?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/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['admindirname'] = 'Administratoriaus aplankas';
+$string['availablelangs'] = 'Galimų kalbų sąrašas';
+$string['chooselanguagehead'] = 'Pasirinkite kalbą';
+$string['chooselanguagesub'] = 'Prašome pasirinkti diegimo kalbą. Ši kalba taip pat taps numatytąją svetainės kalba. Tačiau vėliau, jei norėsite, Jūs galėsite ją pakeisti.';
+$string['clialreadyconfigured'] = 'config.php failas jau egzistuoja. Prašome naudotis admin/cli/install_database.php, jei Jūs norite įdiegti šią svetainę.';
+$string['clialreadyinstalled'] = 'config.php failas jau egzistuoja. Prašome naudoti admin/cli/upgrade.php jei Jūs norite išplėtoti šią svetainę.';
+$string['cliinstallheader'] = '"Moodle" {$a} komandinės eilutės įdiegimo programa';
+$string['databasehost'] = 'Duomenų bazės serveris';
+$string['databasename'] = 'Duomenų bazės pavadinimas';
+$string['databasetypehead'] = 'Pasirinkite duomenų bazės tvarkyklę';
+$string['dataroot'] = 'Duomenų aplankas';
+$string['datarootpermission'] = 'Duomenų aplanko leidimai';
+$string['dbprefix'] = 'Lentelių priešdėlis';
+$string['dirroot'] = '"Moodle" aplankas';
+$string['environmenthead'] = 'Tikrinama Jūsų aplinka...';
+$string['environmentsub2'] = 'Kiekviena "Moodle" laida turi kai kuriuos minimalius reikalavimus PHP versijai ir tam tikrą privalomų PHP plėtinių skaičių.
+Pilnas aplinkos patikrinimas yra padaromas prieš kiekvieną įdiegimą ar plėtotę. Prašome susisiekti su serverio administratoriumi, jeigu Jūs nežinote kaip įdiegti naują versiją ar įgalinti PHP plėtinius.';
+$string['errorsinenvironment'] = 'Aplinkos patikrinimas nesėkmingas!';
+$string['installation'] = 'Įdiegimas';
+$string['langdownloaderror'] = 'Deja "{$a}" kalba negali būti parsiųsta. Diegimo procesas bus tęsiamas anglų kalba.';
+$string['memorylimithelp'] = '<p>Šiuo metu Jūsų serverio PHP atminties limitas yra {$a}.</p>
+
+<p>Vėliau tai gali sukelti atminties trūkumo problemų "Moodle", ypač jei Jūs turite daug įgalintų modulių ir/ar daug vartotojų.</p>
+
+<p>Mes rekomenduojame suderinti PHP taip, kad jis turėtų kiek galima didesnį limitą, pvz.: 40MB.
+ Tam yra keletas būdų, kuriuos Jūs galite pabandyti:</p>
+<ol>
+<li>Jei Jūs galite, sukompiliuokite iš naujo PHP panaudodami <i>--enable-memory-limit</i> raktą.
+   Tai leis nustatyti atminties limitą pačiai "Moodle".</li>
+<li>Jei Jūs turite galimybę koreguoti Jūsų "php.ini" failą, tada pakeiskite <b>memory_limit</b> nuostatą į kažką artimo 40MB. Jei Jūs negalite koreguoti, tuomet gal galite paprašyti, kad Jūsų serverio administratorius tai padarytų už Jus.</li>
+<li>Kai kuriuose PHP serveriuose Jūs galite sukurti ".htaccess" failą "Moodle" aplanke ir įrašykite į jį šią eilutę:
+<blockquote><div>php_value memory_limit 40M</div></blockquote>
+<p>Tačiau kai kuriuose serveriuose tai neleis veikti <b>visiems</b> PHP puslapiams (Jūs matysite klaidas bandydami peržiūrėti tinklapius). Taigi Jums gali tekti pašalinti ".htaccess" failą.</p></li>
+</ol>';
+$string['paths'] = 'Keliai';
+$string['pathserrcreatedataroot'] = 'Diegiklis negali sukurti duomenų katalogo ({$a->dataroot}).';
+$string['pathshead'] = 'Patvirtinkite kelius';
+$string['pathsrodataroot'] = 'Dataroot katalogas yra neįrašomas';
+$string['pathsroparentdataroot'] = 'Virškatalogis ({$a->parent}) yra neįrašomas. Diegiklis negali sukurti duomenų katalogo ({$a->dataroot}).';
+$string['pathssubadmindir'] = 'Nedaugelis interneto paslaugų tiekėjų naudoja /admin kaip specialų URL skirtą prisijungti prie valdymo skydo ar panašiai. Deja tai kelia konfliktus su įprastais Moodle administravimo puslapių talpinimo keliais. Jūs galite tai pataisyti
+pervardydami admin katalogą Jūsų diegime bei įrašydami naują pavadinimą čia. Pavyzdžiui: <em>moodleadmin</em>. Tai pakeis visas admin nuorodas Moodle diegime.';
+$string['pathssubdataroot'] = 'Jums reikia vietos kur Moodle gali išsaugoti įkeliamus failus. Šis katalogas turi būti skaitomas IR ĮRAŠOMAS web serverio naudotojo
+(dažniausiai tai \'nobody\' arba \'apache\'), tačiau jis neturi būti pasiekiamas tiesiogiai per internetą. Diegiklis pabandys sukurti katalogą, jei tokio nėra.';
+$string['pathssubdirroot'] = 'Pilnas kelias iki Moodle diegimo vietos.';
+$string['pathssubwwwroot'] = 'Pilnas internetinis adresas, kuriuo bus pasiekiamas Moodle.
+Pasiekti Moodle naudojantis keliais adresais yra neįmanoma.
+Jei Jūsų svetainėje yra keletas viešų adresų, Jūs turite visuose adresuose nustatyti pastovų peradresavimą į šį adresą.
+Jei Jūsų svetainė yra pasiekiama ir iš Intraneto, ir iš Interneto - panaudokite viešą adresą čia ir nustatykite DNS taip, kad Intraneto naudotojai taip pat galėtų matyti viešą adresą.
+Jei adresas neteisingas - prašome pakeisti URL Jūsų naršyklėje ir pradėti diegimą su nauju adresu.';
+$string['pathsunsecuredataroot'] = 'Dataroot katalogo vieta yra nesaugi.';
+$string['pathswrongadmindir'] = 'Admin katalogas neegzistuoja';
+$string['phpextension'] = '{$a} PHP plėtinys';
+$string['phpversion'] = 'PHP versija';
+$string['phpversionhelp'] = '<p>Moodle reikalauja, kad būtų įdiegta bent 4.3.0 arba 5.1.0 PHP versija (5.0.x versija turi keletą žymių problemų).
+</p>
+<p>Jūs šiuo metu naudojate {$a} versiją</p>
+<p>Jūs turite išplėtoti turimą PHP versiją iki naujesnės arba persikelti pas kitą interneto paslaugų tiekėją, turintį naujesnę PHP versiją!<br/>
+(Turint 5.0.x versiją, Jūs turėtumėte pereiti prie žemesnės 4.4.x versijos)</p>';
+$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
+$string['welcomep20'] = 'Jūs matote šį puslapį, nes sėkmingai įdiegėte ir užkrovėte <strong>{$a->packname} {$a->packversion}</strong> paketą savo kompiuteryje.
+Sveikiname!';
+$string['welcomep30'] = 'Šis <strong>{$a->installername}</strong> leidimas turi programas skirtas sukurti aplinką, kurioje <strong>Moodle</strong> veiks. Būtent:';
+$string['welcomep40'] = 'Šis paketas taip pat turi  <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
+$string['welcomep50'] = 'Pakete esančių programų naudojimas yra reguliuojamas atitinkamų licencijų. Pilnas <strong>{$a->installername}</strong> paketas  yra <a href="http://www.opensource.org/docs/definition_plain.html">atviro kodo</a> ir platinamas remiantis <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> licencija.';
+$string['welcomep60'] = 'Sekantys puslapiai ves Jus per keletą lengvų žingsnių, kurie padės sukonfigūruoti ir nustatyti <strong>Moodle</strong> Jūsų kompiuteryje. Jūs galite priimti nustatymus pagal nutylėjimą arba, pasirinktinai, pakeisti juos pagal savo poreikius.';
+$string['welcomep70'] = 'Spauskite "Toliau" mygtuką, norėdami tęsti <strong>Moodle</strong> nustatymą.';
+$string['wwwroot'] = 'Interneto adresas';
index dbf755f..42835f0 100644 (file)
@@ -90,7 +90,6 @@ $string['bookmarkthispage'] = 'bookmark this page';
 $string['cachejs'] = 'Cache Javascript';
 $string['cachejs_help'] = 'Javascript caching and compression greatly improves page loading performance. it is strongly recommended for production sites. Developers will probably want to disable this feature.';
 $string['cachetext'] = 'Text cache lifetime';
-$string['cachetype'] = 'Cache type';
 $string['calendarexportsalt'] = 'Calendar export salt';
 $string['calendarsettings'] = 'Calendar';
 $string['calendar_weekend'] = 'Weekend days';
@@ -143,7 +142,6 @@ $string['configautolang'] = 'Detect default language from browser setting, if di
 $string['configautologinguests'] = 'Should visitors be logged in as guests automatically when entering courses with guest access?';
 $string['configbloglevel'] = 'This setting allows you to restrict the level to which user blogs can be viewed on this site.  Note that they specify the maximum context of the VIEWER not the poster or the types of blog posts.  Blogs can also be disabled completely if you don\'t want them at all.';
 $string['configcachetext'] = 'For larger sites or sites that use text filters, this setting can really speed things up.  Copies of texts will be retained in their processed form for the time specified here.  Setting this too small may actually slow things down slightly,  but setting it too large may mean texts take too long to refresh (with new links, for example).';
-$string['configcachetype'] = 'Select a type of cache for Moodle to use. This will only configure the cache, remember to enable rcache so that the cache is used for something. Use <strong>only</strong> if you need to reduce the load on the database system -- otherwise Moodle will actually run slower. Medium-traffic sites may see benefits using \'internal\'. A single webserver with eAccelerator or Turckmmcache installed <em>with the shared memory options enabled</em> should try \'eaccelerator\'. If you have a multiple-server setup, and you have one or more memcached daemons running and the PHP-memcached extension, select \'memcached\' and configure the memached options below. <br /><strong>Note:</strong> make sure you test performance under load and tune accordingly -- the caches can make your site slower. In high-traffic situations, eAccelerator and memcached can yield the most benefits, but have the higher costs in CPU usage on the webserver.';
 $string['configcalendarexportsalt'] = 'This random text is used for improving of security of authentication tokens used for exporting of calendars. Please note that all current tokens are invalidated if you change this hash salt.';
 $string['configclamactlikevirus'] = 'Treat files like viruses';
 $string['configclamdonothing'] = 'Treat files as OK';
@@ -229,7 +227,6 @@ $string['configgradebookroles'] = 'This setting allows you to control who appear
 $string['configgradeexport'] = 'Choose which gradebook export formats are your primary methods for exporting grades.  Chosen plugins will then set and use a "last exported" field for every grade.  For example, this might result in exported records being identified as being "new" or "updated".  If you are not sure about this then leave everything unchecked.';
 $string['confighiddenuserfields'] = 'Select which user information fields you wish to hide from other users other than course teachers/admins. This will increase student privacy. Hold CTRL key to select multiple fields.';
 $string['configidnumber'] = 'This option specifies whether (a) Users are not be asked for an ID number at all, (b) Users are asked for an ID number but can leave it blank or (c) Users are asked for an ID Number and cannot leave it blank. If given the User\'s ID number is displayed in their Profile.';
-$string['configintcachemax'] = 'For internal cache only. Maximum number of records to keep in the cache. Recommended value: 50. Use lower values to reduce memory usage.';
 $string['configintro'] = 'On this page you can specify a number of configuration variables that help make Moodle work properly on your server.  Don\'t worry too much about it - the defaults will usually work fine and you can always come back to this page later and change these settings.';
 $string['configintroadmin'] = 'On this page you should configure your main administrator account which will have complete control over the site. Make sure you give it a secure username and password as well as a valid email address.  You can create more admin accounts later on.';
 $string['configintrosite'] = 'This page allows you to configure the front page and name of this new site.  You can come back here later to change these settings any time using the Administration menus.';
@@ -248,8 +245,6 @@ $string['configmaxbytes'] = 'This specifies a maximum size that uploaded files c
 $string['configmaxconsecutiveidentchars'] = 'Passwords must not have more than this number of consecutive identical characters. Use 0 to disable this check.';
 $string['configmaxeditingtime'] = 'This specifies the amount of time people have to re-edit forum postings, glossary comments etc.  Usually 30 minutes is a good value.';
 $string['configmaxevents'] = 'Events to Lookahead';
-$string['configmemcachedhosts'] = 'For memcached. Comma-separated list of hosts that are running the memcached daemon. Use IP addresses to avoid DNS latency. memcached does not behave well if you add/remove hosts on a running setup.';
-$string['configmemcachedpconn'] = 'For memcached. Use persistent connections. Use carefully -- it can make Apache/PHP crash after a restart of the memcached daemon.';
 $string['configmessaging'] = 'Should the messaging system between site users be enabled?';
 $string['configmessagingallowemailoverride'] = 'Allow users to have email message notifications sent to an email address other than the email address in their profile';
 $string['configmessaginghidereadnotifications'] = 'Hide read notifications of events like forum posts when viewing messaging history';
@@ -286,8 +281,6 @@ $string['configproxyport'] = 'If this server needs to use a proxy computer, then
 $string['configproxytype'] = 'Type of web proxy (PHP5 and cURL extension required for SOCKS5 support).';
 $string['configproxyuser'] = 'Username needed to access internet through proxy if required, empty if none (PHP cURL extension required).';
 $string['configquarantinedir'] = 'If you want clam AV to move infected files to a quarantine directory, enter it here. It must be writable by the webserver.  If you leave this blank, or if you enter a directory that doesn\'t exist or isn\'t writable, infected files will be deleted.  Do not include a trailing slash.';
-$string['configrcache'] = 'Use the cache to store database records. Remember to set \'cachetype\' as well!';
-$string['configrcachettl'] = 'Time-to-live for cached records, in seconds. Use a short (&lt;15) value here.';
 $string['configrecaptchaprivatekey'] = 'String of characters used to communicate between your Moodle server and the recaptcha server. Obtain one for this site by visiting http://www.google.com/recaptcha';
 $string['configrecaptchapublickey'] = 'String of characters used to display the reCAPTCHA element in the signup form. Generated by http://www.google.com/recaptcha';
 $string['configrequestcategoryselection'] = 'Allow the selection of a category when requesting a course.';
@@ -597,7 +590,6 @@ $string['includemoduleuserdata'] = 'Include module user data';
 $string['incompatibleblocks'] = 'Incompatible blocks';
 $string['installhijacked'] = 'Installation must be finished from the original IP address, sorry.';
 $string['installsessionerror'] = 'Can not initialise PHP session, please verify that your browser accepts cookies.';
-$string['intcachemax'] = 'Int. cache max';
 $string['intlrecommended'] = 'Intl extension is used to improve internationalization support, such as locale aware sorting.';
 $string['invalidsection'] = 'Invalid section.';
 $string['invaliduserchangeme'] = 'Username "changeme" is reserved -- you cannot create an account with it.';
@@ -681,8 +673,6 @@ $string['mediapluginswf'] = 'Enable .swf filter';
 $string['mediapluginswfnote'] = 'As a default security measure, normal users should not be allowed to embed swf flash files.';
 $string['mediapluginwmv'] = 'Enable .wmv filter';
 $string['mediapluginyoutube'] = 'Enable YouTube links filter';
-$string['memcachedhosts'] = 'memcached hosts';
-$string['memcachedpconn'] = 'memcached use persistent connections';
 $string['messaging'] = 'Enable messaging system';
 $string['messagingallowemailoverride'] = 'Notification email override';
 $string['messaginghidereadnotifications'] = 'Hide read notifications';
@@ -866,8 +856,6 @@ $string['questioncwqpfscheck'] = 'One or more \'random\' questions in a quiz are
 $string['questioncwqpfsok'] = 'Good. There are no \'random\' questions in your quizzes that are set up to select questions from a mixture of shared and unshared question categories.';
 $string['questiontype'] = 'Question type';
 $string['questiontypes'] = 'Question types';
-$string['rcache'] = 'Record cache';
-$string['rcachettl'] = 'Record cache TTL';
 $string['recaptchaprivatekey'] = 'ReCAPTCHA private key';
 $string['recaptchapublickey'] = 'ReCAPTCHA public key';
 $string['register'] = 'Register your site';
index 23e8ecf..54ee712 100644 (file)
@@ -161,6 +161,7 @@ $string['showglobalevents'] = 'Show global events';
 $string['showgroupsevents'] = 'Show group events';
 $string['showuserevents'] = 'Show user events';
 $string['shown'] = 'shown';
+$string['siteevents'] = 'Site events';
 $string['spanningevents'] = 'Events underway';
 $string['subscriptions'] = 'Subscriptions';
 $string['subscriptionname'] = 'Calendar name';
index 5594c8c..1a2c751 100644 (file)
@@ -40,7 +40,6 @@ $string['blocknoncontacts'] = 'Prevent non-contacts from messaging me';
 $string['contactlistempty'] = 'Your contact list is empty';
 $string['contacts'] = 'Contacts';
 $string['context'] = 'context';
-$string['couldnotfindpreference'] = 'Could not load preference {$a}. Does the component and name you supplied to message_send() match a row in message_providers? Message providers must appear in the database so users can configure how they will be notified when they receive messages.';
 $string['defaultmessageoutputs'] = 'Default message outputs';
 $string['defaults'] = 'Defaults';
 $string['deletemessagesdays'] = 'Number of days before old messages are automatically deleted';
index 9ed45e1..2eca489 100644 (file)
@@ -5075,16 +5075,16 @@ class admin_setting_manageenrols extends admin_setting {
                 if ($updowncount > 1) {
                     $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
                     $updown .= "<a href=\"$aurl\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /></a>&nbsp;";
                 } else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
                 }
                 if ($updowncount < $enrolcount) {
                     $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
                     $updown .= "<a href=\"$aurl\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" /></a>";
                 } else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
                 }
                 ++$updowncount;
             }
@@ -5299,7 +5299,8 @@ class admin_page_manageqtypes extends admin_externalpage {
      */
     public function __construct() {
         global $CFG;
-        parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'), "$CFG->wwwroot/$CFG->admin/qtypes.php");
+        parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'),
+                new moodle_url('/admin/qtypes.php'));
     }
 
     /**
@@ -5605,17 +5606,17 @@ class admin_setting_manageauths extends admin_setting {
             if ($enabled) {
                 if ($updowncount > 1) {
                     $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
                 }
                 if ($updowncount < $authcount) {
                     $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
                 }
                 ++ $updowncount;
             }
@@ -5772,17 +5773,17 @@ class admin_setting_manageeditors extends admin_setting {
             if ($enabled) {
                 if ($updowncount > 1) {
                     $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
                 }
                 if ($updowncount < $editorcount) {
                     $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
                 }
                 else {
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
                 }
                 ++ $updowncount;
             }
@@ -5999,7 +6000,7 @@ class admin_setting_manageformats extends admin_setting {
 
         $cnt = 0;
         $defaultformat = get_config('moodlecourse', 'format');
-        $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon'));
+        $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
         foreach ($formats as $format) {
             $url = new moodle_url('/admin/courseformats.php',
                     array('sesskey' => sesskey(), 'format' => $format->name));
@@ -6020,13 +6021,13 @@ class admin_setting_manageformats extends admin_setting {
             $updown = '';
             if ($cnt) {
                 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
-                    $OUTPUT->pix_icon('t/up', $txt->up, 'moodle')). '&nbsp;';
+                    $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
             } else {
                 $updown .= $spacer;
             }
             if ($cnt < count($formats) - 1) {
                 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
-                    $OUTPUT->pix_icon('t/down', $txt->down, 'moodle'));
+                    $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
             } else {
                 $updown .= $spacer;
             }
@@ -6861,18 +6862,19 @@ class admin_setting_managerepository extends admin_setting {
 
                 // Display up/down link
                 $updown = '';
-                $spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
+                // Should be done with CSS instead.
+                $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
 
                 if ($updowncount > 1) {
                     $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
                 }
                 else {
                     $updown .= $spacer;
                 }
                 if ($updowncount < $totalinstances) {
                     $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
-                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
+                    $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
                 }
                 else {
                     $updown .= $spacer;
index 3c2936b..1f6bf3d 100644 (file)
@@ -232,7 +232,7 @@ class iCalendar_component {
     
     function unserialize($string) {
         $string = rfc2445_unfold($string); // Unfold any long lines
-        $lines = explode(RFC2445_CRLF, $string); // Create an array of lines
+        $lines = preg_split("<".RFC2445_CRLF."|\n|\r>", $string, 0, PREG_SPLIT_NO_EMPTY); // Create an array of lines.
         
         $components = array(); // Initialise a stack of components
         $this->clear_errors();
index 1c6154b..582b265 100644 (file)
@@ -2,4 +2,5 @@ Description of Bennu library import - customised library by author, this version
 
 modifications:
 1/ removed ereg functions deprecated as of php 5.3 (18 Nov 2009)
-2/ replaced mbstring functions with moodle textlib (28 Nov 2011)
\ No newline at end of file
+2/ replaced mbstring functions with moodle textlib (28 Nov 2011)
+3/ replaced explode in iCalendar_component::unserialize() with preg_split to support various line breaks (20 Nov 2012)
\ No newline at end of file
index c28c919..e566933 100644 (file)
@@ -1067,7 +1067,7 @@ class block_manager {
 
             $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
                     '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($return),
-                    'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'), 'class' => 'editing_roles');
+                    'icon' => 't/assignroles', 'caption' => get_string('assignroles', 'role'), 'class' => 'editing_roles');
         }
 
         return $controls;
index d160359..548f854 100644 (file)
@@ -251,6 +251,8 @@ function css_minify_css($files) {
     Minify::setCache(null, false);
 
     $options = array(
+        // JSMin is not GNU GPL compatible, use the plus version instead.
+        'minifiers' => array(Minify::TYPE_JS => array('JSMinPlus', 'minify')),
         'bubbleCssImports' => false,
         // Don't gzip content we just want text for storage
         'encodeOutput' => false,
index aee878f..5bd64ec 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20121102" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20121112" COMMENT="XMLDB file for core Moodle tables"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
 >
         <KEY NAME="fk_raterid" TYPE="foreign" FIELDS="raterid" REFTABLE="user" REFFIELDS="id" PREVIOUS="fk_definitionid"/>
       </KEYS>
     </TABLE>
-    <TABLE NAME="event_subscriptions" COMMENT="Tracks subscriptions to remote calendars." PREVIOUS="grading_instances">
+    <TABLE NAME="event_subscriptions" COMMENT="Tracks subscriptions to remote calendars." PREVIOUS="grading_instances" NEXT="temp_enroled_template">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="url"/>
         <FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="courseid"/>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
     </TABLE>
+    <TABLE NAME="temp_enroled_template" COMMENT="Temporary storage for course enrolments" PREVIOUS="event_subscriptions" NEXT="temp_log_template">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
+        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="courseid"/>
+        <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="roleid"/>
+        <FIELD NAME="roleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="courseid"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+        <INDEX NAME="userid" UNIQUE="false" FIELDS="userid" NEXT="courseid"/>
+        <INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid" PREVIOUS="userid" NEXT="roleid"/>
+        <INDEX NAME="roleid" UNIQUE="false" FIELDS="roleid" PREVIOUS="courseid"/>
+      </INDEXES>
+    </TABLE>
+    <TABLE NAME="temp_log_template" COMMENT="Temporary storage for daily logs" PREVIOUS="temp_enroled_template">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
+        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="course"/>
+        <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="action"/>
+        <FIELD NAME="action" TYPE="char" LENGTH="40" NOTNULL="true" SEQUENCE="false" PREVIOUS="course"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+        <INDEX NAME="action" UNIQUE="false" FIELDS="action" NEXT="course"/>
+        <INDEX NAME="course" UNIQUE="false" FIELDS="course" PREVIOUS="action" NEXT="user"/>
+        <INDEX NAME="user" UNIQUE="false" FIELDS="userid" PREVIOUS="course" NEXT="usercourseaction"/>
+        <INDEX NAME="usercourseaction" UNIQUE="false" FIELDS="userid, course, action" PREVIOUS="user"/>
+      </INDEXES>
+    </TABLE>
   </TABLES>
 </XMLDB>
index 6e904b2..d630e21 100644 (file)
@@ -1414,5 +1414,78 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012110700.01);
     }
 
+    if ($oldversion < 2012111200.00) {
+
+        // Define table temp_enroled_template to be created
+        $table = new xmldb_table('temp_enroled_template');
+
+        // Adding fields to table temp_enroled_template
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
+
+        // Adding keys to table temp_enroled_template
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+        // Adding indexes to table temp_enroled_template
+        $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
+        $table->add_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
+        $table->add_index('roleid', XMLDB_INDEX_NOTUNIQUE, array('roleid'));
+
+        // Conditionally launch create table for temp_enroled_template
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Define table temp_log_template to be created
+        $table = new xmldb_table('temp_log_template');
+
+        // Adding fields to table temp_log_template
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_field('action', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null);
+
+        // Adding keys to table temp_log_template
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+        // Adding indexes to table temp_log_template
+        $table->add_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
+        $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
+        $table->add_index('user', XMLDB_INDEX_NOTUNIQUE, array('userid'));
+        $table->add_index('usercourseaction', XMLDB_INDEX_NOTUNIQUE, array('userid', 'course', 'action'));
+
+        // Conditionally launch create table for temp_log_template
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012111200.00);
+    }
+
+    if ($oldversion < 2012111200.01) {
+        // Force the rebuild of the cache of every courses, some cached information could contain wrong icon references.
+        rebuild_course_cache();
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2012111200.01);
+    }
+
+    if ($oldversion < 2012111601.01) {
+        // Clea up after old shared memory caching support.
+        unset_config('cachetype');
+        unset_config('rcache');
+        unset_config('rcachettl');
+        unset_config('intcachemax');
+        unset_config('memcachedhosts');
+        unset_config('memcachedpconn');
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2012111601.01);
+    }
+
+
     return true;
 }
diff --git a/lib/eaccelerator.class.php b/lib/eaccelerator.class.php
deleted file mode 100644 (file)
index bde70b9..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-<?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/>.
-
-/**
- * This class abstracts eaccelerator/turckmmcache
- * API to provide
- *
- * - get()
- * - set()
- * - delete()
- * - getforfill()
- * - releaseforfill()
- *
- * Note: do NOT store booleans here. For compatibility with
- * memcached, a false value is indistinguisable from a
- * "not found in cache" response.
- *
- * @package    core
- * @subpackage lib
- * @copyright  Martin Langhoff <martin@catalyst.net.nz>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- *
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @package moodlecore
- */
-class eaccelerator {
-
-    /**
-     * @todo Document this function
-     *
-     * @global object
-     */
-    function eaccelerator() {
-        global $CFG;
-        if ( function_exists('eaccelerator_get')) {
-            $this->mode = 'eaccelerator';
-        } elseif (function_exists('mmcache_get')) {
-            $this->mode = 'mmcache';
-        } else {
-            debugging("\$CFG->eaccelerator is set to true but the required functions are not available. You need to have either eaccelerator or turckmmcache extensions installed, compiled with the shmem keys option enabled.");
-        }
-
-        $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
-    }
-
-    /**
-     * The status of the eaccelerator, if it has been established
-     * this will return true
-     *
-     * @return bool
-     */
-    function status() {
-        if (isset($this->mode)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @todo Document this function
-     *
-     * @param string $key
-     * @param string $value
-     * @param int $ttl
-     * @return mixed
-     */
-    function set($key, $value, $ttl=0) {
-        $set    = $this->mode . '_put';
-        $unlock = $this->mode . '_unlock';
-
-        // we may have acquired a lock via getforfill
-        // release if it exists
-        @$unlock($this->prefix . $key . '_forfill');
-
-        return $set($this->prefix . $key, serialize($value), $ttl);
-    }
-
-    /**
-     * @todo Document this function
-     *
-     * @param string $key
-     * @return string|bool String if success else false
-     */
-    function get($key) {
-        $fn = $this->mode . '_get';
-        $rec = $fn($this->prefix . $key);
-        if (is_null($rec)) {
-            return false;
-        }
-        return unserialize($rec);
-    }
-
-    /**
-     * @todo Document this function
-     *
-     * @param string $key
-     * @return mixed
-     */
-    function delete($key) {
-        $fn = $this->mode . '_rm';
-        return $fn($this->prefix . $key);
-    }
-
-    /**
-     * In the simple case, this function will
-     * get the cached value if available. If the entry
-     * is not cached, it will try to get an exclusive
-     * lock that announces that this process will
-     * populate the cache.
-     *
-     * If we fail to get the lock -- this means another
-     * process is doing it.
-     * so we wait (block) for a few microseconds while we wait for
-     * the cache to be filled or the lock to timeout.
-     *
-     * If you get a false from this call, you _must_
-     * populate the cache ASAP or indicate that
-     * you won't by calling releaseforfill().
-     *
-     * This technique forces serialisation and so helps deal
-     * with thundering herd scenarios where a lot of clients
-     * ask the for the same idempotent (and costly) operation.
-     * The implementation is based on suggestions in this message
-     * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
-     *
-     * @param $key string
-     * @return mixed on cache hit, false otherwise
-     */
-    function getforfill ($key) {
-        $get    = $this->mode . '_get';
-        $lock   = $this->mode . '_lock';
-
-        $rec = $get($this->prefix . $key);
-        if (!is_null($rec)) {
-            return unserialize($rec);
-        }
-        if ($lock($this->prefix . $key . '_forfill')) {
-            // we obtained the _forfill lock
-            // our caller will compute and set the value
-            return false;
-        }
-        // someone else has the lock
-        // "block" till we can get the value
-        // actually, loop .05s waiting for it
-        for ($n=0;$n<5;$n++) {
-            usleep(10000);
-            $rec = $get($this->prefix . $key);
-            if (!is_null($rec)) {
-                return unserialize($rec);
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Release the exclusive lock obtained by
-     * getforfill(). See getforfill()
-     * for more details.
-     *
-     * @param $key string
-     * @return bool
-     */
-    function releaseforfill ($key) {
-        $unlock = $this->mode . '_unlock';
-        return $unlock($this->prefix . $key . '_forfill');
-    }
-}
-
-?>
\ No newline at end of file
index e2b74da..57ce3d9 100644 (file)
@@ -56,6 +56,7 @@ $relroot = preg_replace('|^http.?://[^/]+|', '', $CFG->wwwroot);
 
 $htmllang = get_html_lang();
 header('Content-Type: text/html; charset=utf-8');
+header('X-UA-Compatible: IE=edge');
 ?>
 <!DOCTYPE html>
 <html <?php echo $htmllang ?>
index 7ca35ce..071c481 100644 (file)
@@ -88,6 +88,8 @@ if ($mimetype === 'application/x-javascript' && $allowcache) {
     }
 
     $file = $cachefile;
+} else if ($mimetype === 'text/html') {
+    header('X-UA-Compatible: IE=edge');
 }
 
 // Serve file.
index 39bf1ac..d26d8eb 100644 (file)
@@ -37,6 +37,7 @@ $plugin = $editor->get_plugin('moodleemoticon');
 
 $htmllang = get_html_lang();
 header('Content-Type: text/html; charset=utf-8');
+header('X-UA-Compatible: IE=edge');
 ?>
 <!DOCTYPE html>
 <html <?php echo $htmllang ?>
index afb60da..e3acf2d 100644 (file)
@@ -39,7 +39,7 @@ class GoogleSpell extends SpellChecker {
                $matches = $this->_getMatches($lang, $word);\r
 \r
                if (count($matches) > 0)\r
-                       $sug = explode("\t", utf8_encode($this->_unhtmlentities($matches[0][4])));\r
+                       $sug = explode("\t", $this->_unhtmlentities($matches[0][4]));\r
 \r
                // Remove empty\r
                foreach ($sug as $item) {\r
index 47fdd0d..21bc763 100644 (file)
@@ -19,8 +19,9 @@ Upgrade procedure:
 
 Changes:
 
-1/ zIndex 300000 and 200000 changed to 3000 and 2000 - this prevents collision with YUI,
+ * zIndex 300000 and 200000 changed to 3000 and 2000 - this prevents collision with YUI,
    see MDL-35771
+ * MDL-25736 - French spellchecker fixes.
 
 TODO:
  * create some new automated script that sends other languages from upstream into AMOS
index a045d77..6295a10 100644 (file)
@@ -401,7 +401,7 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
         // list all participants - allows assigning roles, groups, etc.
         if (has_capability('moodle/course:enrolreview', $coursecontext)) {
             $url = new moodle_url('/enrol/users.php', array('id'=>$course->id));
-            $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'review', new pix_icon('i/users', ''));
+            $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'review', new pix_icon('i/enrolusers', ''));
         }
 
         // manage enrol plugin instances
@@ -444,7 +444,7 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
         if ($course->id == SITEID or (!empty($CFG->adminsassignrolesincourse) and is_siteadmin())) {
             if (has_capability('moodle/role:assign', $coursecontext)) {
                 $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$coursecontext->id));
-                $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/roles', ''));
+                $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/assignroles', ''));
             }
         }
         // Check role permissions
@@ -459,7 +459,7 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
         //TODO, create some new UI for role assignments at course level
         if (has_capability('moodle/role:assign', $coursecontext)) {
             $url = new moodle_url('/enrol/otherusers.php', array('id'=>$course->id));
-            $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/roles', ''));
+            $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/assignroles', ''));
         }
     }
 
index 96dede0..6c935ef 100644 (file)
@@ -3685,7 +3685,6 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
             if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'eventtype'=>'site'))) {
                 send_file_not_found();
             }
-            // Check that we got an event and that it's userid is that of the user
 
             // Get the file and serve if successful
             $filename = array_pop($args);
@@ -3733,8 +3732,8 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
                 require_login($course);
             }
 
-            // Must be able to at least view the course
-            if (!is_enrolled($context) and !is_viewing($context)) {
+            // Must be able to at least view the course. This does not apply to the front page.
+            if ($course->id != SITEID && (!is_enrolled($context)) && (!is_viewing($context))) {
                 //TODO: hmm, do we really want to block guests here?
                 send_file_not_found();
             }
@@ -3755,10 +3754,10 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
                 if (!has_capability('moodle/site:accessallgroups', $context) && !groups_is_member($event->groupid, $USER->id)) {
                     send_file_not_found();
                 }
-            } else if ($event->eventtype === 'course') {
-                //ok
+            } else if ($event->eventtype === 'course' || $event->eventtype === 'site') {
+                // Ok. Please note that the event type 'site' still uses a course context.
             } else {
-                // some other type
+                // Some other type.
                 send_file_not_found();
             }
 
index 5e39e77..e5e1830 100644 (file)
@@ -2227,15 +2227,15 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
         // switch next two lines for ol li containers for form items.
         //        $this->_elementTemplates=array('default'=>"\n\t\t".'<li class="fitem"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class="qfelement<!-- BEGIN error --> error<!-- END error --> {type}"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></li>');
         $this->_elementTemplates = array(
-        'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
+        'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
 
         'actionbuttons'=>"\n\t\t".'<div id="{id}" class="fitem fitem_actionbuttons fitem_{type}"><div class="felement {type}">{element}</div></div>',
 
-        'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
+        'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
 
-        'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}&nbsp;</div></div>',
+        'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}&nbsp;</div></div>',
 
-'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
+        'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
 
         'nodisplay'=>'');
 
index 3ace654..4b1307e 100644 (file)
@@ -81,11 +81,19 @@ class google_docs {
         if ($search) {
             $url.='?q='.urlencode($search);
         }
-        $content = $this->googleoauth->get($url);
-
-        $xml = new SimpleXMLElement($content);
 
         $files = array();
+        $content = $this->googleoauth->get($url);
+        try {
+            if (strpos($content, '<?xml') !== 0) {
+                throw new moodle_exception('invalidxmlresponse');
+            }
+            $xml = new SimpleXMLElement($content);
+        } catch (Exception $e) {
+            // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
+            // return a more specific Exception, that's why the global Exception class is caught here.
+            return $files;
+        }
         foreach ($xml->entry as $gdoc) {
             $docid  = (string) $gdoc->children('http://schemas.google.com/g/2005')->resourceId;
             list($type, $docid) = explode(':', $docid);
@@ -317,10 +325,19 @@ class google_picasa {
      * @return mixes $files Array in the format get_listing uses for folders
      */
     public function get_albums() {
+        $files = array();
         $content = $this->googleoauth->get(self::LIST_ALBUMS_URL);
-        $xml = new SimpleXMLElement($content);
 
-        $files = array();
+        try {
+            if (strpos($content, '<?xml') !== 0) {
+                throw new moodle_exception('invalidxmlresponse');
+            }
+            $xml = new SimpleXMLElement($content);
+        } catch (Exception $e) {
+            // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
+            // return a more specific Exception, that's why the global Exception class is caught here.
+            return $files;
+        }
 
         foreach ($xml->entry as $album) {
             $gphoto = $album->children('http://schemas.google.com/photos/2007');
@@ -338,7 +355,6 @@ class google_picasa {
                 'thumbnail_height' => 160,
                 'children' => array(),
             );
-
         }
 
         return $files;
@@ -352,12 +368,20 @@ class google_picasa {
      * @return mixed $files A list of files for the file picker
      */
     public function get_photo_details($rawxml) {
+        $files = array();
 
-        $xml = new SimpleXMLElement($rawxml);
+        try {
+            if (strpos($rawxml, '<?xml') !== 0) {
+                throw new moodle_exception('invalidxmlresponse');
+            }
+            $xml = new SimpleXMLElement($rawxml);
+        } catch (Exception $e) {
+            // An error occured while trying to parse the XML, let's just return nothing. SimpleXML does not
+            // return a more specific Exception, that's why the global Exception class is caught here.
+            return $files;
+        }
         $this->lastalbumname = (string)$xml->title;
 
-        $files = array();
-
         foreach ($xml->entry as $photo) {
             $gphoto = $photo->children('http://schemas.google.com/photos/2007');
 
index 12afe84..8378b78 100644 (file)
@@ -1423,30 +1423,33 @@ class grade_item extends grade_object {
      * Refetch grades from modules, plugins.
      *
      * @param int $userid optional, limit the refetch to a single user
+     * @return bool Returns true on success or if there is nothing to do
      */
     public function refresh_grades($userid=0) {
         global $DB;
         if ($this->itemtype == 'mod') {
             if ($this->is_outcome_item()) {
                 //nothing to do
-                return;
+                return true;
             }
 
             if (!$activity = $DB->get_record($this->itemmodule, array('id' => $this->iteminstance))) {
                 debugging("Can not find $this->itemmodule activity with id $this->iteminstance");
-                return;
+                return false;
             }
 
             if (!$cm = get_coursemodule_from_instance($this->itemmodule, $activity->id, $this->courseid)) {
                 debugging('Can not find course module');
-                return;
+                return false;
             }
 
             $activity->modname    = $this->itemmodule;
             $activity->cmidnumber = $cm->idnumber;
 
-            grade_update_mod_grades($activity);
+            return grade_update_mod_grades($activity, $userid);
         }
+
+        return true;
     }
 
     /**
index dab82c2..35d527b 100644 (file)
@@ -58,6 +58,7 @@ class grade_item_testcase extends grade_base_testcase {
         $this->sub_test_grade_item_is_course_item();
         $this->sub_test_grade_item_fetch_course_item();
         $this->sub_test_grade_item_depends_on();
+        $this->sub_test_refresh_grades();
         $this->sub_test_grade_item_is_calculated();
         $this->sub_test_grade_item_set_calculation();
         $this->sub_test_grade_item_get_calculation();
@@ -483,6 +484,18 @@ class grade_item_testcase extends grade_base_testcase {
         $this->assertEquals($res, $deps);
     }
 
+    protected function sub_test_refresh_grades() {
+        // Testing with the grade item for a mod_assignment instance.
+        $grade_item = new grade_item($this->grade_items[0], false);
+        $this->assertTrue(method_exists($grade_item, 'refresh_grades'));
+        $this->assertTrue($grade_item->refresh_grades());
+
+        // Break the grade item and check error handling.
+        $grade_item->iteminstance = 123456789;
+        $this->assertFalse($grade_item->refresh_grades());
+        $this->assertDebuggingCalled();
+    }
+
     protected function sub_test_grade_item_is_calculated() {
         $grade_item = new grade_item($this->grade_items[1], false);
         $this->assertTrue(method_exists($grade_item, 'is_calculated'));
index f83cffd..f8742c2 100644 (file)
@@ -1190,7 +1190,7 @@ function grade_update_mod_grades($modinstance, $userid=0) {
         $updategradesfunc($modinstance, $userid);
 
     } else {
-        // mudule does not support grading??
+        // Module does not support grading?
     }
 
     return true;
index bc6f902..7b8cca2 100644 (file)
@@ -253,6 +253,7 @@ function install_print_help_page($help) {
     global $CFG, $OUTPUT; //TODO: MUST NOT USE $OUTPUT HERE!!!
 
     @header('Content-Type: text/html; charset=UTF-8');
+    @header('X-UA-Compatible: IE=edge');
     @header('Cache-Control: no-store, no-cache, must-revalidate');
     @header('Cache-Control: post-check=0, pre-check=0', false);
     @header('Pragma: no-cache');
@@ -299,6 +300,7 @@ function install_print_header($config, $stagename, $heading, $stagetext) {
     global $CFG;
 
     @header('Content-Type: text/html; charset=UTF-8');
+    @header('X-UA-Compatible: IE=edge');
     @header('Cache-Control: no-store, no-cache, must-revalidate');
     @header('Cache-Control: post-check=0, pre-check=0', false);
     @header('Pragma: no-cache');
index 077693d..6044ea1 100644 (file)
@@ -111,7 +111,7 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
     // Get the height of the div at this point before we shrink it if required
     var height = this.div.get('offsetHeight');
     var collapsedimage = 't/collapsed'; // ltr mode
-    if ( Y.one(document.body).hasClass('dir-rtl') ) {
+    if (right_to_left()) {
         collapsedimage = 't/collapsed_rtl';
     } else {
         collapsedimage = 't/collapsed';
@@ -140,7 +140,7 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
     animation.on('end', function() {
         this.div.toggleClass('collapsed');
         var collapsedimage = 't/collapsed'; // ltr mode
-        if ( Y.one(document.body).hasClass('dir-rtl') ) {
+        if (right_to_left()) {
             collapsedimage = 't/collapsed_rtl';
             } else {
             collapsedimage = 't/collapsed';
@@ -871,7 +871,7 @@ M.util.add_lightbox = function(Y, node) {
         'top' : 0,
         'left' : 0,
         'backgroundColor' : 'white',
-        'text-align' : 'center'
+        'textAlign' : 'center'
     })
     .setAttribute('class', 'lightbox')
     .hide();
@@ -1209,6 +1209,20 @@ function getElementsByClassName(oElm, strTagName, name) {
     return (arrReturnElements)
 }
 
+/**
+ * Return whether we are in right to left mode or not.
+ *
+ * @return boolean
+ */
+function right_to_left() {
+    var body = Y.one('body');
+    var rtl = false;
+    if (body && body.hasClass('dir-rtl')) {
+        rtl = true;
+    }
+    return rtl;
+}
+
 function openpopup(event, args) {
 
     if (event) {
index ee905f1..1d20bbd 100644 (file)
@@ -114,6 +114,8 @@ function js_minify($files) {
     Minify::setCache(null, false);
 
     $options = array(
+        // JSMin is not GNU GPL compatible, use the plus version instead.
+        'minifiers' => array(Minify::TYPE_JS => array('JSMinPlus', 'minify')),
         'bubbleCssImports' => false,
         // Don't gzip content we just want text for storage
         'encodeOutput' => false,
diff --git a/lib/memcached.class.php b/lib/memcached.class.php
deleted file mode 100644 (file)
index 35ac0f4..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-<?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/>.
-
-/**
- * @package    core
- * @subpackage lib
- * @copyright  Martin Langhoff <martin@catalyst.net.nz>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * This class abstracts PHP's PECL memcached
- * API to provide
- *
- * - get()
- * - set()
- * - delete()
- * - getforfill()
- * - releaseforfill()
- *
- * Author: Martin Langhoff <martin@catalyst.net.nz>
- *
- * Note: do NOT store booleans here. With memcached, a false value
- * is indistinguisable from a "not found in cache" response.
- *
- * @package   moodlecore
- * @copyright Martin Langhoff <martin@catalyst.net.nz>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-class memcached {
-
-    function memcached() {
-        global $CFG;
-
-        if (!function_exists('memcache_connect')) {
-            debugging("Memcached is set to true but the memcached extension is not installed");
-            return false;
-        }
-        $this->_cache = new Memcache;
-
-        $hosts = explode(',', $CFG->memcachedhosts);
-        if (count($hosts) === 1 && !empty($CFG->memcachedpconn)) {
-            // the faster pconnect is only available
-            // for single-server setups
-            // NOTE: PHP-PECL client is buggy and pconnect()
-            // will segfault if the server is unavailable
-            $this->_cache->pconnect($hosts[0]);
-        } else {
-            // multi-host setup will share key space
-            foreach ($hosts as $host) {
-                $host = trim($host);
-                $this->_cache->addServer($host);
-            }
-        }
-
-        $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
-    }
-
-    function status() {
-        if (is_object($this->_cache)) {
-            return true;
-        }
-        return false;
-    }
-
-    function set($key, $value, $ttl=0) {
-
-        // we may have acquired a lock via getforfill
-        // release if it exists
-        @$this->_cache->delete($this->prefix . $key . '_forfill');
-
-        return $this->_cache->set($this->prefix . $key, $value, false);
-    }
-
-    function get($key) {
-        $rec = $this->_cache->get($this->prefix . $key);
-        return $rec;
-    }
-
-    function delete($key) {
-        return $this->_cache->delete($this->prefix . $key);
-    }
-
-    /**
-     * In the simple case, this function will
-     * get the cached value if available. If the entry
-     * is not cached, it will try to get an exclusive
-     * lock that announces that this process will
-     * populate the cache.
-     *
-     * If we fail to get the lock -- this means another
-     * process is doing it.
-     * so we wait (block) for a few microseconds while we wait for
-     * the cache to be filled or the lock to timeout.
-     *
-     * If you get a false from this call, you _must_
-     * populate the cache ASAP or indicate that
-     * you won't by calling releaseforfill().
-     *
-     * This technique forces serialisation and so helps deal
-     * with thundering herd scenarios where a lot of clients
-     * ask the for the same idempotent (and costly) operation.
-     * The implementation is based on suggestions in this message
-     * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
-     *
-     * @param $key string
-     * @return mixed on cache hit, NULL otherwise
-     */
-    function getforfill ($key) {
-
-        $rec = $this->_cache->get($this->prefix . $key);
-        if ($rec) {
-            return $rec;
-        }
-        if ($this->_cache->add($this->prefix . $key . '_forfill', 'true', false, 1)) {
-            // we obtained the _forfill lock
-            // our caller will compute and set the value
-            return false;
-        }
-        // someone else has the lock
-        // "block" till we can get the value
-        // actually, loop .05s waiting for it
-        for ($n=0;$n<5;$n++) {
-            usleep(10000);
-            $rec = $this->_cache->get($this->prefix . $key);
-            if ($rec) {
-                return $rec;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Release the exclusive lock obtained by
-     * getforfill(). See getforfill()
-     * for more details.
-     *
-     * @param $key string
-     * @return bool
-     */
-    function releaseforfill ($key) {
-        return $this->_cache->delete($this->prefix . $key . '_forfill');
-    }
-}
index d007432..d464106 100644 (file)
@@ -155,10 +155,11 @@ function message_send($eventdata) {
         if (isset($defaultpreferences->{$defaultpreference})) {
             $permitted = $defaultpreferences->{$defaultpreference};
         } else {
-            //MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
-            //exist in the message_provider table (thus there is no default settings for them)
-            $preferrormsg = get_string('couldnotfindpreference', 'message', $defaultpreference);
-            throw new coding_exception($preferrormsg,'blah');
+            // MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
+            // exist in the message_provider table (thus there is no default settings for them).
+            $preferrormsg = "Could not load preference $defaultpreference. Make sure the component and name you supplied
+                    to message_send() are valid.";
+            throw new coding_exception($preferrormsg);
         }
 
         // Find out if user has configured this output
@@ -414,32 +415,98 @@ function message_get_my_providers() {
 function message_get_providers_for_user($userid) {
     global $DB, $CFG;
 
-    $systemcontext = context_system::instance();
-
     $providers = get_message_providers();
 
-    // Remove all the providers we aren't allowed to see now
-    foreach ($providers as $providerid => $provider) {
-        if (!empty($provider->capability)) {
-            if (!has_capability($provider->capability, $systemcontext, $userid)) {
-                unset($providers[$providerid]);   // Not allowed to see this
-                continue;
+    // Ensure user is not allowed to configure instantmessage if it is globally disabled.
+    if (!$CFG->messaging) {
+        foreach ($providers as $providerid => $provider) {
+            if ($provider->name == 'instantmessage') {
+                unset($providers[$providerid]);
+                break;
             }
         }
+    }
 
-        // Ensure user is not allowed to configure instantmessage if it is globally disabled.
-        if (!$CFG->messaging && $provider->name == 'instantmessage') {
+    // If the component is an enrolment plugin, check it is enabled
+    foreach ($providers as $providerid => $provider) {
+        list($type, $name) = normalize_component($provider->component);
+        if ($type == 'enrol' && !enrol_is_enabled($name)) {
             unset($providers[$providerid]);
+        }
+    }
+
+    // Now we need to check capabilities. We need to eliminate the providers
+    // where the user does not have the corresponding capability anywhere.
+    // Here we deal with the common simple case of the user having the
+    // capability in the system context. That handles $CFG->defaultuserroleid.
+    // For the remaining providers/capabilities, we need to do a more complex
+    // query involving all overrides everywhere.
+    $unsureproviders = array();
+    $unsurecapabilities = array();
+    $systemcontext = context_system::instance();
+    foreach ($providers as $providerid => $provider) {
+        if (empty($provider->capability) || has_capability($provider->capability, $systemcontext, $userid)) {
+            // The provider is relevant to this user.
             continue;
         }
 
-        // If the component is an enrolment plugin, check it is enabled
-        list($type, $name) = normalize_component($provider->component);
-        if ($type == 'enrol') {
-            if (!enrol_is_enabled($name)) {
-                unset($providers[$providerid]);
-                continue;
-            }
+        $unsureproviders[$providerid] = $provider;
+        $unsurecapabilities[$provider->capability] = 1;
+        unset($providers[$providerid]);
+    }
+
+    if (empty($unsureproviders)) {
+        // More complex checks are not required.
+        return $providers;
+    }
+
+    // Now check the unsure capabilities.
+    list($capcondition, $params) = $DB->get_in_or_equal(
+            array_keys($unsurecapabilities), SQL_PARAMS_NAMED);
+    $params['userid'] = $userid;
+
+    $sql = "SELECT DISTINCT rc.capability, 1
+
+              FROM {role_assignments} ra
+              JOIN {context} actx ON actx.id = ra.contextid
+              JOIN {role_capabilities} rc ON rc.roleid = ra.roleid
+              JOIN {context} cctx ON cctx.id = rc.contextid
+
+             WHERE ra.userid = :userid
+               AND rc.capability $capcondition
+               AND rc.permission > 0
+               AND (".$DB->sql_concat('actx.path', "'/'")." LIKE ".$DB->sql_concat('cctx.path', "'/%'").
+               " OR ".$DB->sql_concat('cctx.path', "'/'")." LIKE ".$DB->sql_concat('actx.path', "'/%'").")";
+
+    if (!empty($CFG->defaultfrontpageroleid)) {
+        $frontpagecontext = context_course::instance(SITEID);
+
+