Merge branch 'MDL-29805-23' of git://github.com/mouneyrac/moodle into MOODLE_23_STABLE
authorSam Hemelryk <sam@moodle.com>
Tue, 11 Dec 2012 20:45:03 +0000 (09:45 +1300)
committerSam Hemelryk <sam@moodle.com>
Tue, 11 Dec 2012 20:45:03 +0000 (09:45 +1300)
94 files changed:
.gitignore
admin/tool/phpunit/cli/util.php
admin/tool/uploaduser/index.php
auth/ldap/auth.php
backup/moodle2/restore_stepslib.php
backup/util/loggers/file_logger.class.php
backup/util/loggers/output_indented_logger.class.php
backup/util/loggers/output_text_logger.class.php
blocks/community/block_community.php
blocks/glossary_random/block_glossary_random.php
blocks/online_users/block_online_users.php
composer.json [new file with mode: 0644]
course/externallib.php
course/lib.php
course/recent_form.php
course/rest.php
enrol/README.txt
enrol/paypal/ipn.php
enrol/paypal/lib.php
grade/report/grader/styles.css
grade/report/lib.php
grade/tests/reportlib_test.php [new file with mode: 0644]
install/lang/ga/moodle.php [new file with mode: 0644]
lib/accesslib.php
lib/ajax/blocks.php
lib/datalib.php
lib/ddl/oracle_sql_generator.php
lib/dml/pdo_moodle_database.php
lib/dml/tests/dml_test.php
lib/editor/tinymce/lang/en/editor_tinymce.php
lib/excellib.class.php
lib/filelib.php
lib/filestorage/tests/file_storage_test.php
lib/formslib.php
lib/grade/grade_category.php
lib/moodlelib.php
lib/navigationlib.php
lib/phpunit/classes/hint_resultprinter.php
lib/phpunit/readme.md
lib/pluginlib.php
lib/sessionlib.php
lib/tablelib.php
lib/tests/moodlelib_test.php
lib/tests/pagelib_test.php
lib/webdavlib.php
lib/yui/blocks/blocks.js
message/edit.php
message/lib.php
mod/assign/gradingbatchoperationsform.php
mod/assign/gradingoptionsform.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/renderer.php
mod/assign/submission/comments/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/upgradelib.php
mod/assignment/lib.php
mod/data/field/latlong/kml.php
mod/data/view.php
mod/feedback/item/captcha/captcha_form.php
mod/feedback/item/multichoice/multichoice_form.php
mod/feedback/item/multichoicerated/multichoicerated_form.php
mod/feedback/item/numeric/numeric_form.php
mod/feedback/item/textarea/textarea_form.php
mod/feedback/item/textfield/textfield_form.php
mod/lesson/format.php
mod/lesson/view.php
mod/lti/backup/moodle2/backup_lti_stepslib.php
mod/quiz/accessrule/upgrade.txt
mod/quiz/summary.php
mod/scorm/lib.php
mod/wiki/pagelib.php
mod/wiki/parser/utils.php
mod/workshop/lib.php
question/behaviour/upgrade.txt
question/export.php
question/format.php
question/format/blackboard_six/formatbase.php
question/format/blackboard_six/formatpool.php
question/format/blackboard_six/formatqti.php
question/format/blackboard_six/tests/blackboardformatpool_test.php
question/format/blackboard_six/tests/blackboardsixformatqti_test.php
question/format/upgrade.txt
question/format/xml/format.php
question/type/calculated/questiontype.php
question/type/multianswer/renderer.php
report/log/locallib.php
repository/webdav/lib.php
theme/base/style/question.css
theme/magazine/style/core.css
theme/sky_high/style/admin.css
theme/standardold/layout/frontpage.php
version.php
webservice/externallib.php

index e95a47a..e27bed2 100644 (file)
@@ -25,4 +25,8 @@ CVS
 /.project
 /.buildpath
 /.cache
-phpunit.xml
\ No newline at end of file
+phpunit.xml
+# Composer support - only composer.json is to be in git, the rest is installed in each checkout.
+composer.phar
+composer.lock
+/vendor/
index 5afd3ba..5cfd128 100644 (file)
@@ -39,7 +39,6 @@ list($options, $unrecognized) = cli_get_params(
         'buildconfig'           => false,
         'buildcomponentconfigs' => false,
         'diag'                  => false,
-        'phpunitdir'            => false,
         'run'                   => false,
         'help'                  => false,
     ),
@@ -48,24 +47,12 @@ list($options, $unrecognized) = cli_get_params(
     )
 );
 
-if ($options['phpunitdir']) {
-    // nasty skodak's hack for testing of future PHPUnit versions - intentionally not documented
-    if (!file_exists($options['phpunitdir'])) {
-        cli_error('Invalid custom PHPUnit lib location');
-    }
-    $files = scandir($options['phpunitdir']);
-    foreach ($files as $file) {
-        $path = $options['phpunitdir'].'/'.$file;
-        if (!is_dir($path) or strpos($file, '.') === 0) {
-            continue;
-        }
-        ini_set('include_path', $path . PATH_SEPARATOR . ini_get('include_path'));
-    }
-    unset($files);
-    unset($file);
+if (file_exists(__DIR__.'/../../../../vendor/autoload.php')) {
+    // Composer packages present.
+    require_once(__DIR__.'/../../../../vendor/autoload.php');
 }
 
-// verify PHPUnit libs are loaded
+// Verify PHPUnit libs can be loaded.
 if (!include_once('PHPUnit/Autoload.php')) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_PHPUNITMISSING);
 }
@@ -75,7 +62,7 @@ if ($options['run']) {
     unset($unrecognized);
 
     foreach ($_SERVER['argv'] as $k=>$v) {
-        if (strpos($v, '--run') === 0 or strpos($v, '--phpunitdir') === 0) {
+        if (strpos($v, '--run') === 0) {
             unset($_SERVER['argv'][$k]);
             $_SERVER['argc'] = $_SERVER['argc'] - 1;
         }
index 380db45..0d97168 100644 (file)
@@ -900,7 +900,11 @@ if ($formdata = $mform2->is_cancelled()) {
                     $newgroupdata = new stdClass();
                     $newgroupdata->name = $addgroup;
                     $newgroupdata->courseid = $ccache[$shortname]->id;
-                    if ($ccache[$shortname]->groups[$addgroup]->id = groups_create_group($newgroupdata)){
+                    $newgroupdata->description = '';
+                    $gid = groups_create_group($newgroupdata);
+                    if ($gid){
+                        $ccache[$shortname]->groups[$addgroup] = new stdClass();
+                        $ccache[$shortname]->groups[$addgroup]->id   = $gid;
                         $ccache[$shortname]->groups[$addgroup]->name = $newgroupdata->name;
                     } else {
                         $upt->track('enrolments', get_string('unknowngroup', 'error', s($addgroup)), 'error');
index 88bb10d..1a6bac8 100644 (file)
@@ -685,7 +685,7 @@ class auth_plugin_ldap extends auth_plugin_base {
 /// User removal
         // Find users in DB that aren't in ldap -- to be removed!
         // this is still not as scalable (but how often do we mass delete?)
-        if ($this->config->removeuser !== AUTH_REMOVEUSER_KEEP) {
+        if ($this->config->removeuser != AUTH_REMOVEUSER_KEEP) {
             $sql = 'SELECT u.*
                       FROM {user} u
                       LEFT JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = e.mnethostid)
index 103fb3d..3abea43 100644 (file)
@@ -190,6 +190,15 @@ class restore_gradebook_structure_step extends restore_structure_step {
                 $data->id = $newitemid = $existinggradeitem->id;
                 $DB->update_record('grade_items', $data);
             }
+        } else if ($data->itemtype == 'manual') {
+            // Manual items aren't assigned to a cm, so don't go duplicating them in the target if one exists.
+            $gi = array(
+                'itemtype' => $data->itemtype,
+                'courseid' => $data->courseid,
+                'itemname' => $data->itemname,
+                'categoryid' => $data->categoryid,
+            );
+            $newitemid = $DB->get_field('grade_items', 'id', $gi);
         }
 
         if (empty($newitemid)) {
@@ -2904,9 +2913,6 @@ class restore_create_categories_and_questions extends restore_structure_step {
             $data->penalty = 1;
         }
 
-        $data->timecreated  = $this->apply_date_offset($data->timecreated);
-        $data->timemodified = $this->apply_date_offset($data->timemodified);
-
         $userid = $this->get_mappingid('user', $data->createdby);
         $data->createdby = $userid ? $userid : $this->task->get_userid();
 
index e4ab4b1..5c05380 100644 (file)
@@ -75,7 +75,7 @@ class file_logger extends base_logger {
         if (substr($this->fullpath, -5) !== '.html') {
             $content = $prefix . str_repeat('  ', $depth) . $message . PHP_EOL;
         } else {
-            $content = $prefix . str_repeat('&nbsp;&nbsp;', $depth) . htmlentities($message, ENT_QUOTES) . '<br/>' . PHP_EOL;
+            $content = $prefix . str_repeat('&nbsp;&nbsp;', $depth) . htmlentities($message, ENT_QUOTES, 'UTF-8') . '<br/>' . PHP_EOL;
         }
         if (false === fwrite($this->fhandle, $content)) {
             throw new base_logger_exception('error_writing_file', $this->fullpath);
index 8bb6811..2eaea5b 100644 (file)
@@ -38,7 +38,7 @@ class output_indented_logger extends base_logger {
         if (defined('STDOUT')) {
             echo $prefix . str_repeat('  ', $depth) . $message . PHP_EOL;
         } else {
-            echo $prefix . str_repeat('&nbsp;&nbsp;', $depth) . htmlentities($message, ENT_QUOTES) . '<br/>' . PHP_EOL;
+            echo $prefix . str_repeat('&nbsp;&nbsp;', $depth) . htmlentities($message, ENT_QUOTES, 'UTF-8') . '<br/>' . PHP_EOL;
         }
         flush();
         return true;
index fe61536..9d13dfd 100644 (file)
@@ -37,7 +37,7 @@ class output_text_logger extends base_logger {
         if (defined('STDOUT')) {
             echo $prefix . $message . PHP_EOL;
         } else {
-            echo $prefix . htmlentities($message, ENT_QUOTES) . '<br/>' . PHP_EOL;
+            echo $prefix . htmlentities($message, ENT_QUOTES, 'UTF-8') . '<br/>' . PHP_EOL;
         }
         flush();
         return true;
index 35e3f2e..bef1b69 100644 (file)
@@ -69,7 +69,7 @@ class block_community extends block_list {
         }
 
         $icon = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('i/group'),
-                    'class' => 'icon', 'alt' => get_string('addcourse', 'block_community')));
+                    'class' => 'icon', 'alt' => ""));
         $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'),
index 102a167..c06d078 100644 (file)
@@ -137,6 +137,7 @@ class block_glossary_random extends block_base {
             $this->config->cache = '';
             $this->instance_config_commit();
 
+            $this->content = new stdClass();
             $this->content->text   = get_string('notyetconfigured','block_glossary_random');
             $this->content->footer = '';
             return $this->content;
index 2efe9a2..77f8a69 100644 (file)
@@ -151,12 +151,13 @@ class block_online_users extends block_base {
                 $timeago = format_time($now - $user->lastaccess); //bruno to calculate correctly on frontpage
 
                 if (isguestuser($user)) {
-                    $this->content->text .= '<div class="user">'.$OUTPUT->user_picture($user, array('size'=>16));
+                    $this->content->text .= '<div class="user">'.$OUTPUT->user_picture($user, array('size'=>16, 'alttext'=>false));
                     $this->content->text .= get_string('guestuser').'</div>';
 
                 } else {
-                    $this->content->text .= '<div class="user">'.$OUTPUT->user_picture($user, array('size'=>16));
-                    $this->content->text .= '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$this->page->course->id.'" title="'.$timeago.'">'.$user->fullname.'</a></div>';
+                    $this->content->text .= '<div class="user">';
+                    $this->content->text .= '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$this->page->course->id.'" title="'.$timeago.'">';
+                    $this->content->text .= $OUTPUT->user_picture($user, array('size'=>16, 'alttext'=>false, 'link'=>false)) .$user->fullname.'</a></div>';
                 }
                 if ($canshowicon and ($USER->id != $user->id) and !isguestuser($user)) {  // Only when logged in and messaging active etc
                     $anchortagcontents = '<img class="iconsmall" src="'.$OUTPUT->pix_url('t/message') . '" alt="'. get_string('messageselectadd') .'" />';
diff --git a/composer.json b/composer.json
new file mode 100644 (file)
index 0000000..5f618de
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "require-dev": {
+        "phpunit/phpunit": "3.7.*",
+        "phpunit/dbUnit": "1.2.*"
+    }
+}
\ No newline at end of file
index 88fd0fa..1d91b94 100644 (file)
@@ -212,7 +212,7 @@ class core_course_external extends external_api {
                                 array(
                                     'id' => new external_value(PARAM_INT, 'activity id'),
                                     'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
-                                    'name' => new external_value(PARAM_TEXT, 'activity module name'),
+                                    'name' => new external_value(PARAM_RAW, 'activity module name'),
                                     'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
                                     'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
                                     'modicon' => new external_value(PARAM_URL, 'activity icon url'),
index 21fcfcd..b9f93bc 100644 (file)
@@ -583,7 +583,7 @@ function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
             $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
             $ldcache[$log->module][$log->action] = $ld;
         }
-        if ($ld && !empty($log->info)) {
+        if ($ld && is_numeric($log->info)) {
             // ugly hack to make sure fullname is shown correctly
             if (($ld->mtable == 'user') and ($ld->field ==  $DB->sql_concat('firstname', "' '" , 'lastname'))) {
                 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
@@ -600,7 +600,7 @@ function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
         $firstField = format_string($courses[$log->course], true, array('context' => $coursecontext));
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action, $log->info);
-        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);\r
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
         $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action.' ('.$actionurl.')', $log->info);
         $text = implode("\t", $row);
         echo $text." \n";
@@ -684,7 +684,7 @@ function print_log_xls($course, $user, $date, $order='l.time DESC', $modname,
             $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
             $ldcache[$log->module][$log->action] = $ld;
         }
-        if ($ld && !empty($log->info)) {
+        if ($ld && is_numeric($log->info)) {
             // ugly hack to make sure fullname is shown correctly
             if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
                 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
@@ -798,7 +798,7 @@ function print_log_ods($course, $user, $date, $order='l.time DESC', $modname,
             $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
             $ldcache[$log->module][$log->action] = $ld;
         }
-        if ($ld && !empty($log->info)) {
+        if ($ld && is_numeric($log->info)) {
             // ugly hack to make sure fullname is shown correctly
             if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
                 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
@@ -1710,14 +1710,25 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                         } else {
                             $extraclass = '';
                         }
-                        echo "
-<form class='togglecompletion$extraclass' method='post' action='".$CFG->wwwroot."/course/togglecompletion.php'><div>
-<input type='hidden' name='id' value='{$mod->id}' />
-<input type='hidden' name='modulename' value='".s($mod->name)."' />
-<input type='hidden' name='sesskey' value='".sesskey()."' />
-<input type='hidden' name='completionstate' value='$newstate' />
-<input type='image' src='$imgsrc' alt='$imgalt' title='$imgtitle' />
-</div></form>";
+                        echo html_writer::start_tag('form', array(
+                                'class' => 'togglecompletion' . $extraclass,
+                                'method' => 'post',
+                                'action' => $CFG->wwwroot . '/course/togglecompletion.php'));
+                        echo html_writer::start_tag('div');
+                        echo html_writer::empty_tag('input', array(
+                                'type' => 'hidden', 'name' => 'id', 'value' => $mod->id));
+                        echo html_writer::empty_tag('input', array(
+                                'type' => 'hidden', 'name' => 'modulename',
+                                'value' => $mod->name));
+                        echo html_writer::empty_tag('input', array(
+                                'type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
+                        echo html_writer::empty_tag('input', array(
+                                'type' => 'hidden', 'name' => 'completionstate',
+                                'value' => $newstate));
+                        echo html_writer::empty_tag('input', array(
+                                'type' => 'image', 'src' => $imgsrc, 'alt' => $imgalt, 'title' => $imgtitle));
+                        echo html_writer::end_tag('div');
+                        echo html_writer::end_tag('form');
                     } else {
                         // In auto mode, or when editing, the icon is just an image
                         echo "<span class='autocompletion'>";
@@ -1869,7 +1880,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
         // The module chooser link
         $modchooser = html_writer::start_tag('div', array('class' => 'mdl-right'));
         $modchooser.= html_writer::start_tag('div', array('class' => 'section-modchooser'));
-        $icon = $OUTPUT->pix_icon('t/add', $straddeither);
+        $icon = $OUTPUT->pix_icon('t/add', '');
         $span = html_writer::tag('span', $straddeither, array('class' => 'section-modchooser-text'));
         $modchooser .= html_writer::tag('span', $icon . $span, array('class' => 'section-modchooser-link'));
         $modchooser.= html_writer::end_tag('div');
@@ -4542,6 +4553,7 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
         'courseid' => $course->id,
         'pagetype' => $PAGE->pagetype,
         'pagelayout' => $PAGE->pagelayout,
+        'subpage' => $PAGE->subpage,
         'regions' => $PAGE->blocks->get_regions(),
     );
     $PAGE->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
index dc7fa19..5f35a57 100644 (file)
@@ -99,6 +99,9 @@ class recent_form extends moodleform {
 
             $mform->addElement('select', 'user', get_string('participants'), $options);
             $mform->setAdvanced('user');
+        } else {
+            // Default to no user.
+            $mform->addElement('hidden', 'user', 0);
         }
 
         $options = array(''=>get_string('allactivities'));
index 61392ea..a7b55c9 100644 (file)
@@ -150,6 +150,7 @@ switch($requestmethod) {
                         break;
                     case 'updatetitle':
                         require_capability('moodle/course:manageactivities', $modcontext);
+                        require_once($CFG->libdir . '/gradelib.php');
                         $cm = get_coursemodule_from_id('', $id, 0, false, MUST_EXIST);
                         $module = new stdClass();
                         $module->id = $cm->instance;
@@ -167,10 +168,16 @@ switch($requestmethod) {
                             $module->name = $cm->name;
                         }
 
+                        // Attempt to update the grade item if relevant
+                        $grademodule = $DB->get_record($cm->modname, array('id' => $cm->instance));
+                        $grademodule->cmidnumber = $cm->idnumber;
+                        $grademodule->modname = $cm->modname;
+                        grade_update_mod_grades($grademodule);
+
                         // We need to return strings after they've been through filters for multilang
                         $stringoptions = new stdClass;
                         $stringoptions->context = $coursecontext;
-                        echo json_encode(array('instancename' => format_string($module->name, true,  $stringoptions)));
+                        echo json_encode(array('instancename' => html_entity_decode(format_string($module->name, true,  $stringoptions))));
                         break;
                 }
                 rebuild_course_cache($course->id);
index 70ce970..d6a1887 100644 (file)
@@ -3,102 +3,7 @@ ENROLMENT MODULES
 
 (Yes, that's the correct English spelling  ;-) )
 
-enrol.class.php contains a simple 'factory' method that
-will instantiate your class when called. For an example
-of a complete class, take a look at the 'manual' class.
-
-Each plugin is in a subfolder here.
-
-Except for the configuration methods, most methods
-defined in the API are optional -- callers will use
-method_exists() to determine whether your plugin offers
-the functionality they are after.
-
-
-Mandatory methods
-=================
-
-  config_form()
-  process_config()
-
-
-Login-time methods
-==================
-
-  Before Moodle 1.7
-  -----------------
-
-      get_student_courses()
-      get_teacher_courses()
-
-  You probably will want to offer at least get_student_courses().
-
-  These methods are triggered when a user logs in successfully,
-  and they are expected to populate $USER->student and
-  $USER->teacher arrays and maintain (add/delete) entries from
-  user_students and user_teachers.
-
-  These methods are relevant for most plugins, and are the main
-  interest for plugins that work with a read-only backend such
-  as LDAP or a database.
-
-  Note that with the multi-enrol infrastructure two things have
-  changed. We now have an 'enrol' field in those tables, and
-  each plugin must maintain only its own enrolment records.
-  Conversely, the $USER->student and ->teacher arrays have the
-  enrolment type as value, like
-
-     $USER->student = array ( $courseid => $plugintype );
-
-
-  Moodle 1.7 and later
-  --------------------
-
-      setup_enrolments()
-
-  With the advent of roles, there could well not be students and
-  teachers any more, so enrolment plugins have to be more flexible
-  about how they map outside data to the internal roles.
-
-  This one method should do everything, calling functions from
-  lib/accesslib.php as necessary to set up relationships.
-
-
-Interactive enrolment methods
-=============================
-
-  print_entry()
-  check_entry()
-  check_group_entry()
-  get_access_icons()
-
-These methods are for enrolment plugins that allow for user
-driven enrolment. These methods are relevant for plugins
-that implement payment gateways (credit card, paypal),
-as well as "magic password" schemes.
-
-Only one interactive enrolment method can be active for
-a given course. The site default can be set from
-Admin->Enrolment, and then individual courses can be
-set to specific interactive enrolment methods.
-
-
-Cron
-====
-
-If your class offers a cron() method, it will be invoked by
-the standard Moodle cron every time it is called. Note that if the
-tasks are not lightweight you must control how frequently they
-execute, perhaps offering a config option.
-
-For really heavy cron processing, an alternative is to have
-a separate script to be called separately. Currently the LDAP
-and DB plugins have external scripts.
-
-
-Guilty Parties
---------------
-
-Martin Dougiamas and Shane Elliott, Moodle.com
-Martin Langhoff and Patrick Li, Catalyst IT
+All enrolment modules must extend base class enrol_plugin
+which is defined in lib/enrollib.php. You can find documentation
+of each method in the base class.
 
index e5ec7dd..86951db 100644 (file)
@@ -90,13 +90,14 @@ if (! $plugin_instance = $DB->get_record("enrol", array("id"=>$data->instanceid,
 $plugin = enrol_get_plugin('paypal');
 
 /// Open a connection back to PayPal to validate the data
+$paypaladdr = empty($CFG->usepaypalsandbox) ? 'www.paypal.com' : 'www.sandbox.paypal.com';
 $c = new curl();
 $options = array(
     'returntransfer' => true,
-    'httpheader' => array('application/x-www-form-urlencoded'),
+    'httpheader' => array('application/x-www-form-urlencoded', "Host: $paypaladdr"),
     'timeout' => 30,
+    'CURLOPT_HTTP_VERSION' => CURL_HTTP_VERSION_1_1,
 );
-$paypaladdr = empty($CFG->usepaypalsandbox) ? 'www.paypal.com' : 'www.sandbox.paypal.com';
 $location = "https://$paypaladdr/cgi-bin/webscr";
 $result = $c->post($location, $req, $options);
 
@@ -171,7 +172,7 @@ if (strlen($result) > 0) {
 
         }
 
-        if ($data->business != $plugin->get_config('paypalbusiness')) {   // Check that the email is the one we want it to be
+        if (textlib::strtolower($data->business) !== textlib::strtolower($plugin->get_config('paypalbusiness'))) {   // Check that the email is the one we want it to be
             message_paypal_error_to_admin("Business email is {$data->business} (not ".
                     $plugin->get_config('paypalbusiness').")", $data);
             die;
index d9f9d49..f23e91b 100644 (file)
@@ -207,4 +207,23 @@ class enrol_paypal_plugin extends enrol_plugin {
         return $OUTPUT->box(ob_get_clean());
     }
 
+    /**
+     * Gets an array of the user enrolment actions
+     *
+     * @param course_enrolment_manager $manager
+     * @param stdClass $ue A user enrolment object
+     * @return array An array of user_enrolment_actions
+     */
+    public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) {
+        $actions = array();
+        $context = $manager->get_context();
+        $instance = $ue->enrolmentinstance;
+        $params = $manager->get_moodlepage()->url->params();
+        $params['ue'] = $ue->id;
+        if ($this->allow_unenrol($instance) && has_capability("enrol/paypal:unenrol", $context)) {
+            $url = new moodle_url('/enrol/unenroluser.php', $params);
+            $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
+        }
+        return $actions;
+    }
 }
index c562c82..d0df11d 100644 (file)
@@ -214,7 +214,7 @@ border-color:#cecece;
 }
 
 .path-grade-report-grader th {
-padding:2px 10px 0;
+padding:1px 10px;
 }
 
 .path-grade-report-grader span.inclusion-links {
index 2475550..6e6db0b 100644 (file)
@@ -351,17 +351,21 @@ abstract class grade_report {
         global $CFG, $DB;
         static $hiding_affected = null;//array of items in this course affected by hiding
 
-        //if we're dealing with multiple users we need to know when we've moved on to a new user
+        // If we're dealing with multiple users we need to know when we've moved on to a new user.
         static $previous_userid = null;
 
+        // If we're dealing with multiple courses we need to know when we've moved on to a new course.
+        static $previous_courseid = null;
+
         if( $this->showtotalsifcontainhidden==GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN ) {
             return $finalgrade;
         }
 
-        //if we've moved on to another user don't return the previous user's affected grades
-        if ($previous_userid!=$this->user->id) {
+        // If we've moved on to another course or user, reload the grades.
+        if ($previous_userid != $this->user->id || $previous_courseid != $courseid) {
             $hiding_affected = null;
             $previous_userid = $this->user->id;
+            $previous_courseid = $courseid;
         }
 
         if( !$hiding_affected ) {
diff --git a/grade/tests/reportlib_test.php b/grade/tests/reportlib_test.php
new file mode 100644 (file)
index 0000000..48b0eaa
--- /dev/null
@@ -0,0 +1,197 @@
+<?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/>.
+
+/**
+ * Unit tests for grade/report/lib.php.
+ *
+ * @pacakge  core_grade
+ * @category phpunit
+ * @author   Andrew Davis
+ * @license  http://www.gnu.org/copyleft/gpl.html GNU Public License
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot.'/grade/lib.php');
+require_once($CFG->dirroot.'/grade/report/lib.php');
+
+/**
+ * A test class used to test grade_report, the abstract grade report parent class
+ */
+class grade_report_test extends grade_report {
+    public function __construct($courseid, $gpr, $context, $user) {
+        parent::__construct($courseid, $gpr, $context);
+        $this->user = $user;
+    }
+
+    /**
+     * A wrapper around blank_hidden_total() to allow test code to call it directly
+     */
+    public function blank_hidden_total($courseid, $courseitem, $finalgrade) {
+        return parent::blank_hidden_total($courseid, $courseitem, $finalgrade);
+    }
+
+    /**
+     * Implementation of the abstract method process_data()
+     */
+    public function process_data($data) {
+    }
+
+    /**
+     * Implementation of the abstract method process_action()
+     */
+    public function process_action($target, $action) {
+    }
+}
+
+/**
+ * Tests grade_report, the parent class for all grade reports.
+ */
+class gradereportlib_testcase extends advanced_testcase {
+
+    /**
+     * Tests grade_report::blank_hidden_total()
+     */
+    public function test_blank_hidden_total() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        $student = $this->getDataGenerator()->create_user();
+        $this->setUser($student);
+
+        // Create a course and two activities.
+        // One activity will be hidden.
+        $course = $this->getDataGenerator()->create_course();
+        $coursegradeitem = grade_item::fetch_course_item($course->id);
+        $coursecontext = context_course::instance($course->id);
+
+        $data = $this->getDataGenerator()->create_module('data', array('assessed' => 1, 'scale' => 100, 'course' => $course->id));
+        $datacm = get_coursemodule_from_id('data', $data->cmid);
+
+        $forum = $this->getDataGenerator()->create_module('forum', array('assessed' => 1, 'scale' => 100, 'course' => $course->id));
+        $forumcm = get_coursemodule_from_id('forum', $forum->cmid);
+
+        // Insert student grades for the two activities.
+        $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'data', 'iteminstance' => $data->id, 'courseid' => $course->id));
+        $datagrade = 50;
+        $grade_grade = new grade_grade();
+        $grade_grade->itemid = $gi->id;
+        $grade_grade->userid = $student->id;
+        $grade_grade->rawgrade = $datagrade;
+        $grade_grade->finalgrade = $datagrade;
+        $grade_grade->rawgrademax = 100;
+        $grade_grade->rawgrademin = 0;
+        $grade_grade->timecreated = time();
+        $grade_grade->timemodified = time();
+        $grade_grade->insert();
+
+        $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum->id, 'courseid' => $course->id));
+        $forumgrade = 70;
+        $grade_grade = new grade_grade();
+        $grade_grade->itemid = $gi->id;
+        $grade_grade->userid = $student->id;
+        $grade_grade->rawgrade = $forumgrade;
+        $grade_grade->finalgrade = $forumgrade;
+        $grade_grade->rawgrademax = 100;
+        $grade_grade->rawgrademin = 0;
+        $grade_grade->timecreated = time();
+        $grade_grade->timemodified = time();
+        $grade_grade->insert();
+
+        // Hide the database activity.
+        set_coursemodule_visible($datacm->id, 0);
+
+        $gpr = new grade_plugin_return(array('type' => 'report', 'courseid' => $course->id));
+        $report = new grade_report_test($course->id, $gpr, $coursecontext, $student);
+
+        // Should return the supplied student total grade regardless of hiding.
+        $report->showtotalsifcontainhidden = GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN;
+        $this->assertEquals($datagrade + $forumgrade, $report->blank_hidden_total($course->id, $coursegradeitem, $datagrade + $forumgrade));
+
+        // Should blank the student total as course grade depends on a hidden item.
+        $report->showtotalsifcontainhidden = GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN;
+        $this->assertEquals(null, $report->blank_hidden_total($course->id, $coursegradeitem, $datagrade + $forumgrade));
+
+        // Should return the course total minus the hidden database activity grade.
+        $report->showtotalsifcontainhidden = GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN;
+        $this->assertEquals($forumgrade, $report->blank_hidden_total($course->id, $coursegradeitem, $datagrade + $forumgrade));
+
+        // Note: we cannot simply hide modules and call $report->blank_hidden_total() again.
+        // It stores grades in a static variable so $report->blank_hidden_total() will return incorrect totals
+        // In practice this isn't a problem. Grade visibility isn't altered mid-request outside of the unit tests.
+
+        // Add a second course to test:
+        // 1) How a course with no visible activities behaves.
+        // 2) That $report->blank_hidden_total() correctly moves on to the new course.
+        $course = $this->getDataGenerator()->create_course();
+        $coursegradeitem = grade_item::fetch_course_item($course->id);
+        $coursecontext = context_course::instance($course->id);
+
+        $data = $this->getDataGenerator()->create_module('data', array('assessed' => 1, 'scale' => 100, 'course' => $course->id));
+        $datacm = get_coursemodule_from_id('data', $data->cmid);
+
+        $forum = $this->getDataGenerator()->create_module('forum', array('assessed' => 1, 'scale' => 100, 'course' => $course->id));
+        $forumcm = get_coursemodule_from_id('forum', $forum->cmid);
+
+        $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'data', 'iteminstance' => $data->id, 'courseid' => $course->id));
+        $datagrade = 50;
+        $grade_grade = new grade_grade();
+        $grade_grade->itemid = $gi->id;
+        $grade_grade->userid = $student->id;
+        $grade_grade->rawgrade = $datagrade;
+        $grade_grade->finalgrade = $datagrade;
+        $grade_grade->rawgrademax = 100;
+        $grade_grade->rawgrademin = 0;
+        $grade_grade->timecreated = time();
+        $grade_grade->timemodified = time();
+        $grade_grade->insert();
+
+        $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum->id, 'courseid' => $course->id));
+        $forumgrade = 70;
+        $grade_grade = new grade_grade();
+        $grade_grade->itemid = $gi->id;
+        $grade_grade->userid = $student->id;
+        $grade_grade->rawgrade = $forumgrade;
+        $grade_grade->finalgrade = $forumgrade;
+        $grade_grade->rawgrademax = 100;
+        $grade_grade->rawgrademin = 0;
+        $grade_grade->timecreated = time();
+        $grade_grade->timemodified = time();
+        $grade_grade->insert();
+
+        // Hide both activities.
+        set_coursemodule_visible($datacm->id, 0);
+        set_coursemodule_visible($forumcm->id, 0);
+
+        $gpr = new grade_plugin_return(array('type' => 'report', 'courseid' => $course->id));
+        $report = new grade_report_test($course->id, $gpr, $coursecontext, $student);
+
+        // Should return the supplied student total grade regardless of hiding.
+        $report->showtotalsifcontainhidden = GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN;
+        $this->assertEquals($datagrade + $forumgrade, $report->blank_hidden_total($course->id, $coursegradeitem, $datagrade + $forumgrade));
+
+        // Should blank the student total as course grade depends on a hidden item.
+        $report->showtotalsifcontainhidden = GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN;
+        $this->assertEquals(null, $report->blank_hidden_total($course->id, $coursegradeitem, $datagrade + $forumgrade));
+
+        // Should return the course total minus the hidden activity grades.
+        // They are both hidden so should return null.
+        $report->showtotalsifcontainhidden = GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN;
+        $this->assertEquals(null, $report->blank_hidden_total($course->id, $coursegradeitem, $datagrade + $forumgrade));
+    }
+}
diff --git a/install/lang/ga/moodle.php b/install/lang/ga/moodle.php
new file mode 100644 (file)
index 0000000..3e5ec38
--- /dev/null
@@ -0,0 +1,35 @@
+<?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['language'] = 'Teanga';
+$string['next'] = 'Ar aghaidh';
+$string['previous'] = 'Siar';
index 50a9ee4..48f24df 100644 (file)
@@ -2937,8 +2937,13 @@ function get_user_roles_in_course($userid, $courseid) {
 function user_can_assign(context $context, $targetroleid) {
     global $DB;
 
-    // first check if user has override capability
-    // if not return false;
+    // First check to see if the user is a site administrator.
+    if (is_siteadmin()) {
+        return true;
+    }
+
+    // Check if user has override capability.
+    // If not return false.
     if (!has_capability('moodle/role:assign', $context)) {
         return false;
     }
index 041190a..470106d 100644 (file)
@@ -30,6 +30,7 @@ require_once(dirname(__FILE__) . '/../../config.php');
 $courseid = required_param('courseid', PARAM_INT);
 $pagelayout = required_param('pagelayout', PARAM_ALPHAEXT);
 $pagetype = required_param('pagetype', PARAM_ALPHAEXT);
+$subpage = optional_param('subpage', '', PARAM_ALPHANUMEXT);
 $cmid = optional_param('cmid', null, PARAM_INT);
 $action = optional_param('action', '', PARAM_ALPHA);
 // Params for blocks-move actions
@@ -51,6 +52,7 @@ require_sesskey();
 
 // Setting layout to replicate blocks configuration for the page we edit
 $PAGE->set_pagelayout($pagelayout);
+$PAGE->set_subpage($subpage);
 echo $OUTPUT->header(); // send headers
 
 switch ($action) {
index dde0f20..d17e3e1 100644 (file)
@@ -1694,7 +1694,7 @@ function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user
     $timenow = time();
     $info = $info;
     if (!empty($url)) { // could break doing html_entity_decode on an empty var.
-        $url = html_entity_decode($url);
+        $url = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
     } else {
         $url = '';
     }
index e096c87..8deccf9 100644 (file)
@@ -172,7 +172,7 @@ class oracle_sql_generator extends sql_generator {
     public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
 
         switch ($xmldb_type) {
-            case XMLDB_TYPE_INTEGER:    // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
+            case XMLDB_TYPE_INTEGER:    // See http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/sql_elements001.htm#sthref86.
                 if (empty($xmldb_length)) {
                     $xmldb_length = 10;
                 }
index 4aae9ce..61b161c 100644 (file)
@@ -172,7 +172,7 @@ abstract class pdo_moodle_database extends moodle_database {
      * Function to print/save/ignore debugging messages related to SQL queries.
      */
     protected function debug_query($sql, $params = null) {
-        echo '<hr /> (', $this->get_dbtype(), '): ',  htmlentities($sql);
+        echo '<hr /> (', $this->get_dbtype(), '): ',  htmlentities($sql, ENT_QUOTES, 'UTF-8');
         if($params) {
             echo ' (parameters ';
             print_r($params);
index e056b53..39481ad 100644 (file)
@@ -3813,7 +3813,7 @@ class dml_testcase extends database_driver_testcase {
         $this->assertEquals("Firstname Surname", $DB->get_field_sql($sql, $params));
     }
 
-    function sql_sql_order_by_text() {
+    function test_sql_order_by_text() {
         $DB = $this->tdb;
         $dbman = $DB->get_manager();
 
index 2209291..0b72fa9 100644 (file)
@@ -687,6 +687,7 @@ $string['table_dlg:bordercolor'] = 'Border color';
 $string['table_dlg:caption'] = 'Table caption';
 $string['table_dlg:cell_all'] = 'Update all cells in table';
 $string['table_dlg:cell_cell'] = 'Update current cell';
+$string['table_dlg:cell_col'] = 'Update all cells in column';
 $string['table_dlg:cell_limit'] = 'You\'ve exceeded the maximum number of cells of {$cells}.';
 $string['table_dlg:cell_row'] = 'Update all cells in row';
 $string['table_dlg:cell_title'] = 'Table cell properties';
index 44315ca..69205d9 100644 (file)
@@ -74,8 +74,8 @@ class MoodleExcelWorkbook {
      * @param string $name Name of the sheet
      * @return object MoodleExcelWorksheet
      */
-    function &add_worksheet($name = '') {
-    /// Create the Moodle Worksheet. Returns one pointer to it
+    function add_worksheet($name = '') {
+        // Create the Moodle Worksheet. Returns one pointer to it
         $ws = new MoodleExcelWorksheet ($name, $this->pear_excel_workbook, $this->latin_output);
         return $ws;
     }
@@ -138,6 +138,9 @@ class MoodleExcelWorksheet {
      */
     function MoodleExcelWorksheet($name, &$workbook, $latin_output=false) {
 
+        // Replace any characters in the name that Excel cannot cope with.
+        $name = strtr($name, '[]*/\?:', '       ');
+
         if (strlen($name) > 31) {
             // Excel does not seem able to cope with sheet names > 31 chars.
             // With $latin_output = false, it does not cope at all.
index fd3c612..ce5c160 100644 (file)
@@ -2250,7 +2250,7 @@ function send_file($path, $filename, $lifetime = 'default' , $filter=0, $pathiss
             $options = new stdClass();
             $options->newlines = false;
             $options->noclean = true;
-            $text = htmlentities($pathisstring ? $path : implode('', file($path)));
+            $text = htmlentities($pathisstring ? $path : implode('', file($path)), ENT_QUOTES, 'UTF-8');
             $output = '<pre>'. format_text($text, FORMAT_MOODLE, $options, $COURSE->id) .'</pre>';
 
             readstring_accel($output, $mimetype, false);
index dfc4fa0..049acfe 100644 (file)
@@ -67,6 +67,10 @@ class filestoragelib_testcase extends advanced_testcase {
     public function test_get_file_preview(stored_file $file) {
         global $CFG;
 
+        if (empty($CFG->gdversion)) {
+            $this->markTestSkipped('GD extension is disabled');
+        }
+
         $this->resetAfterTest(true);
         $fs = get_file_storage();
 
index f5ba088..83b06c9 100644 (file)
@@ -1964,7 +1964,7 @@ function qf_errorHandler(element, _qfMsg) {
             list($jsArr,$element)=$jsandelement;
             //end of fix
             $escapedElementName = preg_replace_callback(
-                '/[_\[\]]/',
+                '/[_\[\]-]/',
                 create_function('$matches', 'return sprintf("_%2x",ord($matches[0]));'),
                 $elementName);
             $js .= '
index 3fa19ec..6f3deff 100644 (file)
@@ -886,7 +886,9 @@ class grade_category extends grade_object {
                 $droppedsomething = false;
 
                 $grade_keys = array_keys($grade_values);
-                if (count($grade_keys) === 0) {
+                $gradekeycount = count($grade_keys);
+
+                if ($gradekeycount === 0) {
                     //We've dropped all grade items
                     break;
                 }
@@ -910,7 +912,7 @@ class grade_category extends grade_object {
                 }
 
                 $i = 1;
-                while ($originalindex+$i < count($grade_keys)) {
+                while ($originalindex + $i < $gradekeycount) {
 
                     $possibleitemid = $grade_keys[$originalindex+$i];
                     $i++;
index 32697fa..bf3bdc1 100644 (file)
@@ -1128,7 +1128,7 @@ function clean_param($param, $type) {
 
         case PARAM_TIMEZONE:    //can be int, float(with .5 or .0) or string seperated by '/' and can have '-_'
             $param = fix_utf8($param);
-            $timezonepattern = '/^(([+-]?(0?[0-9](\.[5|0])?|1[0-3]|1[0-2]\.5))|(99)|[[:alnum:]]+(\/?[[:alpha:]_-])+)$/';
+            $timezonepattern = '/^(([+-]?(0?[0-9](\.[5|0])?|1[0-3](\.0)?|1[0-2]\.5))|(99)|[[:alnum:]]+(\/?[[:alpha:]_-])+)$/';
             if (preg_match($timezonepattern, $param)) {
                 return $param;
             } else {
index b95aae6..f092010 100644 (file)
@@ -3515,9 +3515,9 @@ class settings_navigation extends navigation_node {
                         continue;
                     }
                     if ($type->modclass == MOD_CLASS_RESOURCE) {
-                        $resources[html_entity_decode($type->type)] = $type->typestr;
+                        $resources[html_entity_decode($type->type, ENT_QUOTES, 'UTF-8')] = $type->typestr;
                     } else {
-                        $activities[html_entity_decode($type->type)] = $type->typestr;
+                        $activities[html_entity_decode($type->type, ENT_QUOTES, 'UTF-8')] = $type->typestr;
                     }
                 }
             } else {
@@ -4194,7 +4194,7 @@ class settings_navigation extends navigation_node {
 
         // Messaging
         if (($currentuser && has_capability('moodle/user:editownmessageprofile', $systemcontext)) || (!isguestuser($user) && has_capability('moodle/user:editmessageprofile', $usercontext) && !is_primary_admin($user->id))) {
-            $url = new moodle_url('/message/edit.php', array('id'=>$user->id, 'course'=>$course->id));
+            $url = new moodle_url('/message/edit.php', array('id'=>$user->id));
             $usersetting->add(get_string('editmymessage', 'message'), $url, self::TYPE_SETTING);
         }
 
@@ -4491,7 +4491,7 @@ class navigation_json {
         }
 
         if ($child->forcetitle || $child->title !== $child->text) {
-            $attributes['title'] = htmlentities($child->title);
+            $attributes['title'] = htmlentities($child->title, ENT_QUOTES, 'UTF-8');
         }
         if (array_key_exists($child->key.':'.$child->type, $this->expandable)) {
             $attributes['expandable'] = $child->key;
index 33ec793..4f68206 100644 (file)
@@ -88,10 +88,28 @@ class Hint_ResultPrinter extends PHPUnit_TextUI_ResultPrinter {
             $file = substr($file, strlen($cwd)+1);
         }
 
-        $executable = 'phpunit';
-        if (phpunit_bootstrap_is_cygwin()) {
-            $file = str_replace('\\', '/', $file);
-            $executable = 'phpunit.bat';
+        $executable = null;
+
+        if (isset($_SERVER['argv'][0])) {
+            if (preg_match('/phpunit(\.bat|\.cmd)?$/', $_SERVER['argv'][0])) {
+                $executable = $_SERVER['argv'][0];
+                for($i=1;$i<count($_SERVER['argv']);$i++) {
+                    if (!isset($_SERVER['argv'][$i])) {
+                        break;
+                    }
+                    if (in_array($_SERVER['argv'][$i], array('--colors', '--verbose', '-v', '--debug', '--strict'))) {
+                        $executable .= ' '.$_SERVER['argv'][$i];
+                    }
+                }
+            }
+        }
+
+        if (!$executable) {
+            $executable = 'phpunit';
+            if (phpunit_bootstrap_is_cygwin()) {
+                $file = str_replace('\\', '/', $file);
+                $executable = 'phpunit.bat';
+            }
         }
 
         $this->write("\nTo re-run:\n $executable $testName $file\n");
index 5af9c06..0bf70c4 100644 (file)
@@ -5,22 +5,35 @@ PHPUnit testing support in Moodle
 Documentation
 -------------
 * [Moodle Dev wiki](http://docs.moodle.org/dev/PHPUnit)
-* [PHPUnit online documentaion](http://www.phpunit.de/manual/current/en/)
+* [PHPUnit online documentation](http://www.phpunit.de/manual/current/en/)
+* [Composer dependency manager](http://getcomposer.org/)
 
 
-Installation
-------------
+Composer installation
+---------------------
+Composer is a new dependency manager for PHP projects.
+It installs PHP libraries into /vendor/ subdirectory inside your moodle dirroot.
+
+1. install Composer - http://getcomposer.org/doc/00-intro.md
+2. go to your moodle dirroot and execute `php composer.phar install --dev`
+
+
+PEAR installation (not recommended)
+-----------------------------------
+PEAR is a framework and distribution system for reusable PHP components.
+The packages installed via PEAR are available in all PHP projects.
+
 1. install PEAR package manager - see [PEAR Manual](http://pear.php.net/manual/en/installation.php)
 2. install PHPUnit package and phpunit/DbUnit extension - see [PHPUnit installation documentation](http://www.phpunit.de/manual/current/en/installation.html)
 3. edit main config.php - add `$CFG->phpunit_prefix` and `$CFG->phpunit_dataroot` - see config-dist.php
-4. execute `php admin/tool/phpunit/cli/init.php` to initialise the test environemnt, repeat it after every upgrade or installation of plugins
+4. execute `php admin/tool/phpunit/cli/init.php` to initialise the test environment, repeat it after every upgrade or installation of plugins
 
 
 Test execution
 --------------
-* execute `phpunit` from dirroot directory
-* you can execute a single test case class using class name followed by path to test file `phpunit core_phpunit_basic_testcase lib/tests/phpunit_test.php`
-* it is also possible to create custom configuration files in xml format and use `phpunit -c mytestsuites.xml`
+* execute `vendor/bin/phpunit` (or `phpunit` if you use PEAR) from dirroot directory
+* you can execute a single test case class using class name followed by path to test file `vendor/bin/phpunit core_phpunit_basic_testcase lib/tests/phpunit_test.php`
+* it is also possible to create custom configuration files in xml format and use `vendor/bin/phpunit -c mytestsuites.xml`
 
 
 How to add more tests?
index 5d78cf7..1bc425a 100644 (file)
@@ -1191,19 +1191,28 @@ class available_update_checker {
                 foreach ($componentupdates as $componentupdate) {
                     if ($componentupdate->version == $componentchange['version']) {
                         if ($component == 'core') {
-                            // in case of 'core' this is enough, we already know that the
-                            // $componentupdate is a real update with higher version
-                            $notifications[] = $componentupdate;
+                            // In case of 'core', we already know that the $componentupdate
+                            // is a real update with higher version ({@see self::get_update_info()}).
+                            // We just perform additional check for the release property as there
+                            // can be two Moodle releases having the same version (e.g. 2.4.0 and 2.5dev shortly
+                            // after the release). We can do that because we have the release info
+                            // always available for the core.
+                            if ((string)$componentupdate->release === (string)$componentchange['release']) {
+                                $notifications[] = $componentupdate;
+                            }
                         } else {
-                            // use the plugin_manager to check if the reported $componentchange
-                            // is a real update with higher version. such a real update must be
-                            // present in the 'availableupdates' property of one of the component's
-                            // available_update_info object
+                            // Use the plugin_manager to check if the detected $componentchange
+                            // is a real update with higher version. That is, the $componentchange
+                            // is present in the array of {@link available_update_info} objects
+                            // returned by the plugin's available_updates() method.
                             list($plugintype, $pluginname) = normalize_component($component);
-                            if (!empty($plugins[$plugintype][$pluginname]->availableupdates)) {
-                                foreach ($plugins[$plugintype][$pluginname]->availableupdates as $availableupdate) {
-                                    if ($availableupdate->version == $componentchange['version']) {
-                                        $notifications[] = $componentupdate;
+                            if (!empty($plugins[$plugintype][$pluginname])) {
+                                $availableupdates = $plugins[$plugintype][$pluginname]->available_updates();
+                                if (!empty($availableupdates)) {
+                                    foreach ($availableupdates as $availableupdate) {
+                                        if ($availableupdate->version == $componentchange['version']) {
+                                            $notifications[] = $componentupdate;
+                                        }
                                     }
                                 }
                             }
index be15e14..b40927d 100644 (file)
@@ -1069,6 +1069,10 @@ function get_moodle_cookie() {
 function session_set_user($user) {
     $_SESSION['USER'] = $user;
     unset($_SESSION['USER']->description); // conserve memory
+    if (isset($_SESSION['USER']->lang)) {
+        // Make sure it is a valid lang pack name.
+        $_SESSION['USER']->lang = clean_param($_SESSION['USER']->lang, PARAM_LANG);
+    }
     sesskey(); // init session key
 
     if (PHPUNIT_TEST) {
index 2a08616..63e607e 100644 (file)
@@ -60,6 +60,7 @@ class flexible_table {
     var $column_class    = array();
     var $column_suppress = array();
     var $column_nosort   = array('userpic');
+    private $column_textsort = array();
     var $setup           = false;
     var $sess            = NULL;
     var $baseurl         = NULL;
@@ -214,6 +215,14 @@ class flexible_table {
         $this->sort_default_order  = $defaultorder;
     }
 
+    /**
+     * Use text sorting functions for this column (required for text columns with Oracle).
+     * @param string column name
+     */
+    function text_sorting($column) {
+        $this->column_textsort[] = $column;
+    }
+
     /**
      * Do not sort using this column
      * @param string column name
@@ -513,10 +522,14 @@ class flexible_table {
      * @param array $cols column name => SORT_ASC or SORT_DESC
      * @return SQL fragment that can be used in an ORDER BY clause.
      */
-    public static function construct_order_by($cols) {
+    public static function construct_order_by($cols, $textsortcols=array()) {
+        global $DB;
         $bits = array();
 
         foreach ($cols as $column => $order) {
+            if (in_array($column, $textsortcols)) {
+                $column = $DB->sql_order_by_text($column);
+            }
             if ($order == SORT_ASC) {
                 $bits[] = $column . ' ASC';
             } else {
@@ -531,7 +544,7 @@ class flexible_table {
      * @return SQL fragment that can be used in an ORDER BY clause.
      */
     public function get_sql_sort() {
-        return self::construct_order_by($this->get_sort_columns());
+        return self::construct_order_by($this->get_sort_columns(), $this->column_textsort);
     }
 
     /**
@@ -1487,7 +1500,7 @@ class table_spreadsheet_export_format_parent extends table_default_export_format
     }
 
     function start_table($sheettitle) {
-        $this->worksheet =& $this->workbook->add_worksheet($sheettitle);
+        $this->worksheet = $this->workbook->add_worksheet($sheettitle);
         $this->rownum=0;
     }
 
index c26bab7..f5045c3 100644 (file)
@@ -979,9 +979,23 @@ class moodlelib_testcase extends advanced_testcase {
             '0'                              => '0',
             '0.0'                            => '0.0',
             '0.5'                            => '0.5',
+            '9.0'                            => '9.0',
+            '-9.0'                           => '-9.0',
+            '+9.0'                           => '+9.0',
+            '9.5'                            => '9.5',
+            '-9.5'                           => '-9.5',
+            '+9.5'                           => '+9.5',
+            '12.0'                           => '12.0',
+            '-12.0'                          => '-12.0',
+            '+12.0'                          => '+12.0',
+            '12.5'                           => '12.5',
             '-12.5'                          => '-12.5',
             '+12.5'                          => '+12.5',
+            '13.0'                           => '13.0',
+            '-13.0'                          => '-13.0',
+            '+13.0'                          => '+13.0',
             '13.5'                           => '',
+            '+13.5'                          => '',
             '-13.5'                          => '',
             '0.2'                            => '');
 
index 04814d0..0594466 100644 (file)
@@ -187,7 +187,10 @@ class moodle_page_test extends advanced_testcase {
     }
 
     public function test_pagetype_defaults_to_script() {
+        global $SCRIPT;
         // Exercise SUT and validate
+        $SCRIPT = '/index.php';
+        $this->testpage->initialise_default_pagetype();
         $this->assertEquals('site-index', $this->testpage->pagetype);
     }
 
index d36095e..c1d1d31 100644 (file)
@@ -265,15 +265,17 @@ class webdav_client {
      * Public method get
      *
      * Gets a file from a webdav collection.
-     * @param string path, string &buffer
-     * @return status code and &$buffer (by reference) with response data from server on success. False on error.
+     * @param string $path the path to the file on the webdav server
+     * @param string &$buffer the buffer to store the data in
+     * @param resource $fp optional if included, the data is written directly to this resource and not to the buffer
+     * @return string|bool status code and &$buffer (by reference) with response data from server on success. False on error.
      */
-    function get($path, &$buffer) {
+    function get($path, &$buffer, $fp = null) {
         $this->_path = $this->translate_uri($path);
         $this->header_unset();
         $this->create_basic_request('GET');
         $this->send_request();
-        $this->get_respond();
+        $this->get_respond($fp);
         $response = $this->process_respond();
 
         $http_version = $response['status']['http-version'];
@@ -283,8 +285,13 @@ class webdav_client {
                 // seems to be http ... proceed
                 // We expect a 200 code
                 if ($response['status']['status-code'] == 200 ) {
-                    $this->_error_log('returning buffer with ' . strlen($response['body']) . ' bytes.');
-                    $buffer = $response['body'];
+                    if (!is_null($fp)) {
+                        $stat = fstat($fp);
+                        $this->_error_log('file created with ' . $stat['size'] . ' bytes.');
+                    } else {
+                        $this->_error_log('returning buffer with ' . strlen($response['body']) . ' bytes.');
+                        $buffer = $response['body'];
+                    }
                 }
                 return $response['status']['status-code'];
             }
@@ -387,27 +394,24 @@ class webdav_client {
      * Gets a file from a collection into local filesystem.
      *
      * fopen() is used.
-     * @param string srcpath, string localpath
-     * @return true on success. false on error.
+     * @param string $srcpath
+     * @param string $localpath
+     * @return bool true on success. false on error.
      */
     function get_file($srcpath, $localpath) {
 
-        if ($this->get($srcpath, $buffer)) {
-            // convert utf-8 filename to iso-8859-1
+        $localpath = $this->utf_decode_path($localpath);
 
-            $localpath = $this->utf_decode_path($localpath);
-
-            $handle = fopen ($localpath, 'w');
-            if ($handle) {
-                fwrite($handle, $buffer);
-                fclose($handle);
+        $handle = fopen($localpath, 'wb');
+        if ($handle) {
+            $unused = '';
+            $ret = $this->get($srcpath, $unused, $handle);
+            fclose($handle);
+            if ($ret) {
                 return true;
-            } else {
-                return false;
             }
-        } else {
-            return false;
         }
+        return false;
     }
 
     /**
@@ -1447,8 +1451,9 @@ EOD;
      * This routine is the weakest part of this class, because it very depends how php does handle a socket stream.
      * If the stream is blocked for some reason php is blocked as well.
      * @access private
+     * @param resource $fp optional the file handle to write the body content to (stored internally in the '_body' if not set)
      */
-    private function get_respond() {
+    private function get_respond($fp = null) {
         $this->_error_log('get_respond()');
         // init vars (good coding style ;-)
         $buffer = '';
@@ -1509,7 +1514,8 @@ EOD;
                     $read = 0;
                     // Reading the chunk in one bite is not secure, we read it byte by byte.
                     while ($read < $chunk_size) {
-                        $buffer .= fread($this->sock, 1);
+                        $chunk = fread($this->sock, 1);
+                        self::update_file_or_buffer($chunk, $fp, $buffer);
                         $read++;
                     }
                 }
@@ -1525,21 +1531,20 @@ EOD;
             if ($matches[1] <= $max_chunk_size ) {
                 // only read something if Content-Length is bigger than 0
                 if ($matches[1] > 0 ) {
-                    $buffer = fread($this->sock, $matches[1]);
-                    $loadsize = strlen($buffer);
+                    $chunk = fread($this->sock, $matches[1]);
+                    $loadsize = strlen($chunk);
                     //did we realy get the full length?
                     if ($loadsize < $matches[1]) {
                         $max_chunk_size = $loadsize;
                         do {
-                            $mod = $max_chunk_size % ($matches[1] - strlen($buffer));
-                            $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - strlen($buffer));
-                            $buffer .= fread($this->sock, $chunk_size);
-                            $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . strlen($buffer));
+                            $mod = $max_chunk_size % ($matches[1] - strlen($chunk));
+                            $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - strlen($chunk));
+                            $chunk .= fread($this->sock, $chunk_size);
+                            $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . strlen($chunk));
                         } while ($mod == $max_chunk_size);
-                        break;
-                    } else {
-                        break;
                     }
+                    self::update_file_or_buffer($chunk, $fp, $buffer);
+                    break;
                 } else {
                     $buffer = '';
                     break;
@@ -1548,20 +1553,23 @@ EOD;
 
             // data is to big to handle it as one. Get it chunk per chunk...
             //trying to get the full length of max_chunk_size
-            $buffer = fread($this->sock, $max_chunk_size);
-            $loadsize = strlen($buffer);
+            $chunk = fread($this->sock, $max_chunk_size);
+            $loadsize = strlen($chunk);
+            self::update_file_or_buffer($chunk, $fp, $buffer);
             if ($loadsize < $max_chunk_size) {
                 $max_chunk_size = $loadsize;
             }
             do {
-                $mod = $max_chunk_size % ($matches[1] - strlen($buffer));
-                $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - strlen($buffer));
-                $buffer .= fread($this->sock, $chunk_size);
-                $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . strlen($buffer));
+                $mod = $max_chunk_size % ($matches[1] - $loadsize);
+                $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - $loadsize);
+                $chunk = fread($this->sock, $chunk_size);
+                self::update_file_or_buffer($chunk, $fp, $buffer);
+                $loadsize += strlen($chunk);
+                $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . $loadsize);
             } while ($mod == $max_chunk_size);
-            $loadsize = strlen($buffer);
             if ($loadsize < $matches[1]) {
-                $buffer .= fread($this->sock, $matches[1] - $loadsize);
+                $chunk = fread($this->sock, $matches[1] - $loadsize);
+                self::update_file_or_buffer($chunk, $fp, $buffer);
             }
             break;
 
@@ -1577,7 +1585,8 @@ EOD;
             $this->_error_log('reading until feof...' . $header);
             socket_set_timeout($this->sock, 0, 0);
             while (!feof($this->sock)) {
-                $buffer .= fread($this->sock, 4096);
+                $chunk = fread($this->sock, 4096);
+                self::update_file_or_buffer($chunk, $fp, $buffer);
             }
             // renew the socket timeout...does it do something ???? Is it needed. More debugging needed...
             socket_set_timeout($this->sock, $this->_socket_timeout, 0);
@@ -1591,6 +1600,19 @@ EOD;
 
     }
 
+    /**
+     * Write the chunk to the file if $fp is set, otherwise append the data to the buffer
+     * @param string $chunk the data to add
+     * @param resource $fp the file handle to write to (or null)
+     * @param string &$buffer the buffer to append to (if $fp is null)
+     */
+    static private function update_file_or_buffer($chunk, $fp, &$buffer) {
+        if ($fp) {
+            fwrite($fp, $chunk);
+        } else {
+            $buffer .= $chunk;
+        }
+    }
 
     /**
      * Private method process_respond
index 2147502..99c4b48 100644 (file)
@@ -99,7 +99,13 @@ YUI.add('moodle-core-blocks', function(Y) {
         },
 
         get_block_region : function(node) {
-            return node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region/i, 'side');
+            var region = node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region-/i, '');
+            if (Y.Array.indexOf(this.get('regions'), region) === -1) {
+                // Must be standard side-X
+                return 'side-' + region;
+            }
+            // Perhaps custom region
+            return region;
         },
 
         get_region_id : function(node) {
@@ -207,6 +213,7 @@ YUI.add('moodle-core-blocks', function(Y) {
                 courseid : this.get('courseid'),
                 pagelayout : this.get('pagelayout'),
                 pagetype : this.get('pagetype'),
+                subpage : this.get('subpage'),
                 action : 'move',
                 bui_moveid : this.get_block_id(dragnode),
                 bui_newregion : this.get_block_region(dropnode)
@@ -262,6 +269,9 @@ YUI.add('moodle-core-blocks', function(Y) {
             pagetype : {
                 value : null
             },
+            subpage : {
+                value : null
+            },
             regions : {
                 value : null
             }
index be963fe..84fc654 100644 (file)
@@ -26,30 +26,14 @@ require_once(dirname(__FILE__) . '/../config.php');
 require_once($CFG->dirroot . '/message/lib.php');
 
 $userid = optional_param('id', $USER->id, PARAM_INT);    // user id
-$course = optional_param('course', SITEID, PARAM_INT);   // course id (defaults to Site)
 $disableall = optional_param('disableall', 0, PARAM_BOOL); //disable all of this user's notifications
 
 $url = new moodle_url('/message/edit.php');
 $url->param('id', $userid);
-$url->param('course', $course);
 
 $PAGE->set_url($url);
 
-if (!$course = $DB->get_record('course', array('id' => $course))) {
-    print_error('invalidcourseid');
-}
-
-if ($course->id != SITEID) {
-    require_login($course);
-
-} else {
-    if (!isloggedin()) {
-        if (empty($SESSION->wantsurl)) {
-            $SESSION->wantsurl = $CFG->httpswwwroot.'/message/edit.php';
-        }
-        redirect(get_login_url());
-    }
-}
+require_login();
 
 if (isguestuser()) {
     print_error('guestnoeditmessage', 'message');
@@ -71,10 +55,6 @@ $PAGE->requires->js_init_call('M.core_message.init_editsettings');
 if ($user->id == $USER->id) {
     //editing own message profile
     require_capability('moodle/user:editownmessageprofile', $systemcontext);
-    if ($course->id != SITEID && $node = $PAGE->navigation->find($course->id, navigation_node::TYPE_COURSE)) {
-        $node->make_active();
-        $PAGE->navbar->includesettingsbase = true;
-    }
 } else {
     // teachers, parents, etc.
     require_capability('moodle/user:editmessageprofile', $personalcontext);
@@ -144,7 +124,7 @@ if (($form = data_submitted()) && confirm_sesskey()) {
         print_error('cannotupdateusermsgpref');
     }
 
-    redirect("$CFG->wwwroot/message/edit.php?id=$user->id&course=$course->id");
+    redirect("$CFG->wwwroot/message/edit.php?id=$user->id");
 }
 
 /// Load preferences
@@ -179,14 +159,8 @@ $preferences->blocknoncontacts  =  get_user_preferences( 'message_blocknoncontac
 
 /// Display page header
 $streditmymessage = get_string('editmymessage', 'message');
-$strparticipants  = get_string('participants');
-
-$PAGE->set_title("$course->shortname: $streditmymessage");
-if ($course->id != SITEID) {
-    $PAGE->set_heading("$course->fullname: $streditmymessage");
-} else {
-    $PAGE->set_heading($course->fullname);
-}
+$PAGE->set_title($streditmymessage);
+$PAGE->set_heading($streditmymessage);
 
 // Grab the renderer
 $renderer = $PAGE->get_renderer('core', 'message');
index cac237b..1fc1cd3 100644 (file)
@@ -77,17 +77,6 @@ define('MESSAGE_PERMITTED_MASK', 0x0c); // 1100
  */
 define('MESSAGE_DEFAULT_PERMITTED', 'permitted');
 
-//TODO: defaults must be initialised via settings - this is a bad hack! (skodak)
-if (!isset($CFG->message_contacts_refresh)) {  // Refresh the contacts list every 60 seconds
-    $CFG->message_contacts_refresh = 60;
-}
-if (!isset($CFG->message_chat_refresh)) {      // Look for new comments every 5 seconds
-    $CFG->message_chat_refresh = 5;
-}
-if (!isset($CFG->message_offline_time)) {
-    $CFG->message_offline_time = 300;
-}
-
 /**
  * Print the selector that allows the user to view their contacts, course participants, their recent
  * conversations etc
@@ -185,7 +174,18 @@ function message_print_participants($context, $courseid, $contactselecturl=null,
     }
 
     $countparticipants = count_enrolled_users($context);
-    $participants = get_enrolled_users($context, '', 0, 'u.*', '', $page*MESSAGE_CONTACTS_PER_PAGE, MESSAGE_CONTACTS_PER_PAGE);
+
+    list($esql, $params) = get_enrolled_sql($context);
+    $params['mcuserid'] = $USER->id;
+    $ufields = user_picture::fields('u');
+
+    $sql = "SELECT $ufields, mc.id as contactlistid, mc.blocked
+              FROM {user} u
+              JOIN ($esql) je ON je.id = u.id
+              LEFT JOIN {message_contacts} mc ON mc.contactid = u.id AND mc.userid = :mcuserid
+             WHERE u.deleted = 0";
+
+    $participants = $DB->get_records_sql($sql, $params, $page * MESSAGE_CONTACTS_PER_PAGE, MESSAGE_CONTACTS_PER_PAGE);
 
     $pagingbar = new paging_bar($countparticipants, $page, MESSAGE_CONTACTS_PER_PAGE, $PAGE->url, 'page');
     echo $OUTPUT->render($pagingbar);
@@ -196,11 +196,23 @@ function message_print_participants($context, $courseid, $contactselecturl=null,
     echo html_writer::tag('td', $titletodisplay, array('colspan' => 3, 'class' => 'heading'));
     echo html_writer::end_tag('tr');
 
-    //todo these need to come from somewhere if the course participants list is to show users with unread messages
-    $iscontact = true;
-    $isblocked = false;
     foreach ($participants as $participant) {
         if ($participant->id != $USER->id) {
+
+            $iscontact = false;
+            $isblocked = false;
+            if ( $participant->contactlistid )  {
+                if ($participant->blocked == 0) {
+                    // Is contact. Is not blocked.
+                    $iscontact = true;
+                    $isblocked = false;
+                } else {
+                    // Is blocked.
+                    $iscontact = false;
+                    $isblocked = true;
+                }
+            }
+
             $participant->messagecount = 0;//todo it would be nice if the course participant could report new messages
             message_print_contactlist_user($participant, $iscontact, $isblocked, $contactselecturl, $showactionlinks, $user2);
         }
index 2ae00a2..a71e9ce 100644 (file)
@@ -58,7 +58,7 @@ class mod_assign_grading_batch_operations_form extends moodleform {
         $mform->addElement('hidden', 'returnaction', 'grading');
 
         $objs = array();
-        $objs[] =& $mform->createElement('select', 'operation', '', $options);
+        $objs[] =& $mform->createElement('select', 'operation', get_string('chooseoperation', 'assign'), $options);
         $objs[] =& $mform->createElement('submit', 'submit', get_string('go'));
         $mform->addElement('group', 'actionsgrp', get_string('batchoperationsdescription', 'assign'), $objs, ' ', false);
 
index b24f4fa..8eb7ce3 100644 (file)
@@ -59,7 +59,7 @@ class mod_assign_grading_options_form extends moodleform {
 
         // quickgrading
         if ($instance['showquickgrading']) {
-            $mform->addElement('checkbox', 'quickgrading', get_string('quickgrading', 'assign'), '');
+            $mform->addElement('checkbox', 'quickgrading', get_string('quickgrading', 'assign'), '', $dirtyclass);
             $mform->addHelpButton('quickgrading', 'quickgrading', 'assign');
             $mform->setDefault('quickgrading', $instance['quickgrading']);
         }
index 45fa21a..78ae6ca 100644 (file)
@@ -65,6 +65,8 @@ $string['batchoperationlock'] = 'lock submissions';
 $string['batchoperationunlock'] = 'unlock submissions';
 $string['batchoperationreverttodraft'] = 'revert submissions to draft';
 $string['changegradewarning'] = 'This assignment has graded submissions and changing the grade will not automatically re-calculate existing submission grades. You must re-grade all existing submissions, if you wish to change the grade.';
+$string['choosegradingaction'] = 'Grading action';
+$string['chooseoperation'] = 'Choose operation';
 $string['comment'] = 'Comment';
 $string['conversionexception'] = 'Could not convert assignment. Exception was: {$a}.';
 $string['configshowrecentsubmissions'] = 'Everyone can see notifications of submissions in recent activity reports.';
index da09984..9ae8c82 100644 (file)
@@ -968,6 +968,8 @@ class assign {
 
         static $scalegrades = array();
 
+        $o = '';
+
         if ($this->get_instance()->grade >= 0) {
             // Normal number
             if ($editing && $this->get_instance()->grade > 0) {
@@ -976,15 +978,18 @@ class assign {
                 } else {
                     $displaygrade = format_float($grade);
                 }
-                $o = '<input type="text" name="quickgrade_' . $userid . '" value="' . $displaygrade . '" size="6" maxlength="10" class="quickgrade"/>';
+                $o .= '<input type="text" name="quickgrade_' . $userid . '" value="' . $displaygrade . '" size="6" maxlength="10" class="quickgrade"/>';
                 $o .= '&nbsp;/&nbsp;' . format_float($this->get_instance()->grade,2);
                 $o .= '<input type="hidden" name="grademodified_' . $userid . '" value="' . $modified . '"/>';
                 return $o;
             } else {
+                $o .= '<input type="hidden" name="grademodified_' . $userid . '" value="' . $modified . '"/>';
                 if ($grade == -1 || $grade === null) {
-                    return '-';
+                    $o .= '-';
+                    return $o;
                 } else {
-                    return format_float(($grade),2) .'&nbsp;/&nbsp;'. format_float($this->get_instance()->grade,2);
+                    $o .= format_float(($grade),2) .'&nbsp;/&nbsp;'. format_float($this->get_instance()->grade,2);
+                    return $o;
                 }
             }
 
@@ -994,11 +999,12 @@ class assign {
                 if ($scale = $DB->get_record('scale', array('id'=>-($this->get_instance()->grade)))) {
                     $this->cache['scale'] = make_menu_from_list($scale->scale);
                 } else {
-                    return '-';
+                    $o .= '-';
+                    return $o;
                 }
             }
             if ($editing) {
-                $o = '<select name="quickgrade_' . $userid . '" class="quickgrade">';
+                $o .= '<select name="quickgrade_' . $userid . '" class="quickgrade">';
                 $o .= '<option value="-1">' . get_string('nograde') . '</option>';
                 foreach ($this->cache['scale'] as $optionid => $option) {
                     $selected = '';
@@ -1013,9 +1019,11 @@ class assign {
             } else {
                 $scaleid = (int)$grade;
                 if (isset($this->cache['scale'][$scaleid])) {
-                    return $this->cache['scale'][$scaleid];
+                    $o .= $this->cache['scale'][$scaleid];
+                    return $o;
                 }
-                return '-';
+                $o .= '-';
+                return $o;
             }
         }
     }
@@ -1048,22 +1056,32 @@ class assign {
     /**
      * Load a count of users submissions in the current module that require grading
      * This means the submission modification time is more recent than the
-     * grading modification time.
+     * grading modification time and the status is SUBMITTED.
      *
      * @return int number of matching submissions
      */
     public function count_submissions_need_grading() {
         global $DB;
 
-        $params = array($this->get_course_module()->instance);
+        $currentgroup = groups_get_activity_group($this->get_course_module(), true);
+        list($esql, $params) = get_enrolled_sql($this->get_context(), 'mod/assign:submit', $currentgroup, false);
 
-        return $DB->count_records_sql("SELECT COUNT('x')
-                                       FROM {assign_submission} s
-                                       LEFT JOIN {assign_grades} g ON s.assignment = g.assignment AND s.userid = g.userid
-                                       WHERE s.assignment = ?
-                                           AND s.timemodified IS NOT NULL
-                                           AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)",
-                                       $params);
+        $params['assignid'] = $this->get_instance()->id;
+        $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+
+        $sql = 'SELECT COUNT(s.userid)
+                   FROM {assign_submission} s
+                   LEFT JOIN {assign_grades} g ON
+                        s.assignment = g.assignment AND
+                        s.userid = g.userid
+                   JOIN(' . $esql . ') AS e ON e.id = s.userid
+                   WHERE
+                        s.assignment = :assignid AND
+                        s.timemodified IS NOT NULL AND
+                        s.status = :submitted AND
+                        (s.timemodified > g.timemodified OR g.timemodified IS NULL)';
+
+        return $DB->count_records_sql($sql, $params);
     }
 
     /**
@@ -1074,10 +1092,26 @@ class assign {
      */
     public function count_submissions_with_status($status) {
         global $DB;
-        return $DB->count_records_sql("SELECT COUNT('x')
-                                     FROM {assign_submission}
-                                    WHERE assignment = ? AND
-                                          status = ?", array($this->get_course_module()->instance, $status));
+
+        $currentgroup = groups_get_activity_group($this->get_course_module(), true);
+        list($esql, $params) = get_enrolled_sql($this->get_context(), 'mod/assign:submit', $currentgroup, false);
+
+        $params['assignid'] = $this->get_instance()->id;
+        $params['submissionstatus'] = $status;
+
+        $sql = 'SELECT COUNT(s.userid)
+                   FROM {assign_submission} s
+                   LEFT JOIN {assign_grades} g ON
+                        s.assignment = g.assignment AND
+                        s.userid = g.userid
+                   JOIN(' . $esql . ') AS e ON e.id = s.userid
+                   WHERE
+                        s.assignment = :assignid AND
+                        s.timemodified IS NOT NULL AND
+                        s.status = :submissionstatus AND
+                        (s.timemodified > g.timemodified OR g.timemodified IS NULL)';
+
+        return $DB->count_records_sql($sql, $params);
     }
 
     /**
@@ -1130,22 +1164,32 @@ class assign {
      * @return array The submission objects indexed by id
      */
     private function get_all_submissions( $sort="", $dir="DESC") {
-        global $CFG, $DB;
+        global $DB;
+
+        $currentgroup = groups_get_activity_group($this->get_course_module(), true);
+        list($esql, $params) = get_enrolled_sql($this->get_context(), 'mod/assign:submit', $currentgroup, false);
+
+        $params['assignid'] = $this->get_instance()->id;
+
+        $sql = 'SELECT s.*, u.lastname, u.firstname, u.username
+                   FROM {assign_submission} s
+                   JOIN {user} u ON s.userid = u.id
+                   JOIN(' . $esql . ') AS e ON e.id = s.userid
+                   WHERE
+                        s.assignment = :assignid AND
+                        s.timemodified IS NOT NULL';
 
         if ($sort == "lastname" or $sort == "firstname") {
             $sort = "u.$sort $dir";
         } else if (empty($sort)) {
-            $sort = "a.timemodified DESC";
+            $sort = "s.timemodified DESC";
         } else {
-            $sort = "a.$sort $dir";
+            $sort = "s.$sort $dir";
         }
 
-        return $DB->get_records_sql("SELECT a.*
-                                       FROM {assign_submission} a, {user} u
-                                      WHERE u.id = a.userid
-                                            AND a.assignment = ?
-                                   ORDER BY $sort", array($this->get_instance()->id));
+        $sql .= ' ORDER BY ' . $sort;
 
+        return $DB->get_records_sql($sql, $params);
     }
 
     /**
@@ -1534,9 +1578,7 @@ class assign {
             if ((groups_is_member($groupid,$userid) or !$groupmode or !$groupid)) {
                 // get the plugins to add their own files to the zip
 
-                $user = $DB->get_record("user", array("id"=>$userid),'id,username,firstname,lastname', MUST_EXIST);
-
-                $prefix = clean_filename(fullname($user) . "_" .$userid . "_");
+                $prefix = clean_filename(fullname($submission) . "_" .$userid . "_");
 
                 foreach ($this->submissionplugins as $plugin) {
                     if ($plugin->is_enabled() && $plugin->is_visible()) {
@@ -1601,12 +1643,7 @@ class assign {
             $submission->userid       = $userid;
             $submission->timecreated = time();
             $submission->timemodified = $submission->timecreated;
-
-            if ($this->get_instance()->submissiondrafts) {
-                $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
-            } else {
-                $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-            }
+            $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
             $sid = $DB->insert_record('assign_submission', $submission);
             $submission->id = $sid;
             return $submission;
@@ -1801,6 +1838,7 @@ class assign {
         }
 
         $gradingactions = new url_select($links);
+        $gradingactions->set_label(get_string('choosegradingaction', 'assign'));
 
         $gradingmanager = get_grading_manager($this->get_context(), 'mod_assign', 'submissions');
 
@@ -2094,6 +2132,9 @@ class assign {
             $showedit = has_capability('mod/assign:submit', $this->context) &&
                          $this->submissions_open() && ($this->is_any_submission_plugin_enabled()) && $showlinks;
             $showsubmit = $submission && ($submission->status == ASSIGN_SUBMISSION_STATUS_DRAFT) && $showlinks;
+            if (!$this->get_instance()->submissiondrafts) {
+                $showsubmit = false;
+            }
             $gradelocked = ($grade && $grade->locked) || $this->grading_disabled($user->id);
 
             $o .= $this->output->render(new assign_submission_status($this->get_instance()->allowsubmissionsfromdate,
@@ -2620,19 +2661,16 @@ class assign {
         // gets a list of possible users and look for values based upon that.
         foreach ($participants as $userid => $unused) {
             $modified = optional_param('grademodified_' . $userid, -1, PARAM_INT);
-            if ($modified >= 0) {
-                // gather the userid, updated grade and last modified value
-                $record = new stdClass();
-                $record->userid = $userid;
-                $record->grade = unformat_float(required_param('quickgrade_' . $record->userid, PARAM_TEXT));
-                $record->lastmodified = $modified;
-                $record->gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, array($userid));
-                $users[$userid] = $record;
+            // Gather the userid, updated grade and last modified value.
+            $record = new stdClass();
+            $record->userid = $userid;
+            $gradevalue = optional_param('quickgrade_' . $userid, '', PARAM_TEXT);
+            if($modified >= 0) {
+                $record->grade = unformat_float(optional_param('quickgrade_' . $record->userid, -1, PARAM_TEXT));
             }
-        }
-        if (empty($users)) {
-            // Quick check to see whether we have any users to update and we don't
-            return get_string('quickgradingchangessaved', 'assign'); // Technical lie
+            $record->lastmodified = $modified;
+            $record->gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, array($userid));
+            $users[$userid] = $record;
         }
 
         list($userids, $params) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED);
@@ -2847,13 +2885,18 @@ class assign {
         }
         if ($data = $mform->get_data()) {
             $submission = $this->get_user_submission($USER->id, true); //create the submission if needed & its id
+            if ($this->get_instance()->submissiondrafts) {
+                $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
+            } else {
+                $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+            }
+
             $grade = $this->get_user_grade($USER->id, false); // get the grade to check if it is locked
             if ($grade && $grade->locked) {
                 print_error('submissionslocked', 'assign');
                 return true;
             }
 
-
             $allempty = true;
             $pluginerror = false;
             foreach ($this->submissionplugins as $plugin) {
@@ -2993,6 +3036,11 @@ class assign {
                 $grademenu = make_grades_menu($this->get_instance()->grade);
                 if (count($grademenu) > 0) {
                     $gradingelement = $mform->addElement('select', 'grade', get_string('grade').':', $grademenu);
+
+                    // The grade is already formatted with format_float so it needs to be converted back to an integer.
+                    if (!empty($data->grade)) {
+                        $data->grade = (int)unformat_float($data->grade);
+                    }
                     $mform->setType('grade', PARAM_INT);
                     if ($gradingdisabled) {
                         $gradingelement->freeze();
index 993db48..107eae8 100644 (file)
@@ -452,7 +452,11 @@ class mod_assign_renderer extends plugin_renderer_base {
             $t->data[] = $row;
 
             foreach ($status->submissionplugins as $plugin) {
-                if ($plugin->is_enabled() && $plugin->is_visible() && !$plugin->is_empty($status->submission)) {
+                $pluginshowsummary = !$plugin->is_empty($status->submission) || !$plugin->allow_submissions();
+                if ($plugin->is_enabled() &&
+                    $plugin->is_visible() &&
+                    $pluginshowsummary) {
+
                     $row = new html_table_row();
                     $cell1 = new html_table_cell($plugin->get_name());
                     $pluginsubmission = new assign_submission_plugin_submission($plugin, $status->submission, assign_submission_plugin_submission::SUMMARY, $status->coursemoduleid, $status->returnaction, $status->returnparams);
index eb87938..1d91186 100644 (file)
@@ -78,12 +78,13 @@ class assign_submission_comments extends assign_submission_plugin {
     }
 
     /**
-     * Always return false because at a minimum there is the comments control
+     * Always return true because the submission comments are not part of the submission form.
+     *
      * @param stdClass $submission
      * @return bool
      */
     public function is_empty(stdClass $submission) {
-        return false;
+        return true;
     }
 
   /**
index cfb95ad..7d5b624 100644 (file)
@@ -200,7 +200,12 @@ class assign_submission_onlinetext extends assign_submission_plugin {
         $showviewlink = true;
 
         if ($onlinetextsubmission) {
-            $text = format_text($onlinetextsubmission->onlinetext, $onlinetextsubmission->onlineformat, array('context'=>$this->assignment->get_context()));
+            $text = $this->assignment->render_editor_content(ASSIGNSUBMISSION_ONLINETEXT_FILEAREA,
+                                                             $onlinetextsubmission->submission,
+                                                             $this->get_type(),
+                                                             'onlinetext',
+                                                             'assignsubmission_onlinetext');
+
             $shorttext = shorten_text($text, 140);
             if ($text != $shorttext) {
                 return $shorttext . get_string('numwords', 'assignsubmission_onlinetext', count_words($text));
@@ -376,7 +381,9 @@ class assign_submission_onlinetext extends assign_submission_plugin {
      * @return bool
      */
     public function is_empty(stdClass $submission) {
-        return $this->view($submission) == '';
+        $onlinetextsubmission = $this->get_onlinetext_submission($submission->id);
+
+        return empty($onlinetextsubmission->onlinetext);
     }
 
     /**
index 8e7df84..f50aac0 100644 (file)
@@ -134,6 +134,8 @@ class assign_upgrade_manager {
                     if (!$plugin->upgrade_settings($oldcontext, $oldassignment, $log)) {
                         $rollback = true;
                     }
+                } else {
+                    $plugin->disable();
                 }
             }
             foreach ($newassignment->get_feedback_plugins() as $plugin) {
@@ -142,6 +144,8 @@ class assign_upgrade_manager {
                     if (!$plugin->upgrade_settings($oldcontext, $oldassignment, $log)) {
                         $rollback = true;
                     }
+                } else {
+                    $plugin->disable();
                 }
             }
 
index 0104331..3688ac9 100644 (file)
@@ -1380,6 +1380,7 @@ class assignment_base {
 
         $table->no_sorting('finalgrade');
         $table->no_sorting('outcome');
+        $table->text_sorting('submissioncomment');
 
         // Start working -- this is necessary as soon as the niceties are over
         $table->setup();
index 4a5cf40..2a68d4c 100644 (file)
@@ -75,8 +75,10 @@ if ($rid) {
 
 require_course_login($course, true, $cm);
 
+$context = context_module::instance($cm->id);
+
 /// If it's hidden then it's don't show anything.  :)
-if (empty($cm->visible) and !has_capability('moodle/course:viewhiddenactivities',get_context_instance(CONTEXT_MODULE, $cm->id))) {
+if (empty($cm->visible) and !has_capability('moodle/course:viewhiddenactivities', $context)) {
     $PAGE->set_title($data->name);
     echo $OUTPUT->header();
     notice(get_string("activityiscurrentlyhidden"));
index 93c2e81..6dfaaa1 100644 (file)
@@ -762,7 +762,7 @@ if ($showactivity) {
         $records = array();
     }
 
-    if ($mode == '' && !empty($CFG->enableportfolios)) {
+    if ($mode == '' && !empty($CFG->enableportfolios) && !empty($records)) {
         require_once($CFG->libdir . '/portfoliolib.php');
         $button = new portfolio_add_button();
         $button->set_callback_options('data_portfolio_caller', array('id' => $cm->id), '/mod/data/locallib.php');
index 8dd1bf7..a1c8196 100644 (file)
@@ -29,7 +29,7 @@ class feedback_captcha_form extends feedback_item_form {
         $mform =& $this->_form;
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
-        $mform->addElement('checkbox', 'required', get_string('required', 'feedback'));
+        $mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
         $mform->addElement('text',
                             'name',
                             get_string('item_name', 'feedback'),
index 25074fd..6dd192d 100644 (file)
@@ -29,7 +29,7 @@ class feedback_multichoice_form extends feedback_item_form {
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
 
-        $mform->addElement('checkbox', 'required', get_string('required', 'feedback'));
+        $mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
 
         $mform->addElement('text',
                             'name',
index e95fb44..0c1632a 100644 (file)
@@ -29,7 +29,7 @@ class feedback_multichoicerated_form extends feedback_item_form {
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
 
-        $mform->addElement('checkbox', 'required', get_string('required', 'feedback'));
+        $mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
 
         $mform->addElement('text',
                             'name',
index 1252870..5abbea0 100644 (file)
@@ -29,7 +29,7 @@ class feedback_numeric_form extends feedback_item_form {
         $mform =& $this->_form;
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
-        $mform->addElement('checkbox', 'required', get_string('required', 'feedback'));
+        $mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
 
         $mform->addElement('text',
                             'name',
index d498241..0a777e7 100644 (file)
@@ -28,7 +28,7 @@ class feedback_textarea_form extends feedback_item_form {
         $mform =& $this->_form;
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
-        $mform->addElement('checkbox', 'required', get_string('required', 'feedback'));
+        $mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
 
         $mform->addElement('text',
                             'name',
index 59c25ce..9361dff 100644 (file)
@@ -28,7 +28,7 @@ class feedback_textfield_form extends feedback_item_form {
         $mform =& $this->_form;
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
-        $mform->addElement('checkbox', 'required', get_string('required', 'feedback'));
+        $mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
 
         $mform->addElement('text',
                             'name',
index 9eb2c18..d751340 100644 (file)
@@ -387,14 +387,6 @@ class qformat_default {
                     $newpage->contents = $question->questiontext;
                     $newpage->contentsformat = isset($question->questionformat) ? $question->questionformat : FORMAT_HTML;
 
-                    // Sometimes, questiontext is not a simple text, but one array
-                    // containing both text and format, so we need to support here
-                    // that case with the following dirty patch. MDL-35147
-                    if (is_array($question->questiontext)) {
-                        $newpage->contents = isset($question->questiontext['text']) ? $question->questiontext['text'] : '';
-                        $newpage->contentsformat = isset($question->questiontext['format']) ? $question->questiontext['format'] : FORMAT_HTML;
-                    }
-
                     // set up page links
                     if ($pageid) {
                         // the new page follows on from this page
index 5beec57..464e102 100644 (file)
@@ -338,6 +338,7 @@ if ($pageid != LESSON_EOL) {
         if (lesson_display_teacher_warning($lesson)) {
             // This is the warning msg for teachers to inform them that cluster
             // and unseen does not work while logged in as a teacher
+            $warningvars = new stdClass();
             $warningvars->cluster = get_string('clusterjump', 'lesson');
             $warningvars->unseen = get_string('unseenpageinbranch', 'lesson');
             $lesson->add_message(get_string('teacherjumpwarning', 'lesson', $warningvars));
index b728116..2c0b038 100644 (file)
@@ -70,6 +70,7 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
             'timemodified',
             'typeid',
             'toolurl',
+            'securetoolurl',
             'preferheight',
             'launchcontainer',
             'instructorchoicesendname',
@@ -79,8 +80,11 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
             'instructorchoiceallowsetting',
             'grade',
             'instructorcustomparameters',
+            'debuglaunch',
             'showtitlelaunch',
-            'showdescriptionlaunch'
+            'showdescriptionlaunch',
+            'icon',
+            'secureicon',
             )
         );
 
index 12f117b..78f202e 100644 (file)
@@ -2,14 +2,12 @@ This files describes API changes for quiz access rule plugins.
 
 Overview of this plugin type at http://docs.moodle.org/dev/Quiz_access_rules
 
-
-=== 2.2 ===
-
-* This plugin type was new in Moodle 2.2!
-
-
 === 2.3 ===
 
 * This plugin type now supports cron in the standard way. If required, Create a
   lib.php file containing
 function quizaccess_mypluginname_cron() {};
+
+=== 2.2 ===
+
+* This plugin type was new in Moodle 2.2!
index 303638f..cf6068d 100644 (file)
@@ -36,9 +36,13 @@ $attemptobj = quiz_attempt::create($attemptid);
 // Check login.
 require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
 
-// If this is not our own attempt, display an error.
+// Check that this attempt belongs to this user.
 if ($attemptobj->get_userid() != $USER->id) {
-    print_error('notyourattempt', 'quiz', $attemptobj->view_url());
+    if ($attemptobj->has_capability('mod/quiz:viewreports')) {
+        redirect($attemptobj->review_url(null, $page));
+    } else {
+        throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
+    }
 }
 
 // Check capabilites.
index c3de373..dd410bb 100644 (file)
@@ -272,8 +272,6 @@ function scorm_delete_instance($id) {
             }
         }
         $DB->delete_records('scorm_scoes', array('scorm'=>$scorm->id));
-    } else {
-        $result = false;
     }
     if (! $DB->delete_records('scorm', array('id'=>$scorm->id))) {
         $result = false;
index ee8dc2e..afea1a3 100644 (file)
@@ -657,7 +657,7 @@ class page_wiki_comments extends page_wiki {
                     $parsedcontent = wiki_parse_content('nwiki', $comment->content, $options);
                 }
 
-                $cell4->text = format_text(html_entity_decode($parsedcontent['parsed_text']), FORMAT_HTML);
+                $cell4->text = format_text(html_entity_decode($parsedcontent['parsed_text'], ENT_QUOTES, 'UTF-8'), FORMAT_HTML);
             } else {
                 $cell4->text = format_text($comment->content, FORMAT_HTML);
             }
index eb14bc0..f777f28 100644 (file)
@@ -14,9 +14,9 @@ require_once($CFG->dirroot . "/lib/outputcomponents.php");
 class parser_utils {
         
     public static function h($tag, $text = null, $options = array(), $escape_text = false) {
-        $tag = htmlentities($tag);
+        $tag = htmlentities($tag, ENT_COMPAT, 'UTF-8');
         if(!empty($text) && $escape_text) {
-                $text = htmlentities($text);
+                $text = htmlentities($text, ENT_COMPAT, 'UTF-8');
             }
         return html_writer::tag($tag, $text, $options);
     }
index 1508b5b..cf37a23 100644 (file)
@@ -1035,7 +1035,7 @@ function workshop_get_extra_capabilities() {
  * Needed by grade_update_mod_grades() in lib/gradelib.php. Also used by
  * {@link workshop_update_grades()}.
  *
- * @param stdClass $workshop instance object with extra cmidnumber and modname property
+ * @param stdClass $workshop instance object with extra cmidnumber property
  * @param stdClass $submissiongrades data for the first grade item
  * @param stdClass $assessmentgrades data for the second grade item
  * @return void
index 5f51d0a..abe0b39 100644 (file)
@@ -1,5 +1,11 @@
 This files describes API changes for question behaviour plugins.
 
+=== 2.3 ===
+
+* This plugin type now supports cron in the standard way. If required, Create a
+  lib.php file containing
+function qbehaviour_mypluginname_cron() {};
+
 === 2.2 ===
 
 1) The old
@@ -14,10 +20,3 @@ $plugin->dependencies = array(
 is_compatible_question method. You should change your behaviour to override the
 new method, not the old one. This change has been implemented in a
 backwards-compatible way, so behaviours will not break.
-
-
-=== 2.3 ===
-
-* This plugin type now supports cron in the standard way. If required, Create a
-  lib.php file containing
-function qbehaviour_mypluginname_cron() {};
index e28fe30..8f2396e 100644 (file)
@@ -73,7 +73,7 @@ if ($from_form = $export_form->get_data()) {
     echo get_string('yourfileshoulddownload', 'question', $export_url->out());
     echo $OUTPUT->box_end();
 
-    $PAGE->requires->js_function_call('document.location.replace', array($export_url->out()), false, 1);
+    $PAGE->requires->js_function_call('document.location.replace', array($export_url->out(false)), false, 1);
 
     echo $OUTPUT->continue_button(new moodle_url('edit.php', $thispageurl->params()));
     echo $OUTPUT->footer();
index 13c1232..811e9bc 100644 (file)
@@ -413,20 +413,11 @@ class qformat_default {
                     'maxfiles' => -1,
                     'maxbytes' => 0,
                 );
-            if (is_array($question->questiontext)) {
-                // Importing images from draftfile.
-                $questiontext = $question->questiontext;
-                $question->questiontext = $questiontext['text'];
-            }
-            if (is_array($question->generalfeedback)) {
-                $generalfeedback = $question->generalfeedback;
-                $question->generalfeedback = $generalfeedback['text'];
-            }
 
             $question->id = $DB->insert_record('question', $question);
 
-            if (!empty($questiontext['itemid'])) {
-                $question->questiontext = file_save_draft_area_files($questiontext['itemid'],
+            if (isset($question->questiontextitemid)) {
+                $question->questiontext = file_save_draft_area_files($question->questiontextitemid,
                         $this->importcontext->id, 'question', 'questiontext', $question->id,
                         $fileoptions, $question->questiontext);
             } else if (isset($question->questiontextfiles)) {
@@ -435,8 +426,8 @@ class qformat_default {
                             $this->importcontext, 'question', 'questiontext', $question->id, $file);
                 }
             }
-            if (!empty($generalfeedback['itemid'])) {
-                $question->generalfeedback = file_save_draft_area_files($generalfeedback['itemid'],
+            if (isset($question->generalfeedbackitemid)) {
+                $question->generalfeedback = file_save_draft_area_files($question->generalfeedbackitemid,
                         $this->importcontext->id, 'question', 'generalfeedback', $question->id,
                         $fileoptions, $question->generalfeedback);
             } else if (isset($question->generalfeedbackfiles)) {
index da08e91..4424f5f 100644 (file)
@@ -148,16 +148,4 @@ class qformat_blackboard_six_base extends qformat_based_on_xml {
     public function cleaned_text_field($text) {
         return $this->text_field($this->cleaninput($text));
     }
-
-    /**
-     * Convert the question text to plain text.
-     * We need to overwrite this function because questiontext is an array.
-     */
-    protected function format_question_text($question) {
-        global $DB;
-        $formatoptions = new stdClass();
-        $formatoptions->noclean = true;
-        return html_to_text(format_text($question->questiontext['text'],
-                $question->questiontext['format'], $formatoptions), 0, false);
-    }
 }
index a6c942c..7911305 100644 (file)
@@ -88,12 +88,16 @@ class qformat_blackboard_six_pool extends qformat_blackboard_six_base {
                 array('#', 'BODY', 0, '#', 'TEXT', 0, '#'),
                 '', true, get_string('importnotext', 'qformat_blackboard_six'));
 
-        $question->questiontext = $this->cleaned_text_field($text);
-        $question->questiontextformat = FORMAT_HTML; // Needed because add_blank_combined_feedback uses it.
+        $questiontext = $this->cleaned_text_field($text);
+        $question->questiontext = $questiontext['text'];
+        $question->questiontextformat = $questiontext['format']; // Needed because add_blank_combined_feedback uses it.
+        if (isset($questiontext['itemid'])) {
+            $question->questiontextitemid = $questiontext['itemid'];
+        }
 
         // Put name in question object. We must ensure it is not empty and it is less than 250 chars.
         $id = $this->getpath($questiondata, array('@', 'id'), '',  true);
-        $question->name = $this->create_default_question_name($question->questiontext['text'],
+        $question->name = $this->create_default_question_name($question->questiontext,
                 get_string('defaultname', 'qformat_blackboard_six' , $id));
 
         $question->generalfeedback = '';
@@ -453,7 +457,7 @@ class qformat_blackboard_six_pool extends qformat_blackboard_six_base {
                 $subanswercount++;
             }
             if ($subquestioncount < 2 || $subanswercount < 3) {
-                    $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext['text']));
+                    $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext));
             } else {
                 $questions[] = $question;
             }
index 37545fd..6b9edda 100644 (file)
@@ -506,11 +506,13 @@ class qformat_blackboard_six_qti extends qformat_blackboard_six_base {
     public function process_common($quest) {
         $question = $this->defaultquestion();
         $text = $quest->QUESTION_BLOCK->text;
-
-        $question->questiontext = $this->cleaned_text_field($text);
-        $question->questiontextformat = FORMAT_HTML; // Needed because add_blank_combined_feedback uses it.
-
-        $question->name = $this->create_default_question_name($question->questiontext['text'],
+        $questiontext = $this->cleaned_text_field($text);
+        $question->questiontext = $questiontext['text'];
+        $question->questiontextformat = $questiontext['format']; // Needed because add_blank_combined_feedback uses it.
+        if (isset($questiontext['itemid'])) {
+            $question->questiontextitemid = $questiontext['itemid'];
+        }
+        $question->name = $this->create_default_question_name($question->questiontext,
                 get_string('defaultname', 'qformat_blackboard_six' , $quest->id));
         $question->generalfeedback = '';
         $question->generalfeedbackformat = FORMAT_HTML;
@@ -863,7 +865,7 @@ class qformat_blackboard_six_qti extends qformat_blackboard_six_base {
             $subanswercount++;
         }
         if ($subquestioncount < 2 || $subanswercount < 3) {
-                $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext['text']));
+                $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext));
         } else {
             $questions[] = $question;
         }
index 22cadb7..fdfa5e4 100644 (file)
@@ -58,10 +58,7 @@ class qformat_blackboard_six_pool_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'match';
         $expectedq->name = 'Classify the animals.';
-        $expectedq->questiontext = array(
-                'text' => '<i>Classify the animals.</i>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<i>Classify the animals.</i>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array('text' => '',
                 'format' => FORMAT_HTML);
@@ -98,10 +95,7 @@ class qformat_blackboard_six_pool_test extends question_testcase {
         $expectedq->qtype = 'multichoice';
         $expectedq->single = 1;
         $expectedq->name = 'What\'s between orange and green in the spectrum?';
-        $expectedq->questiontext = array(
-                'text' =>'<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array('text' => 'You gave the right answer.',
                 'format' => FORMAT_HTML);
@@ -161,10 +155,7 @@ class qformat_blackboard_six_pool_test extends question_testcase {
         $expectedq->qtype = 'multichoice';
         $expectedq->single = 0;
         $expectedq->name = 'What\'s between orange and green in the spectrum?';
-        $expectedq->questiontext = array(
-                'text' => '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array(
                 'text' => 'You gave the right answer.',
@@ -237,10 +228,7 @@ class qformat_blackboard_six_pool_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'truefalse';
         $expectedq->name = '42 is the Absolute Answer to everything.';
-        $expectedq->questiontext = array(
-                'text' => '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->generalfeedback = '';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
@@ -270,10 +258,7 @@ class qformat_blackboard_six_pool_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'shortanswer';
         $expectedq->name = 'Name an amphibian: __________.';
-        $expectedq->questiontext = array(
-                'text' => '<span style="font-size:12pt">Name an amphibian: __________.</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">Name an amphibian: __________.</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->generalfeedback = '';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
@@ -308,10 +293,7 @@ class qformat_blackboard_six_pool_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'essay';
         $expectedq->name = 'How are you?';
-        $expectedq->questiontext = array(
-                'text' => 'How are you?',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = 'How are you?';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->generalfeedback = '';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
index 68df181..9d80e9b 100644 (file)
@@ -55,10 +55,7 @@ class qformat_blackboard_six_qti_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'match';
         $expectedq->name = 'Classify the animals.';
-        $expectedq->questiontext = array(
-                'text' => 'Classify the animals.',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = 'Classify the animals.';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array('text' => '',
                 'format' => FORMAT_HTML, 'files' => array());
@@ -94,10 +91,7 @@ class qformat_blackboard_six_qti_test extends question_testcase {
         $expectedq->qtype = 'multichoice';
         $expectedq->single = 1;
         $expectedq->name = 'What\'s between orange and green in the spectrum?';
-        $expectedq->questiontext = array(
-                'text' => '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array('text' => '',
                 'format' => FORMAT_HTML, 'files' => array());
@@ -157,10 +151,7 @@ class qformat_blackboard_six_qti_test extends question_testcase {
         $expectedq->qtype = 'multichoice';
         $expectedq->single = 0;
         $expectedq->name = 'What\'s between orange and green in the spectrum?';
-        $expectedq->questiontext = array(
-                'text' => '<i>What\'s between orange and green in the spectrum?</i>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<i>What\'s between orange and green in the spectrum?</i>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array(
                 'text' => '',
@@ -236,10 +227,7 @@ class qformat_blackboard_six_qti_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'truefalse';
         $expectedq->name = '42 is the Absolute Answer to everything.';
-        $expectedq->questiontext = array(
-                'text' => '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->generalfeedback = '';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
@@ -270,10 +258,7 @@ class qformat_blackboard_six_qti_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'shortanswer';
         $expectedq->name = 'Name an amphibian: __________.';
-        $expectedq->questiontext = array(
-                'text' => '<span style="font-size:12pt">Name an amphibian: __________.</span>',
-                'format' => FORMAT_HTML,
-            );
+        $expectedq->questiontext = '<span style="font-size:12pt">Name an amphibian: __________.</span>';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->generalfeedback = '';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
@@ -308,10 +293,7 @@ class qformat_blackboard_six_qti_test extends question_testcase {
         $expectedq = new stdClass();
         $expectedq->qtype = 'essay';
         $expectedq->name = 'How are you?';
-        $expectedq->questiontext = array(
-                'text' => 'How are you?',
-                'format' => FORMAT_HTML
-            );
+        $expectedq->questiontext = 'How are you?';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->generalfeedback = '';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
index b31a7a0..53943c0 100644 (file)
@@ -1,5 +1,11 @@
 This files describes API changes for question import/export format plugins.
 
+=== 2.3 ===
+
+* This plugin type now supports cron in the standard way. If required, Create a
+  lib.php file containing
+function qformat_mypluginname_cron() {};
+
 === 2.1.5 / 2.2.3 / 2.3 ===
 
 * The readquestions method used to take a second argument $context. However, at
@@ -25,8 +31,3 @@ $string['pluginname_help'] = 'This is a simple format ...';
 $string['pluginname_link'] = 'qformat/aiken';
 
 
-=== 2.3 ===
-
-* This plugin type now supports cron in the standard way. If required, Create a
-  lib.php file containing
-function qformat_mypluginname_cron() {};
index 45ec077..64f0dbf 100644 (file)
@@ -905,17 +905,18 @@ class qformat_xml extends qformat_default {
      */
     protected function readquestions($lines) {
         // We just need it as one big string
-        $text = implode($lines, ' ');
-        unset($lines);
+        $lines = implode('', $lines);
 
         // This converts xml to big nasty data structure
         // the 0 means keep white space as it is (important for markdown format)
         try {
-            $xml = xmlize($text, 0, 'UTF-8', true);
+            $xml = xmlize($lines, 0, 'UTF-8', true);
         } catch (xml_format_exception $e) {
             $this->error($e->getMessage(), '');
             return false;
         }
+        unset($lines); // No need to keep this in memory.
+
         // Set up array to hold all our questions
         $questions = array();
 
index c0ab753..0a91a53 100644 (file)
@@ -1227,7 +1227,7 @@ class qtype_calculated extends question_type {
                 echo $OUTPUT->notification(get_string('notvalidnumber', 'qtype_calculated', $a));
                 $val = 1.0;
             }
-            if ($val < 0) {
+            if ($val <= 0) { // MDL-36025 Use parentheses for "-0"
                 $str = str_replace('{'.$name.'}', '('.$val.')', $str);
             } else {
                 $str = str_replace('{'.$name.'}', $val, $str);
@@ -1255,6 +1255,7 @@ class qtype_calculated extends question_type {
         } else if ($formula === '*') {
             $str = '*';
         } else {
+            $str = null;
             eval('$str = '.$formula.';');
         }
         return $str;
@@ -1870,6 +1871,11 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
     // Exchange formula variables with the correct values...
     $answer = question_bank::get_qtype('calculated')->substitute_variables_and_eval(
             $formula, $individualdata);
+    if (!is_numeric($answer)) {
+        // Something went wrong, so just return NaN.
+        $calculated->answer = NAN;
+        return $calculated;
+    }
     if ('1' == $answerformat) { /* Answer is to have $answerlength decimals */
         /*** Adjust to the correct number of decimals ***/
         if (stripos($answer, 'e')>0) {
index 5afe4ff..a24a4fd 100644 (file)
@@ -118,10 +118,6 @@ abstract class qtype_multianswer_subq_renderer_base extends qtype_renderer {
     protected function feedback_popup(question_graded_automatically $subq,
             $fraction, $feedbacktext, $rightanswer, question_display_options $options) {
 
-        if (!$options->feedback) {
-            return '';
-        }
-
         $feedback = array();
         if ($options->correctness) {
             if (is_null($fraction)) {
@@ -132,7 +128,7 @@ abstract class qtype_multianswer_subq_renderer_base extends qtype_renderer {
             $feedback[] = $state->default_string(true);
         }
 
-        if ($feedbacktext) { // Note $options->feedback is already checked above.
+        if ($options->feedback && $feedbacktext) {
             $feedback[] = $feedbacktext;
         }
 
@@ -141,7 +137,8 @@ abstract class qtype_multianswer_subq_renderer_base extends qtype_renderer {
         }
 
         $subfraction = '';
-        if ($options->marks >= question_display_options::MARK_AND_MAX && $subq->maxmark > 0) {
+        if ($options->marks >= question_display_options::MARK_AND_MAX && $subq->maxmark > 0
+                && (!is_null($fraction) || $feedback)) {
             $a = new stdClass();
             $a->mark = format_float($fraction * $subq->maxmark, $options->markdp);
             $a->max =  format_float($subq->maxmark, $options->markdp);
index 9544e91..276a170 100644 (file)
@@ -281,7 +281,10 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
     $timemidnight = $today = usergetmidnight($timenow);
 
     // Put today up the top of the list
-    $dates = array("$timemidnight" => get_string("today").", ".userdate($timenow, $strftimedate) );
+    $dates = array(
+        "0" => get_string('alldays'),
+        "$timemidnight" => get_string("today").", ".userdate($timenow, $strftimedate)
+    );
 
     if (!$course->startdate or ($course->startdate > $timenow)) {
         $course->startdate = $course->timecreated;
@@ -295,7 +298,7 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
         $numdates++;
     }
 
-    if ($selecteddate == "today") {
+    if ($selecteddate === "today") {
         $selecteddate = $today;
     }
 
@@ -355,7 +358,7 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
     }
 
     echo html_writer::label(get_string('date'), 'menudate', false, array('class' => 'accesshide'));
-    echo html_writer::select($dates, "date", $selecteddate, get_string("alldays"));
+    echo html_writer::select($dates, "date", $selecteddate, false);
     echo html_writer::label(get_string('showreports'), 'menumodid', false, array('class' => 'accesshide'));
     echo html_writer::select($activities, "modid", $selectedactivity, get_string("allactivities"));
     echo html_writer::label(get_string('actions'), 'menumodaction', false, array('class' => 'accesshide'));
index aa35dfe..e467b23 100644 (file)
@@ -71,17 +71,13 @@ class repository_webdav extends repository {
         return true;
     }
     public function get_file($url, $title = '') {
-        global $CFG;
         $url = urldecode($url);
         $path = $this->prepare_file($title);
-        $buffer = '';
         if (!$this->dav->open()) {
             return false;
         }
         $webdavpath = rtrim('/'.ltrim($this->options['webdav_path'], '/ '), '/ '); // without slash in the end
-        $this->dav->get($webdavpath. $url, $buffer);
-        $fp = fopen($path, 'wb');
-        fwrite($fp, $buffer);
+        $this->dav->get_file($webdavpath. $url, $path);
         return array('path'=>$path);
     }
     public function global_search() {
index 3d4a13c..640b90f 100644 (file)
@@ -13,7 +13,6 @@
 #chooseqtype .submitbuttons {margin: 0.7em 0;text-align: center;}
 
 #qtypechoicecontainer {display: none;}
-body.jsenabled #qtypechoicecontainer {display: block;}
 
 #qtypechoicecontainer_c.yui-panel-container.shadow .underlay {background: none;}
 #qtypechoicecontainer.yui-panel .hd {color:#333333;letter-spacing: 1px;text-shadow: 1px 1px 1px #FFFFFF;border-radius: 10px 10px 0 0;border: 1px solid #CCCCCC;border-bottom: 1px solid #BBBBBB;background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));background: -moz-linear-gradient(top,  #FFFFFF,  #CCCCCC);}
@@ -33,6 +32,8 @@ body.jsenabled #qtypechoicecontainer {display: block;}
 #categoryquestions { margin: 0; }
 #categoryquestions td,
 #categoryquestions th { padding: 0 0.2em; }
+#categoryquestions th { text-align: left; font-weight: normal; }
+.dir-rtl #categoryquestions th { text-align: right; }
 .questionbank .singleselect { margin: 0; }
 
 /* Question editing form */
index a8db47e..465de70 100644 (file)
@@ -844,6 +844,11 @@ table#categoryquestions th a {
     padding: 5px;
 }
 
+.generaltable .header,
+.generaltable .header {
+    padding: 0;
+}
+
 tr.r1 td {
     background-color: #f9f9f9;
 }
index 0cf29a7..949de96 100644 (file)
@@ -1,10 +1,5 @@
 /** Admin layout **/
 
-body.pagelayout-admin {
-    background-image: none;
-    background-color: #fff;
-}
-
 body.pagelayout-admin.has_dock {
     margin-left: 30px;
 }
@@ -13,7 +8,6 @@ body.pagelayout-admin.has_dock {
     margin: 0 auto;
     position: relative;
 }
-.pagelayout-admin #page-header,
 .pagelayout-admin #page-footer {
     float: none;
     background: #f3f3f3 none;
@@ -22,13 +16,6 @@ body.pagelayout-admin.has_dock {
     padding: 0;
     text-align: left;
 }
-.pagelayout-admin #page-header {
-    background:#97d3f4 url([[pix:theme|header]]) no-repeat top right;
-    margin-bottom: 0px;
-    height: 105px;
-    border-bottom: 1px solid #FFF;
-}
-
 .pagelayout-admin #page-header #custommenu {
     display: none;
 }
@@ -38,7 +25,6 @@ body.pagelayout-admin.has_dock {
     margin: 0;
     padding: 5px 0;
 }
-
 .pagelayout-admin #page-footer {
     text-align: center;
     height: auto;
@@ -49,7 +35,6 @@ body.pagelayout-admin.has_dock {
     padding: 0;
     text-align: center;
 }
-
 .pagelayout-admin #page-content {
     background: #FFF url([[pix:theme|top_bg]]) repeat-x center top;
     float: none;
index 670b1f0..05abd37 100644 (file)
@@ -49,12 +49,13 @@ echo $OUTPUT->doctype() ?>
     <div id="page-content">
         <table id="region-main-box" class="layout-table" summary="layout">
             <tr id="region-post-box">
+                <?php if ($hassidepre) { ?>
                 <td id="region-pre" class="block-region">
                     <div class="region-content">
                             <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
                     </div>
                 </td>
-                <?php if ($hassidepre) { ?>
+                <?php } ?>
                 <td id="region-main-wrap">
                     <div id="region-main">
                         <div class="region-content">
@@ -62,9 +63,7 @@ echo $OUTPUT->doctype() ?>
                         </div>
                     </div>
                 </td>
-                <?php
-                }
-                if ($hassidepost) { ?>
+                <?php if ($hassidepost) { ?>
                 <td id="region-post" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-post') ?>
index a379a9d..87cc2ca 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062503.04;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062503.05;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.3+ (Build: 20121203)'; // Human-friendly version name
+$release  = '2.3.3+ (Build: 20121208)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
index 7b006d6..4a6f2d0 100644 (file)
@@ -173,7 +173,8 @@ class core_webservice_external extends external_api {
                     new external_single_structure(
                         array(
                             'name' => new external_value(PARAM_RAW, 'function name'),
-                            'version' => new external_value(PARAM_FLOAT, 'The version number of moodle site/local plugin linked to the function')
+                            'version' => new external_value(PARAM_TEXT,
+                                        'The version number of the component to which the function belongs')
                         ), 'functions that are available')
                     ),
                 'downloadfiles'  => new external_value(PARAM_INT, '1 if users are allowed to download files, 0 if not', VALUE_OPTIONAL),
@@ -237,4 +238,4 @@ class moodle_webservice_external extends external_api {
     public static function get_siteinfo_returns() {
         return core_webservice_external::get_site_info_returns();
     }
-}
\ No newline at end of file
+}