Merge branch 'MDL-49543' of https://github.com/totara/openbadges
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 25 Mar 2015 00:32:34 +0000 (01:32 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 25 Mar 2015 00:32:34 +0000 (01:32 +0100)
123 files changed:
admin/registration/lib.php
admin/tool/behat/cli/init.php
admin/tool/behat/cli/run.php
blocks/activity_results/backup/moodle2/restore_activity_results_block_task.class.php [new file with mode: 0644]
blocks/activity_results/block_activity_results.php [new file with mode: 0644]
blocks/activity_results/db/access.php [new file with mode: 0644]
blocks/activity_results/edit_form.php [new file with mode: 0644]
blocks/activity_results/lang/en/block_activity_results.php [new file with mode: 0644]
blocks/activity_results/styles.css [new file with mode: 0644]
blocks/activity_results/tests/behat/addblockinactivity.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/addunconfiguredblock.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/addunsupportedactivity.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/highscoreswithoutgroups.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/highscoreswithseperategroups.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature [new file with mode: 0644]
blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature [new file with mode: 0644]
blocks/activity_results/version.php [new file with mode: 0644]
blocks/quiz_results/backup/moodle2/restore_quiz_results_block_task.class.php
blocks/quiz_results/block_quiz_results.php
blocks/quiz_results/db/install.php [new file with mode: 0644]
blocks/quiz_results/db/upgrade.php [new file with mode: 0644]
blocks/quiz_results/edit_form.php [deleted file]
blocks/quiz_results/lang/en/block_quiz_results.php
blocks/quiz_results/lang/en/depreciated.txt [new file with mode: 0644]
blocks/quiz_results/styles.css [deleted file]
blocks/quiz_results/version.php
calendar/lib.php
calendar/tests/behat/calendar.feature
completion/classes/external.php [new file with mode: 0644]
completion/tests/externallib_test.php [new file with mode: 0644]
composer.json
course/modedit.php
course/modlib.php
course/moodleform_mod.php
course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop-debug.js
course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop-min.js
course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop.js
course/yui/src/dragdrop/js/resource.js
enrol/paypal/lib.php
grade/grading/form/guide/lib.php
grade/grading/form/guide/tests/guide_test.php [new file with mode: 0644]
grade/report/user/styles.css
grade/tests/behat/grade_to_pass.feature [new file with mode: 0644]
lang/en/grades.php
lang/en/moodle.php
lib/classes/plugin_manager.php
lib/classes/task/scheduled_task.php
lib/coursecatlib.php
lib/db/services.php
lib/db/tasks.php
lib/db/upgrade.php
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/clean.js
lib/editor/atto/yui/src/editor/js/editor.js
lib/moodlelib.php
lib/tests/behat/behat_data_generators.php
lib/tests/regex_test.php [new file with mode: 0644]
lib/tests/scheduled_task_test.php
lib/yui/build/moodle-core-checknet/moodle-core-checknet-debug.js
lib/yui/build/moodle-core-checknet/moodle-core-checknet-min.js
lib/yui/build/moodle-core-checknet/moodle-core-checknet.js
lib/yui/src/checknet/js/checknet.js
mod/choice/backup/moodle2/backup_choice_stepslib.php
mod/choice/db/install.xml
mod/choice/db/upgrade.php
mod/choice/lang/en/choice.php
mod/choice/lib.php
mod/choice/mod_form.php
mod/choice/report.php
mod/choice/tests/behat/include_inactive.feature [new file with mode: 0644]
mod/choice/version.php
mod/choice/view.php
mod/data/classes/external.php [new file with mode: 0644]
mod/data/db/services.php [new file with mode: 0644]
mod/data/tests/externallib_test.php [new file with mode: 0644]
mod/data/version.php
mod/feedback/lib.php
mod/glossary/import.php
mod/glossary/lib.php
mod/imscp/lib.php
mod/imscp/tests/lib_test.php [new file with mode: 0644]
mod/imscp/view.php
mod/lesson/classes/event/lesson_restarted.php [new file with mode: 0644]
mod/lesson/classes/event/lesson_resumed.php [new file with mode: 0644]
mod/lesson/classes/event/page_moved.php [new file with mode: 0644]
mod/lesson/editpage.php
mod/lesson/lang/en/lesson.php
mod/lesson/locallib.php
mod/lesson/renderer.php
mod/lesson/tests/events_test.php
mod/lesson/version.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/tests/behat/quiz_reset.feature [new file with mode: 0644]
mod/scorm/locallib.php
mod/upgrade.txt
mod/workshop/lang/en/workshop.php
mod/workshop/lib.php
mod/workshop/mod_form.php
phpunit.xml.dist
theme/bootstrapbase/amd/build/bootstrap.min.js [new file with mode: 0644]
theme/bootstrapbase/amd/src/bootstrap.js [new file with mode: 0644]
theme/bootstrapbase/javascript/moodlebootstrap.js
theme/bootstrapbase/yui/build/moodle-theme_bootstrapbase-bootstrap/moodle-theme_bootstrapbase-bootstrap-debug.js [deleted file]
theme/bootstrapbase/yui/build/moodle-theme_bootstrapbase-bootstrap/moodle-theme_bootstrapbase-bootstrap-min.js [deleted file]
theme/bootstrapbase/yui/build/moodle-theme_bootstrapbase-bootstrap/moodle-theme_bootstrapbase-bootstrap.js [deleted file]
theme/bootstrapbase/yui/src/bootstrap/build.json [deleted file]
theme/bootstrapbase/yui/src/bootstrap/js/bootstrap.js [deleted file]
theme/bootstrapbase/yui/src/bootstrap/js/bootstrapcollapse.js [deleted file]
theme/bootstrapbase/yui/src/bootstrap/js/bootstrapdropdown.js [deleted file]
theme/bootstrapbase/yui/src/bootstrap/js/bootstrapengine.js [deleted file]
theme/bootstrapbase/yui/src/bootstrap/meta/bootstrap.json [deleted file]
theme/clean/layout/columns3.php
theme/yui_combo.php
user/externallib.php
user/messageselect.php
user/tests/externallib_test.php
webservice/externallib.php
webservice/tests/externallib_test.php

index 6aed437..5a521e1 100644 (file)
@@ -53,32 +53,30 @@ class registration_manager {
     public function cron() {
         global $CFG;
         if (extension_loaded('xmlrpc')) {
-            //check if the last registration cron update was less than a week ago
-            $lastcron = get_config('registration', 'crontime');
-            if ($lastcron === false or $lastcron < strtotime("-7 day")) { //set to a week, see MDL-23704
-                $function = 'hub_update_site_info';
-                require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
+            $function = 'hub_update_site_info';
+            require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
 
-                //update all hub where the site is registered on
-                $hubs = $this->get_registered_on_hubs();
-                foreach ($hubs as $hub) {
-                    //update the registration
-                    $siteinfo = $this->get_site_info($hub->huburl);
-                    $params = array('siteinfo' => $siteinfo);
-                    $serverurl = $hub->huburl . "/local/hub/webservice/webservices.php";
-                    $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
-                    try {
-                        $result = $xmlrpcclient->call($function, $params);
-                        $this->update_registeredhub($hub); // To update timemodified.
-                        mtrace(get_string('siteupdatedcron', 'hub', $hub->hubname));
-                    } catch (Exception $e) {
-                        $errorparam = new stdClass();
-                        $errorparam->errormessage = $e->getMessage();
-                        $errorparam->hubname = $hub->hubname;
-                        mtrace(get_string('errorcron', 'hub', $errorparam));
-                    }
+            // Update all hubs where the site is registered.
+            $hubs = $this->get_registered_on_hubs();
+            if (empty($hubs)) {
+                mtrace(get_string('registrationwarning', 'admin'));
+            }
+            foreach ($hubs as $hub) {
+                // Update the registration.
+                $siteinfo = $this->get_site_info($hub->huburl);
+                $params = array('siteinfo' => $siteinfo);
+                $serverurl = $hub->huburl . "/local/hub/webservice/webservices.php";
+                $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
+                try {
+                    $result = $xmlrpcclient->call($function, $params);
+                    $this->update_registeredhub($hub); // To update timemodified.
+                    mtrace(get_string('siteupdatedcron', 'hub', $hub->hubname));
+                } catch (Exception $e) {
+                    $errorparam = new stdClass();
+                    $errorparam->errormessage = $e->getMessage();
+                    $errorparam->hubname = $hub->hubname;
+                    mtrace(get_string('errorcron', 'hub', $errorparam));
                 }
-                set_config('crontime', time(), 'registration');
             }
         } else {
             mtrace(get_string('errorcronnoxmlrpc', 'hub'));
index 52f783f..d4300d9 100644 (file)
@@ -96,17 +96,23 @@ if ($options['parallel']) {
 $cwd = getcwd();
 $output = null;
 
+$installcomposer = true;
 // If behat dependencies not downloaded then do it first, else symfony/process can't be used.
 if ($options['parallel'] && !file_exists(__DIR__ . "/../../../../vendor/autoload.php")) {
-    $code = BEHAT_EXITCODE_COMPOSER;
-} else {
-    chdir(__DIR__);
-    exec("php $utilfile --diag $paralleloption", $output, $code);
+    $installcomposer = false;
+    testing_update_composer_dependencies();
 }
 
+chdir(__DIR__);
+exec("php $utilfile --diag $paralleloption", $output, $code);
+
 // Check if composer needs to be updated.
-if (($code == BEHAT_EXITCODE_INSTALL) || $code == BEHAT_EXITCODE_REINSTALL || $code == BEHAT_EXITCODE_COMPOSER) {
+if ($installcomposer &&
+        ($code == BEHAT_EXITCODE_INSTALL || $code == BEHAT_EXITCODE_REINSTALL || $code == BEHAT_EXITCODE_COMPOSER)) {
     testing_update_composer_dependencies();
+    // Check again for behat test site and see if it's install or re-install.
+    chdir(__DIR__);
+    exec("php $utilfile --diag $paralleloption", $output, $code);
 }
 
 if ($code == 0) {
@@ -137,16 +143,6 @@ if ($code == 0) {
         exit($code);
     }
 
-} else if ($code == BEHAT_EXITCODE_COMPOSER) {
-    // Missing Behat dependencies.
-    // Returning to admin/tool/behat/cli.
-    chdir(__DIR__);
-    passthru("php $utilfile --install $paralleloption", $code);
-    if ($code != 0) {
-        chdir($cwd);
-        exit($code);
-    }
-
 } else {
     // Generic error, we just output it.
     echo implode("\n", $output)."\n";
index 92c393c..4240747 100644 (file)
@@ -134,13 +134,19 @@ $tags = '';
 
 if ($options['profile']) {
     $profile = $options['profile'];
-    if (empty($CFG->behat_config[$profile]['filters']['tags'])) {
-        echo "Invaid profile passed: " . $profile;
+    if (!isset($CFG->behat_config[$profile])) {
+        echo "Invalid profile passed: " . $profile;
         exit(1);
     }
-    $tags = $CFG->behat_config[$profile]['filters']['tags'];
     $extraopts[] = '--profile=\'' . $profile . "'";
-} else if ($options['tags']) {
+    // By default, profile tags will be used.
+    if (!empty($CFG->behat_config[$profile]['filters']['tags'])) {
+        $tags = $CFG->behat_config[$profile]['filters']['tags'];
+    }
+}
+
+// Command line tags have precedence (std behat behavior).
+if ($options['tags']) {
     $tags = $options['tags'];
     $extraopts[] = '--tags="' . $tags . '"';
 }
diff --git a/blocks/activity_results/backup/moodle2/restore_activity_results_block_task.class.php b/blocks/activity_results/backup/moodle2/restore_activity_results_block_task.class.php
new file mode 100644 (file)
index 0000000..42be292
--- /dev/null
@@ -0,0 +1,115 @@
+<?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/>.
+
+/**
+ * Define all the backup steps that will be used by the backup_block_task
+ * @package    block_activity_results
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Specialised restore task for the activity_results block
+ * (using execute_after_tasks for recoding of target activity)
+ *
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class restore_activity_results_block_task extends restore_block_task {
+
+    /**
+     * Define (add) particular settings this activity can have
+     */
+    protected function define_my_settings() {
+    }
+
+    /**
+     * Define (add) particular steps this activity can have
+     */
+    protected function define_my_steps() {
+    }
+
+    /**
+     * Define the associated file areas
+     */
+    public function get_fileareas() {
+        return array(); // No associated fileareas.
+    }
+
+    /**
+     * Define special handling of configdata.
+     */
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata.
+    }
+
+    /**
+     * This function, executed after all the tasks in the plan
+     * have been executed, will perform the recode of the
+     * target activity for the block. This must be done here
+     * and not in normal execution steps because the activity
+     * can be restored after the block.
+     */
+    public function after_restore() {
+        global $DB;
+
+        // Get the blockid.
+        $blockid = $this->get_blockid();
+
+        if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
+            $config = unserialize(base64_decode($configdata));
+            if (!empty($config->activityparentid)) {
+                // Get the mapping and replace it in config.
+                if ($mapping = restore_dbops::get_backup_ids_record($this->get_restoreid(),
+                    $config->activityparent, $config->activityparentid)) {
+
+                    // Update the parent module id (the id from mdl_quiz etc...)
+                    $config->activityparentid = $mapping->newitemid;
+
+                    // Get the grade_items record to update the activitygradeitemid.
+                    $info = $DB->get_record('grade_items',
+                            array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
+
+                    // Update the activitygradeitemid the id from the grade_items table.
+                    $config->activitygradeitemid = $info->id;
+
+                    // Encode and save the config.
+                    $configdata = base64_encode(serialize($config));
+                    $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
+                }
+            }
+        }
+    }
+
+    /**
+     * Define the contents in the activity that must be
+     * processed by the link decoder
+     */
+    static public function define_decode_contents() {
+        return array();
+    }
+
+    /**
+     * Define the decoding rules for links belonging
+     * to the activity to be executed by the link decoder
+     */
+    static public function define_decode_rules() {
+        return array();
+    }
+}
diff --git a/blocks/activity_results/block_activity_results.php b/blocks/activity_results/block_activity_results.php
new file mode 100644 (file)
index 0000000..90cbf5f
--- /dev/null
@@ -0,0 +1,693 @@
+<?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/>.
+
+/**
+ * Classes to enforce the various access rules that can apply to a activity.
+ *
+ * @package    block_activity_results
+ * @copyright  2009 Tim Hunt
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/lib/grade/constants.php');
+
+define('B_ACTIVITYRESULTS_NAME_FORMAT_FULL', 1);
+define('B_ACTIVITYRESULTS_NAME_FORMAT_ID',   2);
+define('B_ACTIVITYRESULTS_NAME_FORMAT_ANON', 3);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_PCT', 1);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_FRA', 2);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_ABS', 3);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE', 4);
+
+/**
+ * Block activity_results class definition.
+ *
+ * This block can be added to a course page or a activity page to display of list of
+ * the best/worst students/groups in a particular activity.
+ *
+ * @package    block_activity_results
+ * @copyright  2009 Tim Hunt
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_activity_results extends block_base {
+
+    /**
+     * Core function used to initialize the block.
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_activity_results');
+    }
+
+    /**
+     * Core function, specifies where the block can be used.
+     * @return array
+     */
+    public function applicable_formats() {
+        return array('course-view' => true, 'mod' => true);
+    }
+
+    /**
+     * If this block belongs to a activity context, then return that activity's id.
+     * Otherwise, return 0.
+     * @return stdclass the activity record.
+     */
+    public function get_owning_activity() {
+        global $DB;
+
+        // Set some defaults.
+        $result = new stdClass();
+        $result->id = 0;
+
+        if (empty($this->instance->parentcontextid)) {
+            return $result;
+        }
+        $parentcontext = context::instance_by_id($this->instance->parentcontextid);
+        if ($parentcontext->contextlevel != CONTEXT_MODULE) {
+            return $result;
+        }
+        $cm = get_coursemodule_from_id($this->page->cm->modname, $parentcontext->instanceid);
+        if (!$cm) {
+            return $result;
+        }
+        // Get the grade_items id.
+        $rec = $DB->get_record('grade_items', array('iteminstance' => $cm->instance, 'itemmodule' => $this->page->cm->modname));
+        if (!$rec) {
+            return $result;
+        }
+        // See if it is a gradable activity.
+        if (($rec->gradetype != GRADE_TYPE_VALUE) || ($rec->gradetype != GRADE_TYPE_SCALE)) {
+            return $result;
+        }
+        return $rec;
+    }
+
+    /**
+     * Used to save the form config data
+     * @param stdclass $data
+     * @param bool $nolongerused
+     */
+    public function instance_config_save($data, $nolongerused = false) {
+        global $DB;
+        if (empty($data->activitygradeitemid)) {
+            // Figure out info about parent module.
+            $info = $this->get_owning_activity();
+            $data->activitygradeitemid = $info->id;
+            if ($info->id < 1) {
+                // No activity was selected.
+                $info->itemmodule = '';
+                $info->iteminstance = '';
+            } else {
+                $data->activityparent = $info->itemmodule;
+                $data->activityparentid = $info->iteminstance;
+            }
+        } else {
+            // Lookup info about the parent module (we have the id from mdl_grade_items.
+            $info = $DB->get_record('grade_items', array('id' => $data->activitygradeitemid));
+            $data->activityparent = $info->itemmodule;
+            $data->activityparentid = $info->iteminstance;
+        }
+        parent::instance_config_save($data);
+    }
+
+    /**
+     * Used to generate the content for the block.
+     * @return string
+     */
+    public function get_content() {
+        global $USER, $CFG, $DB;
+
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        // We are configured so use the configuration.
+        if (!empty($this->config->activitygradeitemid)) {
+            // We are configured.
+            $activitygradeitemid = $this->config->activitygradeitemid;
+
+            // Lookup the module in the grade_items table.
+            $activity = $DB->get_record('grade_items', array('id' => $activitygradeitemid));
+            if (empty($activity)) {
+                // Activity does not exist.
+                $this->content->text = get_string('error_emptyactivityrecord', 'block_activity_results');
+                return $this->content;
+            }
+            $courseid = $activity->courseid;
+            $inactivity = false;
+        } else {
+            // Not configured.
+            $activitygradeitemid = 0;
+        }
+
+        // Check to see if we are in the moule we are displaying results for.
+        if (!empty($this->config->activitygradeitemid)) {
+            if ($this->get_owning_activity()->id == $this->config->activitygradeitemid) {
+                $inactivity = true;
+            } else {
+                $inactivity = false;
+            }
+        }
+
+        // Activity ID is missing.
+        if (empty($activitygradeitemid)) {
+            $this->content->text = get_string('error_emptyactivityid', 'block_activity_results');
+            return $this->content;
+        }
+
+        // Check to see if we are configured.
+        if (empty($this->config->showbest) && empty($this->config->showworst)) {
+            $this->content->text = get_string('configuredtoshownothing', 'block_activity_results');
+            return $this->content;
+        }
+
+        // Check to see if it is a supported grade type.
+        if (empty($activity->gradetype) || ($activity->gradetype != GRADE_TYPE_VALUE && $activity->gradetype != GRADE_TYPE_SCALE)) {
+            $this->content->text = get_string('error_unsupportedgradetype', 'block_activity_results');
+            return $this->content;
+        }
+
+        // Get the grades for this activity.
+        $sql = 'SELECT * FROM {grade_grades}
+                 WHERE itemid = ? AND finalgrade is not NULL
+                 ORDER BY finalgrade, timemodified DESC';
+
+        $grades = $DB->get_records_sql($sql, array( $activitygradeitemid));
+
+        if (empty($grades) || $activity->hidden) {
+            // No grades available, The block will hide itself in this case.
+            return $this->content;
+        }
+
+        // Set up results.
+        $groupmode = NOGROUPS;
+        $best      = array();
+        $worst     = array();
+
+        if (!empty($this->config->nameformat)) {
+            $nameformat = $this->config->nameformat;
+        } else {
+            $nameformat = B_ACTIVITYRESULTS_NAME_FORMAT_FULL;
+        }
+
+        // Get $cm and context.
+        if ($inactivity) {
+            $cm = $this->page->cm;
+            $context = $this->page->context;
+        } else {
+            $cm = get_coursemodule_from_instance($activity->itemmodule, $activity->iteminstance, $courseid);
+            $context = context_module::instance($cm->id);
+        }
+
+        if (!empty($this->config->usegroups)) {
+            $groupmode = groups_get_activity_groupmode($cm);
+
+            if ($groupmode == SEPARATEGROUPS && has_capability('moodle/site:accessallgroups', $context)) {
+                // If you have the ability to see all groups then lets show them.
+                $groupmode = VISIBLEGROUPS;
+            }
+        }
+
+        switch ($groupmode) {
+            case VISIBLEGROUPS:
+                // Display group-mode results.
+                $groups = groups_get_all_groups($courseid);
+
+                if (empty($groups)) {
+                    // No groups exist, sorry.
+                    $this->content->text = get_string('error_nogroupsexist', 'block_activity_results');
+                    return $this->content;
+                }
+
+                // Find out all the userids which have a submitted grade.
+                $userids = array();
+                $gradeforuser = array();
+                foreach ($grades as $grade) {
+                    $userids[] = $grade->userid;
+                    $gradeforuser[$grade->userid] = (float)$grade->finalgrade;
+                }
+
+                // Now find which groups these users belong in.
+                list($usertest, $params) = $DB->get_in_or_equal($userids);
+                $params[] = $courseid;
+                $usergroups = $DB->get_records_sql('
+                        SELECT gm.id, gm.userid, gm.groupid, g.name
+                        FROM {groups} g
+                        LEFT JOIN {groups_members} gm ON g.id = gm.groupid
+                        WHERE gm.userid ' . $usertest . ' AND g.courseid = ?', $params);
+
+                // Now, iterate the grades again and sum them up for each group.
+                $groupgrades = array();
+                foreach ($usergroups as $usergroup) {
+                    if (!isset($groupgrades[$usergroup->groupid])) {
+                        $groupgrades[$usergroup->groupid] = array(
+                                'sum' => (float)$gradeforuser[$usergroup->userid],
+                                'number' => 1,
+                                'group' => $usergroup->name);
+                    } else {
+                        $groupgrades[$usergroup->groupid]['sum'] += $gradeforuser[$usergroup->userid];
+                        $groupgrades[$usergroup->groupid]['number'] += 1;
+                    }
+                }
+
+                foreach ($groupgrades as $groupid => $groupgrade) {
+                    $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
+                }
+
+                // Sort groupgrades according to average grade, ascending.
+                uasort($groupgrades, create_function('$a, $b',
+                        'if($a["average"] == $b["average"]) return 0; return ($a["average"] > $b["average"] ? 1 : -1);'));
+
+                // How many groups do we have with graded member submissions to show?
+                $numbest  = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades));
+                $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest);
+
+                // Collect all the group results we are going to use in $best and $worst.
+                $remaining = $numbest;
+                $groupgrade = end($groupgrades);
+                while ($remaining--) {
+                    $best[key($groupgrades)] = $groupgrade['average'];
+                    $groupgrade = prev($groupgrades);
+                }
+
+                $remaining = $numworst;
+                $groupgrade = reset($groupgrades);
+                while ($remaining--) {
+                    $worst[key($groupgrades)] = $groupgrade['average'];
+                    $groupgrade = next($groupgrades);
+                }
+
+                // Ready for output!
+                if ($activity->gradetype == GRADE_TYPE_SCALE) {
+                    // We must display the results using scales.
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE;
+                    // Preload the scale.
+                    $scale = $this->get_scale($activity->scaleid);
+                } else if (intval(empty($this->config->gradeformat))) {
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_PCT;
+                } else {
+                    $gradeformat = $this->config->gradeformat;
+                }
+
+                // Generate the header.
+                $this->content->text .= $this->activity_link($activity, $cm);
+
+                if ($nameformat == B_ACTIVITYRESULTS_NAME_FORMAT_FULL) {
+                    if (has_capability('moodle/course:managegroups', $context)) {
+                        $grouplink = $CFG->wwwroot.'/group/overview.php?id='.$courseid.'&amp;group=';
+                    } else if (has_capability('moodle/course:viewparticipants', $context)) {
+                        $grouplink = $CFG->wwwroot.'/user/index.php?id='.$courseid.'&amp;group=';
+                    } else {
+                        $grouplink = '';
+                    }
+                }
+
+                $rank = 0;
+                if (!empty($best)) {
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numbest == 1) {
+                        $this->content->text .= get_string('bestgroupgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('bestgroupgrades', 'block_activity_results', $numbest);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($best as $groupid => $averagegrade) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('group');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if ($grouplink) {
+                                    $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
+                                } else {
+                                    $thisname = $groupgrades[$groupid]['group'];
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($averagegrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($averagegrade)
+                                    . '/' . $this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($averagegrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                $this->content->text .= $this->activity_format_grade((float)$averagegrade /
+                                        (float)$activity->grademax * 100).'%';
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+
+                $rank = 0;
+                if (!empty($worst)) {
+                    $worst = array_reverse($worst, true);
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numworst == 1) {
+                        $this->content->text .= get_string('worstgroupgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('worstgroupgrades', 'block_activity_results', $numworst);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($worst as $groupid => $averagegrade) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('group');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if ($grouplink) {
+                                    $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
+                                } else {
+                                    $thisname = $groupgrades[$groupid]['group'];
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($averagegrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($averagegrade)
+                                    . '/' . $this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($averagegrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                $this->content->text .= $this->activity_format_grade((float)$averagegrade /
+                                        (float)$activity->grademax * 100).'%';
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+            break;
+
+            case SEPARATEGROUPS:
+                // This is going to be just like no-groups mode, only we 'll filter
+                // out the grades from people not in our group.
+                if (!isloggedin()) {
+                    // Not logged in, so show nothing.
+                    return $this->content;
+                }
+
+                $mygroups = groups_get_all_groups($courseid, $USER->id);
+                if (empty($mygroups)) {
+                    // Not member of a group, show nothing.
+                    return $this->content;
+                }
+
+                // Get users from the same groups as me.
+                list($grouptest, $params) = $DB->get_in_or_equal(array_keys($mygroups));
+                $mygroupsusers = $DB->get_records_sql_menu(
+                        'SELECT DISTINCT userid, 1 FROM {groups_members} WHERE groupid ' . $grouptest,
+                        $params);
+
+                // Filter out the grades belonging to other users, and proceed as if there were no groups.
+                foreach ($grades as $key => $grade) {
+                    if (!isset($mygroupsusers[$grade->userid])) {
+                        unset($grades[$key]);
+                    }
+                }
+
+                // No break, fall through to the default case now we have filtered the $grades array.
+            default:
+            case NOGROUPS:
+                // Single user mode.
+                $numbest  = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades));
+                $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest);
+
+                // Collect all the usernames we are going to need.
+                $remaining = $numbest;
+                $grade = end($grades);
+                while ($remaining--) {
+                    $best[$grade->userid] = $grade->id;
+                    $grade = prev($grades);
+                }
+
+                $remaining = $numworst;
+                $grade = reset($grades);
+                while ($remaining--) {
+                    $worst[$grade->userid] = $grade->id;
+                    $grade = next($grades);
+                }
+
+                if (empty($best) && empty($worst)) {
+                    // Nothing to show, for some reason...
+                    return $this->content;
+                }
+
+                // Now grab all the users from the database.
+                $userids = array_merge(array_keys($best), array_keys($worst));
+                $fields = array_merge(array('id', 'idnumber'), get_all_user_name_fields());
+                $fields = implode(',', $fields);
+                $users = $DB->get_records_list('user', 'id', $userids, '', $fields);
+
+                // Ready for output!
+                if ($activity->gradetype == GRADE_TYPE_SCALE) {
+                    // We must display the results using scales.
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE;
+                    // Preload the scale.
+                    $scale = $this->get_scale($activity->scaleid);
+                } else if (intval(empty($this->config->gradeformat))) {
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_PCT;
+                } else {
+                    $gradeformat = $this->config->gradeformat;
+                }
+
+                // Generate the header.
+                $this->content->text .= $this->activity_link($activity, $cm);
+
+                $rank = 0;
+                if (!empty($best)) {
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numbest == 1) {
+                        $this->content->text .= get_string('bestgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('bestgrades', 'block_activity_results', $numbest);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($best as $userid => $gradeid) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('user').' '.$users[$userid]->idnumber;
+                            break;
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                                $thisname = get_string('user');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if (has_capability('moodle/user:viewdetails', $context)) {
+                                    $thisname = html_writer::link(new moodle_url('/user/view.php',
+                                        array('id' => $userid, 'course' => $courseid)), fullname($users[$userid]));
+                                } else {
+                                    $thisname = fullname($users[$userid]);
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($grades[$gradeid]->finalgrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                                $this->content->text .= '/'.$this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                if ($activity->grademax) {
+                                    $this->content->text .= $this->activity_format_grade((float)$grades[$gradeid]->finalgrade /
+                                            (float)$activity->grademax * 100).'%';
+                                } else {
+                                    $this->content->text .= '--%';
+                                }
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+
+                $rank = 0;
+                if (!empty($worst)) {
+                    $worst = array_reverse($worst, true);
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numbest == 1) {
+                        $this->content->text .= get_string('worstgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('worstgrades', 'block_activity_results', $numworst);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($worst as $userid => $gradeid) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('user').' '.$users[$userid]->idnumber;
+                            break;
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                                $thisname = get_string('user');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if (has_capability('moodle/user:viewdetails', $context)) {
+                                    $thisname = html_writer::link(new moodle_url('/user/view.php',
+                                        array('id' => $userid, 'course' => $courseid)), fullname($users[$userid]));
+                                } else {
+                                    $thisname = fullname($users[$userid]);
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($grades[$gradeid]->finalgrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                                $this->content->text .= '/'.$this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                if ($activity->grademax) {
+                                    $this->content->text .= $this->activity_format_grade((float)$grades[$gradeid]->finalgrade /
+                                            (float)$activity->grademax * 100).'%';
+                                } else {
+                                    $this->content->text .= '--%';
+                                }
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+            break;
+        }
+
+        return $this->content;
+    }
+
+    /**
+     * Allows the block to be added multiple times to a single page
+     * @return boolean
+     */
+    public function instance_allow_multiple() {
+        return true;
+    }
+
+    /**
+     * Formats the grade to the specified decimal points
+     * @param float $grade
+     * @return string
+     */
+    private function activity_format_grade($grade) {
+        if (is_null($grade)) {
+            return get_string('notyetgraded', 'block_activity_results');
+        }
+        return format_float($grade, $this->config->decimalpoints);
+    }
+
+    /**
+     * Generates the Link to the activity module when displaed outside of the module
+     * @param stdclass $activity
+     * @param stdclass $cm
+     * @return string
+     */
+    private function activity_link($activity, $cm) {
+
+        $o = html_writer::start_tag('h3');
+        $o .= html_writer::link(new moodle_url('/mod/'.$activity->itemmodule.'/view.php',
+        array('id' => $cm->id)), $activity->itemname);
+        $o .= html_writer::end_tag('h3');
+        return $o;
+    }
+
+    /**
+     * Generates a numeric array of scale entries
+     * @param int $scaleid
+     * @return array
+     */
+    private function get_scale($scaleid) {
+        global $DB;
+        $scaletext = $DB->get_field('scale', 'scale', array('id' => $scaleid), IGNORE_MISSING);
+        $scale = explode ( ',', $scaletext);
+        return $scale;
+
+    }
+}
\ No newline at end of file
diff --git a/blocks/activity_results/db/access.php b/blocks/activity_results/db/access.php
new file mode 100644 (file)
index 0000000..70cdede
--- /dev/null
@@ -0,0 +1,41 @@
+<?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/>.
+
+/**
+ * Activity results block caps.
+ *
+ * @package    block_activity_results
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/activity_results:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/blocks/activity_results/edit_form.php b/blocks/activity_results/edit_form.php
new file mode 100644 (file)
index 0000000..0a07151
--- /dev/null
@@ -0,0 +1,104 @@
+<?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/>.
+
+/**
+ * Defines the form for editing Quiz results block instances.
+ *
+ * @package    block_activity_results
+ * @copyright  2009 Tim Hunt
+ * @copyright  2015 Stephen Bourget
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+require_once($CFG->dirroot . '/lib/grade/constants.php');
+
+/**
+ * Form for editing activity results block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @copyright 2015 Stephen Bourget
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_activity_results_edit_form extends block_edit_form {
+    /**
+     * The definition of the fields to use.
+     *
+     * @param MoodleQuickForm $mform
+     */
+    protected function specific_definition($mform) {
+        global $DB;
+
+        // Fields for editing activity_results block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        // Get supported modules (Only modules using grades or scales will be listed).
+        $sql = 'SELECT id, itemname FROM {grade_items} WHERE courseid = ? and itemtype = ? and (gradetype = ? or gradetype = ?)';
+        $params = array($this->page->course->id, 'mod', GRADE_TYPE_VALUE, GRADE_TYPE_SCALE);
+        $activities = $DB->get_records_sql_menu($sql, $params);
+
+        if (empty($activities)) {
+            $mform->addElement('static', 'noactivitieswarning', get_string('config_select_activity', 'block_activity_results'),
+                    get_string('config_no_activities_in_course', 'block_activity_results'));
+        } else {
+            foreach ($activities as $id => $name) {
+                $activities[$id] = strip_tags(format_string($name));
+            }
+            $mform->addElement('select', 'config_activitygradeitemid',
+                    get_string('config_select_activity', 'block_activity_results'), $activities);
+            $mform->setDefault('config_activitygradeitemid', $this->block->get_owning_activity()->id);
+        }
+
+        $mform->addElement('text', 'config_showbest',
+                get_string('config_show_best', 'block_activity_results'), array('size' => 3));
+        $mform->setDefault('config_showbest', 3);
+        $mform->setType('config_showbest', PARAM_INT);
+
+        $mform->addElement('text', 'config_showworst',
+                get_string('config_show_worst', 'block_activity_results'), array('size' => 3));
+        $mform->setDefault('config_showworst', 0);
+        $mform->setType('config_showworst', PARAM_INT);
+
+        $mform->addElement('selectyesno', 'config_usegroups', get_string('config_use_groups', 'block_activity_results'));
+
+        $nameoptions = array(
+            B_ACTIVITYRESULTS_NAME_FORMAT_FULL => get_string('config_names_full', 'block_activity_results'),
+            B_ACTIVITYRESULTS_NAME_FORMAT_ID => get_string('config_names_id', 'block_activity_results'),
+            B_ACTIVITYRESULTS_NAME_FORMAT_ANON => get_string('config_names_anon', 'block_activity_results')
+        );
+        $mform->addElement('select', 'config_nameformat',
+                get_string('config_name_format', 'block_activity_results'), $nameoptions);
+        $mform->setDefault('config_nameformat', B_ACTIVITYRESULTS_NAME_FORMAT_FULL);
+
+        $gradeeoptions = array(
+            B_ACTIVITYRESULTS_GRADE_FORMAT_PCT => get_string('config_format_percentage', 'block_activity_results'),
+            B_ACTIVITYRESULTS_GRADE_FORMAT_FRA => get_string('config_format_fraction', 'block_activity_results'),
+            B_ACTIVITYRESULTS_GRADE_FORMAT_ABS => get_string('config_format_absolute', 'block_activity_results')
+        );
+        $mform->addElement('select', 'config_gradeformat',
+                get_string('config_grade_format', 'block_activity_results'), $gradeeoptions);
+        $mform->setDefault('config_gradeformat', B_ACTIVITYRESULTS_GRADE_FORMAT_PCT);
+
+        $options = array();
+        for ($i = 0; $i <= 5; $i++) {
+            $options[$i] = $i;
+        }
+        $mform->addElement('select', 'config_decimalpoints', get_string('config_decimalplaces', 'block_activity_results'),
+                $options);
+        $mform->setDefault('config_decimalpoints', 2);
+        $mform->setType('config_decimalpoints', PARAM_INT);
+    }
+}
\ No newline at end of file
diff --git a/blocks/activity_results/lang/en/block_activity_results.php b/blocks/activity_results/lang/en/block_activity_results.php
new file mode 100644 (file)
index 0000000..7269799
--- /dev/null
@@ -0,0 +1,55 @@
+<?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/>.
+
+/**
+ * Strings for component 'block_activity_results', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package    block_activity_results
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['activity_results:addinstance'] = 'Add a new activity results block';
+$string['bestgrade'] = 'The highest grade:';
+$string['bestgrades'] = 'The {$a} highest grades:';
+$string['bestgroupgrade'] = 'The group with the highest average:';
+$string['bestgroupgrades'] = 'The {$a} groups with the highest average:';
+$string['config_format_absolute'] = 'Absolute numbers';
+$string['config_format_fraction'] = 'Fractions';
+$string['config_format_percentage'] = 'Percentages';
+$string['config_decimalplaces'] = 'Decimal places to display';
+$string['config_grade_format'] = 'Display grades as:';
+$string['config_name_format'] = 'Privacy level for displayed results:';
+$string['config_names_anon'] = 'Anonymous results';
+$string['config_names_full'] = 'Display full names';
+$string['config_names_id'] = 'Display only ID numbers';
+$string['config_no_activities_in_course'] = 'This course does not contain any activity activities . You must add at least one before you are able to use this block correctly.';
+$string['config_select_activity'] = 'Which activity should this block display results from?';
+$string['config_show_best'] = 'How many of the highest grades should be shown (0 to disable)?';
+$string['config_show_worst'] = 'How many of the lowest grades should be shown (0 to disable)?';
+$string['configuredtoshownothing'] = 'This block\'s configuration currently does not allow it to show any results. You may want to either configure it or hide it.';
+$string['config_use_groups'] = 'Show groups instead of students (only if the activity supports groups)?';
+$string['error_emptyactivityid'] = 'There is an error right now with this block: you need to select which activity it should display results from.';
+$string['error_emptyactivityrecord'] = 'There is an error right now with this block: the selected activity does not seem to exist in the database.';
+$string['error_nogroupsexist'] = 'There is an error right now with this block: it is set to display grades in group mode, but the course has no defined groups.';
+$string['error_unsupportedgradetype'] = 'There is an error right now with this block: The activity selected is configured to use a grading method that is not supported by this block.';
+$string['notyetgraded'] = 'Not yet graded';
+$string['pluginname'] = 'Activity results';
+$string['unknown'] = 'Unknown scale';
+$string['worstgrade'] = 'The lowest grade:';
+$string['worstgrades'] = 'The {$a} lowest grades:';
+$string['worstgroupgrade'] = 'The group with the lowest average:';
+$string['worstgroupgrades'] = 'The {$a} groups with the lowest average:';
diff --git a/blocks/activity_results/styles.css b/blocks/activity_results/styles.css
new file mode 100644 (file)
index 0000000..39ea1cc
--- /dev/null
@@ -0,0 +1,6 @@
+.block_activity_results {text-align: center;}
+.block_activity_results h1 {margin: 4px;font-size: 1.1em;}
+.block_activity_results table.grades {text-align: left;width: 100%;}
+.block_activity_results table.grades .number{text-align: right;width:10%;}
+.block_activity_results table.grades .grade {text-align: right;}
+.block_activity_results table.grades caption {margin: 1em 0px 0px 0px;border-bottom-width: 1px;border-bottom-style: solid;font-weight: bold;}
diff --git a/blocks/activity_results/tests/behat/addblockinactivity.feature b/blocks/activity_results/tests/behat/addblockinactivity.feature
new file mode 100644 (file)
index 0000000..189aaaa
--- /dev/null
@@ -0,0 +1,66 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+
+Scenario: Configure the block on a non-graded activity to show 3 high scores
+    Given I add a "Page" to section "1"
+    And I set the following fields to these values:
+      | Name | Test page name |
+      | Description | Test page description |
+      | page | This is a page |
+    And I press "Save and display"
+    When I add the "Activity results" block
+    And I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_activitygradeitemid | Test assignment |
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/tests/behat/addunconfiguredblock.feature b/blocks/activity_results/tests/behat/addunconfiguredblock.feature
new file mode 100644 (file)
index 0000000..b27874d
--- /dev/null
@@ -0,0 +1,43 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+
+  Scenario: Add the block to a the course
+    Given I add the "Activity results" block
+    Then I should see "There is an error right now with this block: you need to select which activity it should display results from." in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page in a course without activities
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I should see "This course does not contain any activity activities . You must add at least one before you are able to use this block correctly."
+    And I press "Save changes"
+    Then I should see "There is an error right now with this block: you need to select which activity it should display results from." in the "Activity results" "block"
+
+  Scenario: Try to configure the block on a resource page in a course without activities
+    Given I add a "Page" to section "1"
+    And I set the following fields to these values:
+      | Name | Test page name |
+      | Description | Test page description |
+      | page | This is a page |
+    And I press "Save and display"
+    When I add the "Activity results" block
+    And I configure the "Activity results" block
+    And I should see "This course does not contain any activity activities . You must add at least one before you are able to use this block correctly."
+    And I press "Save changes"
+    Then I should see "There is an error right now with this block: you need to select which activity it should display results from." in the "Activity results" "block"
diff --git a/blocks/activity_results/tests/behat/addunsupportedactivity.feature b/blocks/activity_results/tests/behat/addunsupportedactivity.feature
new file mode 100644 (file)
index 0000000..e77a8b8
--- /dev/null
@@ -0,0 +1,40 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to properly configure the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+
+  Scenario: Try to configure the block to use an activity without grades
+    Given I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I follow "C1"
+    And I add the "Activity results" block
+    And I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    When I follow "Test assignment"
+    And I click on "Edit settings" "link" in the "Administration" "block"
+    And I set the following fields to these values:
+      | id_modgrade_type | None |
+    And I press "Save and return to course"
+    Then I should see "There is an error right now with this block: The activity selected is configured to use a grading method that is not supported by this block." in the "Activity results" "block"
diff --git a/blocks/activity_results/tests/behat/highscoreswithoutgroups.feature b/blocks/activity_results/tests/behat/highscoreswithoutgroups.feature
new file mode 100644 (file)
index 0000000..d1a6d20
--- /dev/null
@@ -0,0 +1,170 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+
+  Scenario: Configure the block on the course page to show 0 high scores
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "This block's configuration currently does not allow it to show any results." in the "Activity results" "block"
+
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90%" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80%" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80.00/100.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "User S1" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "80.00%" in the "Activity results" "block"
+    And I should see "User S3" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+    And I press "Save changes"
+    Then I should see "User" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+    And I should see "80.00%" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/tests/behat/highscoreswithseperategroups.feature b/blocks/activity_results/tests/behat/highscoreswithseperategroups.feature
new file mode 100644 (file)
index 0000000..e6e7063
--- /dev/null
@@ -0,0 +1,433 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+      | student6 | Student | 6 | student6@asd.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+
+  @javascript
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 high score as a fraction
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores as percentages
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100%" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "90%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores as fractions
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student3"
+    And I follow "Course 1"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "80.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "User S1" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "User" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature b/blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature
new file mode 100644 (file)
index 0000000..ff6ee62
--- /dev/null
@@ -0,0 +1,410 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+      | student6 | Student | 6 | student6@asd.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+
+  @javascript
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 high score as a fraction
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores as percentages
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores as fractions
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature b/blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature
new file mode 100644 (file)
index 0000000..998eec5
--- /dev/null
@@ -0,0 +1,159 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a absolute number
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50%" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "60%" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00/100.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "60.00/100.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "60.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "User S5" in the "Activity results" "block"
+    And I should see "50.00%" in the "Activity results" "block"
+    And I should see "User S4" in the "Activity results" "block"
+    And I should see "60.00%" in the "Activity results" "block"
+    And I should see "User S3" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+    And I press "Save changes"
+    Then I should see "User" in the "Activity results" "block"
+    And I should see "50.00%" in the "Activity results" "block"
+    And I should see "60.00%" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature b/blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature
new file mode 100644 (file)
index 0000000..876119b
--- /dev/null
@@ -0,0 +1,425 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+      | student6 | Student | 6 | student6@asd.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+
+  @javascript
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 low score as a fraction
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I follow "Course 1"
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I follow "Course 1"
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores as percentages
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I follow "Course 1"
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70%" in the "Activity results" "block"
+    And I should see "Student 5" in the "Activity results" "block"
+    And I should see "80%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores as fractions
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student3"
+    And I follow "Course 1"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "80.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I follow "Course 1"
+    And I should see "Student 5" in the "Activity results" "block"
+    And I should see "80.00" in the "Activity results" "block"
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "User S1" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "User" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature b/blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature
new file mode 100644 (file)
index 0000000..4c629fa
--- /dev/null
@@ -0,0 +1,406 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@asd.com | T1 |
+      | student1 | Student | 1 | student1@asd.com | S1 |
+      | student2 | Student | 2 | student2@asd.com | S2 |
+      | student3 | Student | 3 | student3@asd.com | S3 |
+      | student4 | Student | 4 | student4@asd.com | S4 |
+      | student5 | Student | 5 | student5@asd.com | S5 |
+      | student6 | Student | 6 | student6@asd.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+
+  @javascript
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 low score as a fraction
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores as percentages
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I follow "Course 1"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores as fractions
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+
+  @javascript
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I expand "Users" node
+    And I follow "Groups"
+    And I add "Student 1 (student1@asd.com)" user to "Group 1" group members
+    And I add "Student 2 (student2@asd.com)" user to "Group 1" group members
+    And I add "Student 3 (student3@asd.com)" user to "Group 2" group members
+    And I add "Student 4 (student4@asd.com)" user to "Group 2" group members
+    And I add "Student 5 (student5@asd.com)" user to "Group 3" group members
+    And I add "Student 6 (student6@asd.com)" user to "Group 3" group members
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I follow "Course 1"
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
\ No newline at end of file
diff --git a/blocks/activity_results/version.php b/blocks/activity_results/version.php
new file mode 100644 (file)
index 0000000..96b0dc8
--- /dev/null
@@ -0,0 +1,29 @@
+<?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/>.
+
+/**
+ * Version information for the block_quiz_results plugin.
+ *
+ * @package    block_activity_results
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2014111000;               // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2014110400;               // Requires this Moodle version.
+$plugin->component = 'block_activity_results'; // Full name of the plugin (used for diagnostics).
\ No newline at end of file
index 36c5407..548eea3 100644 (file)
@@ -57,18 +57,36 @@ class restore_quiz_results_block_task extends restore_block_task {
     public function after_restore() {
         global $DB;
 
-        // Get the blockid
+        // Get the blockid.
         $blockid = $this->get_blockid();
 
-        // Extract block configdata and update it to point to the new quiz
+        // Extract block configdata and update it to point to the new quiz.
         if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
             $config = unserialize(base64_decode($configdata));
             if (!empty($config->quizid)) {
-                // Get quiz mapping and replace it in config
+                // Get quiz mapping and replace it in config.
                 if ($quizmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'quiz', $config->quizid)) {
-                    $config->quizid = $quizmap->newitemid;
-                    $configdata = base64_encode(serialize($config));
-                    $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
+                    $config->activityparent = 'quiz';
+                    $config->activityparentid = $quizmap->newitemid;
+
+                    // Set the decimal valuue as appropriate.
+                    if ($config->gradeformat == 1) {
+                        // This block is using percentages, do not display any decimal places.
+                        $config->decimalpoints = 0;
+                    } else {
+                        // Get the decimal value from the corresponding quiz.
+                        $config->decimalpoints = $DB->get_field('quiz', 'decimalpoints', array('id' => $config->activityparentid));
+                    }
+
+                    // Get the grade_items record to set the activitygradeitemid.
+                    $info = $DB->get_record('grade_items',
+                            array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
+                    $config->activitygradeitemid = $info->id;
+                    unset($config->quizid);
+
+                    // Save the new configuration and update the record.
+                    $DB->set_field('block_instances', 'configdata', base64_encode(serialize($config)), array('id' => $blockid));
+                    $DB->set_field('block_instances', 'blockname', 'activity_results', array('id' => $blockid));
                 }
             }
         }
index 137a62b..3d7d649 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-
 defined('MOODLE_INTERNAL') || die();
 
 require_once($CFG->dirroot . '/mod/quiz/lib.php');
 
-
 /**
  * Block quiz_results class definition.
  *
@@ -38,441 +36,25 @@ require_once($CFG->dirroot . '/mod/quiz/lib.php');
  * @copyright  2009 Tim Hunt
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-define('B_QUIZRESULTS_NAME_FORMAT_FULL', 1);
-define('B_QUIZRESULTS_NAME_FORMAT_ID',   2);
-define('B_QUIZRESULTS_NAME_FORMAT_ANON', 3);
-define('B_QUIZRESULTS_GRADE_FORMAT_PCT', 1);
-define('B_QUIZRESULTS_GRADE_FORMAT_FRA', 2);
-define('B_QUIZRESULTS_GRADE_FORMAT_ABS', 3);
-
 class block_quiz_results extends block_base {
     function init() {
         $this->title = get_string('pluginname', 'block_quiz_results');
     }
 
     function applicable_formats() {
-        return array('course' => true, 'mod-quiz' => true);
-    }
-
-    /**
-     * If this block belongs to a quiz context, then return that quiz's id.
-     * Otherwise, return 0.
-     * @return integer the quiz id.
-     */
-    public function get_owning_quiz() {
-        if (empty($this->instance->parentcontextid)) {
-            return 0;
-        }
-        $parentcontext = context::instance_by_id($this->instance->parentcontextid);
-        if ($parentcontext->contextlevel != CONTEXT_MODULE) {
-            return 0;
-        }
-        $cm = get_coursemodule_from_id('quiz', $parentcontext->instanceid);
-        if (!$cm) {
-            return 0;
-        }
-        return $cm->instance;
+        return array('mod-quiz' => true);
     }
 
     function instance_config_save($data, $nolongerused = false) {
-        if (empty($data->quizid)) {
-            $data->quizid = $this->get_owning_quiz();
-        }
         parent::instance_config_save($data);
     }
 
     function get_content() {
-        global $USER, $CFG, $DB;
-
-        if ($this->content !== NULL) {
-            return $this->content;
-        }
-
-        $this->content = new stdClass;
-        $this->content->text = '';
-        $this->content->footer = '';
-
-        if (empty($this->instance)) {
-            return $this->content;
-        }
-
-        if ($this->page->activityname == 'quiz' && $this->page->context->id == $this->instance->parentcontextid) {
-            $quiz = $this->page->activityrecord;
-            $quizid = $quiz->id;
-            $courseid = $this->page->course->id;
-            $inquiz = true;
-        } else if (!empty($this->config->quizid)) {
-            $quizid = $this->config->quizid;
-            $quiz = $DB->get_record('quiz', array('id' => $quizid));
-            if (empty($quiz)) {
-                $this->content->text = get_string('error_emptyquizrecord', 'block_quiz_results');
-                return $this->content;
-            }
-            $courseid = $quiz->course;
-            $inquiz = false;
-        } else {
-            $quizid = 0;
-        }
-
-        if (empty($quizid)) {
-            $this->content->text = get_string('error_emptyquizid', 'block_quiz_results');
-            return $this->content;
-        }
-
-        if (empty($this->config->showbest) && empty($this->config->showworst)) {
-            $this->content->text = get_string('configuredtoshownothing', 'block_quiz_results');
-            return $this->content;
-        }
-
-        // Get the grades for this quiz
-        $grades = $DB->get_records('quiz_grades', array('quiz' => $quizid), 'grade, timemodified DESC');
-
-        if (empty($grades)) {
-            // No grades, sorry
-            // The block will hide itself in this case
-            return $this->content;
-        }
-
-        $groupmode = NOGROUPS;
-        $best      = array();
-        $worst     = array();
-
-        if (!empty($this->config->nameformat)) {
-            $nameformat = $this->config->nameformat;
-        } else {
-            $nameformat = B_QUIZRESULTS_NAME_FORMAT_FULL;
-        }
-
-        if (!empty($this->config->usegroups)) {
-            if ($inquiz) {
-                $cm = $this->page->cm;
-                $context = $this->page->context;
-            } else {
-                $cm = get_coursemodule_from_instance('quiz', $quizid, $courseid);
-                $context = context_module::instance($cm->id);
-            }
-            $groupmode = groups_get_activity_groupmode($cm);
-
-            if ($groupmode == SEPARATEGROUPS && has_capability('moodle/site:accessallgroups', $context)) {
-                // We 'll make an exception in this case
-                $groupmode = VISIBLEGROUPS;
-            }
-        }
-
-        switch ($groupmode) {
-            case VISIBLEGROUPS:
-            // Display group-mode results
-            $groups = groups_get_all_groups($courseid);
-
-            if(empty($groups)) {
-                // No groups exist, sorry
-                $this->content->text = get_string('error_nogroupsexist', 'block_quiz_results');
-                return $this->content;
-            }
-
-            // Find out all the userids which have a submitted grade
-            $userids = array();
-            $gradeforuser = array();
-            foreach ($grades as $grade) {
-                $userids[] = $grade->userid;
-                $gradeforuser[$grade->userid] = (float)$grade->grade;
-            }
-
-            // Now find which groups these users belong in
-            list($usertest, $params) = $DB->get_in_or_equal($userids);
-            $params[] = $courseid;
-            $usergroups = $DB->get_records_sql('
-                    SELECT gm.id, gm.userid, gm.groupid, g.name
-                    FROM {groups} g
-                    LEFT JOIN {groups_members} gm ON g.id = gm.groupid
-                    WHERE gm.userid ' . $usertest . ' AND g.courseid = ?', $params);
-
-            // Now, iterate the grades again and sum them up for each group
-            $groupgrades = array();
-            foreach ($usergroups as $usergroup) {
-                if (!isset($groupgrades[$usergroup->groupid])) {
-                    $groupgrades[$usergroup->groupid] = array(
-                            'sum' => (float)$gradeforuser[$usergroup->userid],
-                            'number' => 1,
-                            'group' => $usergroup->name);
-                } else {
-                    $groupgrades[$usergroup->groupid]['sum'] += $gradeforuser[$usergroup->userid];
-                    $groupgrades[$usergroup->groupid]['number'] += 1;
-                }
-            }
-
-            foreach($groupgrades as $groupid => $groupgrade) {
-                $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
-            }
-
-            // Sort groupgrades according to average grade, ascending
-            uasort($groupgrades, create_function('$a, $b', 'if($a["average"] == $b["average"]) return 0; return ($a["average"] > $b["average"] ? 1 : -1);'));
-
-            // How many groups do we have with graded member submissions to show?
-            $numbest  = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades));
-            $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest);
-
-            // Collect all the group results we are going to use in $best and $worst
-            $remaining = $numbest;
-            $groupgrade = end($groupgrades);
-            while ($remaining--) {
-                $best[key($groupgrades)] = $groupgrade['average'];
-                $groupgrade = prev($groupgrades);
-            }
-
-            $remaining = $numworst;
-            $groupgrade = reset($groupgrades);
-            while ($remaining--) {
-                $worst[key($groupgrades)] = $groupgrade['average'];
-                $groupgrade = next($groupgrades);
-            }
-
-            // Ready for output!
-            $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat);
-
-            if (!$inquiz) {
-                // Don't show header and link to the quiz if we ARE at the quiz...
-                $this->content->text .= '<h1><a href="'.$CFG->wwwroot.'/mod/quiz/view.php?q='.$quizid.'">'.$quiz->name.'</a></h1>';
-            }
-
-            if ($nameformat = B_QUIZRESULTS_NAME_FORMAT_FULL) {
-                if (has_capability('moodle/course:managegroups', $context)) {
-                    $grouplink = $CFG->wwwroot.'/group/overview.php?id='.$courseid.'&amp;group=';
-                } else if (has_capability('moodle/course:viewparticipants', $context)) {
-                    $grouplink = $CFG->wwwroot.'/user/index.php?id='.$courseid.'&amp;group=';
-                } else {
-                    $grouplink = '';
-                }
-            }
-
-            $rank = 0;
-            if(!empty($best)) {
-                $this->content->text .= '<table class="grades"><caption>';
-                $this->content->text .= ($numbest == 1?get_string('bestgroupgrade', 'block_quiz_results'):get_string('bestgroupgrades', 'block_quiz_results', $numbest));
-                $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
-                foreach($best as $groupid => $averagegrade) {
-                    switch($nameformat) {
-                        case B_QUIZRESULTS_NAME_FORMAT_ANON:
-                        case B_QUIZRESULTS_NAME_FORMAT_ID:
-                            $thisname = get_string('group');
-                        break;
-                        default:
-                        case B_QUIZRESULTS_NAME_FORMAT_FULL:
-                            if ($grouplink) {
-                                $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
-                            } else {
-                                $thisname = $groupgrades[$groupid]['group'];
-                            }
-                        break;
-                    }
-                    $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
-                    switch($gradeformat) {
-                        case B_QUIZRESULTS_GRADE_FORMAT_FRA:
-                            $this->content->text .= quiz_format_grade($quiz, $averagegrade).'/'.$quiz->grade;
-                        break;
-                        case B_QUIZRESULTS_GRADE_FORMAT_ABS:
-                            $this->content->text .= quiz_format_grade($quiz, $averagegrade);
-                        break;
-                        default:
-                        case B_QUIZRESULTS_GRADE_FORMAT_PCT:
-                            $this->content->text .= round((float)$averagegrade / (float)$quiz->grade * 100).'%';
-                        break;
-                    }
-                    $this->content->text .= '</td></tr>';
-                }
-                $this->content->text .= '</tbody></table>';
-            }
-
-            $rank = 0;
-            if(!empty($worst)) {
-                $worst = array_reverse($worst, true);
-                $this->content->text .= '<table class="grades"><caption>';
-                $this->content->text .= ($numworst == 1?get_string('worstgroupgrade', 'block_quiz_results'):get_string('worstgroupgrades', 'block_quiz_results', $numworst));
-                $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
-                foreach($worst as $groupid => $averagegrade) {
-                    switch($nameformat) {
-                        case B_QUIZRESULTS_NAME_FORMAT_ANON:
-                        case B_QUIZRESULTS_NAME_FORMAT_ID:
-                            $thisname = get_string('group');
-                        break;
-                        default:
-                        case B_QUIZRESULTS_NAME_FORMAT_FULL:
-                            $thisname = '<a href="'.$CFG->wwwroot.'/course/group.php?group='.$groupid.'&amp;id='.$courseid.'">'.$groupgrades[$groupid]['group'].'</a>';
-                        break;
-                    }
-                    $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
-                    switch($gradeformat) {
-                        case B_QUIZRESULTS_GRADE_FORMAT_FRA:
-                            $this->content->text .= quiz_format_grade($quiz, $averagegrade).'/'.$quiz->grade;
-                        break;
-                        case B_QUIZRESULTS_GRADE_FORMAT_ABS:
-                            $this->content->text .= quiz_format_grade($quiz, $averagegrade);
-                        break;
-                        default:
-                        case B_QUIZRESULTS_GRADE_FORMAT_PCT:
-                            $this->content->text .= round((float)$averagegrade / (float)$quiz->grade * 100).'%';
-                        break;
-                    }
-                    $this->content->text .= '</td></tr>';
-                }
-                $this->content->text .= '</tbody></table>';
-            }
-            break;
-
-
-            case SEPARATEGROUPS:
-            // This is going to be just like no-groups mode, only we 'll filter
-            // out the grades from people not in our group.
-            if (!isloggedin()) {
-                // Not logged in, so show nothing
-                return $this->content;
-            }
-
-            $mygroups = groups_get_all_groups($courseid, $USER->id);
-            if(empty($mygroups)) {
-                // Not member of a group, show nothing
-                return $this->content;
-            }
-
-            // Get users from the same groups as me.
-            list($grouptest, $params) = $DB->get_in_or_equal(array_keys($mygroups));
-            $mygroupsusers = $DB->get_records_sql_menu(
-                    'SELECT DISTINCT userid, 1 FROM {groups_members} WHERE groupid ' . $grouptest,
-                    $params);
-
-            // Filter out the grades belonging to other users, and proceed as if there were no groups
-            foreach ($grades as $key => $grade) {
-                if (!isset($mygroupsusers[$grade->userid])) {
-                    unset($grades[$key]);
-                }
-            }
-
-            // No break, fall through to the default case now we have filtered the $grades array.
-            default:
-            case NOGROUPS:
-            // Single user mode
-            $numbest  = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades));
-            $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest);
-
-            // Collect all the usernames we are going to need
-            $remaining = $numbest;
-            $grade = end($grades);
-            while($remaining--) {
-                $best[$grade->userid] = $grade->id;
-                $grade = prev($grades);
-            }
-
-            $remaining = $numworst;
-            $grade = reset($grades);
-            while($remaining--) {
-                $worst[$grade->userid] = $grade->id;
-                $grade = next($grades);
-            }
-
-            if(empty($best) && empty($worst)) {
-                // Nothing to show, for some reason...
-                return $this->content;
-            }
-
-            // Now grab all the users from the database
-            $userids = array_merge(array_keys($best), array_keys($worst));
-            $fields = array_merge(array('id', 'idnumber'), get_all_user_name_fields());
-            $fields = implode(',', $fields);
-            $users = $DB->get_records_list('user', 'id', $userids, '', $fields);
-
-            // Ready for output!
-
-            $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat);
-
-            if(!$inquiz) {
-                // Don't show header and link to the quiz if we ARE at the quiz...
-                $this->content->text .= '<h1><a href="'.$CFG->wwwroot.'/mod/quiz/view.php?q='.$quizid.'">'.$quiz->name.'</a></h1>';
-            }
-
-            $rank = 0;
-            if(!empty($best)) {
-                $this->content->text .= '<table class="grades"><caption>';
-                $this->content->text .= ($numbest == 1?get_string('bestgrade', 'block_quiz_results'):get_string('bestgrades', 'block_quiz_results', $numbest));
-                $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
-                foreach($best as $userid => $gradeid) {
-                    switch($nameformat) {
-                        case B_QUIZRESULTS_NAME_FORMAT_ID:
-                            $thisname = get_string('user').' '.$users[$userid]->idnumber;
-                        break;
-                        case B_QUIZRESULTS_NAME_FORMAT_ANON:
-                            $thisname = get_string('user');
-                        break;
-                        default:
-                        case B_QUIZRESULTS_NAME_FORMAT_FULL:
-                            $thisname = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'&amp;course='.$courseid.'">'.fullname($users[$userid]).'</a>';
-                        break;
-                    }
-                    $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
-                    switch($gradeformat) {
-                        case B_QUIZRESULTS_GRADE_FORMAT_FRA:
-                            $this->content->text .=  quiz_format_grade($quiz, $grades[$gradeid]->grade).'/'.$quiz->grade;
-                        break;
-                        case B_QUIZRESULTS_GRADE_FORMAT_ABS:
-                            $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade);
-                        break;
-                        default:
-                        case B_QUIZRESULTS_GRADE_FORMAT_PCT:
-                            if ($quiz->grade) {
-                                $this->content->text .= round((float)$grades[$gradeid]->grade / (float)$quiz->grade * 100).'%';
-                            } else {
-                                $this->content->text .= '--%';
-                            }
-                        break;
-                    }
-                    $this->content->text .= '</td></tr>';
-                }
-                $this->content->text .= '</tbody></table>';
-            }
-
-            $rank = 0;
-            if(!empty($worst)) {
-                $worst = array_reverse($worst, true);
-                $this->content->text .= '<table class="grades"><caption>';
-                $this->content->text .= ($numworst == 1?get_string('worstgrade', 'block_quiz_results'):get_string('worstgrades', 'block_quiz_results', $numworst));
-                $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
-                foreach($worst as $userid => $gradeid) {
-                    switch($nameformat) {
-                        case B_QUIZRESULTS_NAME_FORMAT_ID:
-                            $thisname = get_string('user').' '.$users[$userid]->idnumber;
-                        break;
-                        case B_QUIZRESULTS_NAME_FORMAT_ANON:
-                            $thisname = get_string('user');
-                        break;
-                        default:
-                        case B_QUIZRESULTS_NAME_FORMAT_FULL:
-                            $thisname = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'&amp;course='.$courseid.'">'.fullname($users[$userid]).'</a>';
-                        break;
-                    }
-                    $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
-                    switch($gradeformat) {
-                        case B_QUIZRESULTS_GRADE_FORMAT_FRA:
-                            $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade).'/'.$quiz->grade;
-                        break;
-                        case B_QUIZRESULTS_GRADE_FORMAT_ABS:
-                            $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade);
-                        break;
-                        default:
-                        case B_QUIZRESULTS_GRADE_FORMAT_PCT:
-                            $this->content->text .= round((float)$grades[$gradeid]->grade / (float)$quiz->grade * 100).'%';
-                        break;
-                    }
-                    $this->content->text .= '</td></tr>';
-                }
-                $this->content->text .= '</tbody></table>';
-            }
-            break;
-        }
-
         return $this->content;
     }
 
     function instance_allow_multiple() {
-        return true;
+        return false;
     }
 }
 
diff --git a/blocks/quiz_results/db/install.php b/blocks/quiz_results/db/install.php
new file mode 100644 (file)
index 0000000..255cdba
--- /dev/null
@@ -0,0 +1,31 @@
+<?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/>.
+
+/**
+ * Quiz results block installation.
+ *
+ * @package    block_quiz_results
+ * @copyright  2015 Dan Poltawski <dan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+function xmldb_block_quiz_results_install() {
+    global $DB;
+
+    // Disable quiz_results on new installs (its now just a stub).
+    $DB->set_field('block', 'visible', 0, array('name' => 'quiz_results'));
+}
+
diff --git a/blocks/quiz_results/db/upgrade.php b/blocks/quiz_results/db/upgrade.php
new file mode 100644 (file)
index 0000000..a729e4e
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the quiz_results block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.9
+ * @package block_quiz_results
+ * @copyright 2015 Stephen Bourget
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Upgrade the quiz_results block
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_quiz_results_upgrade($oldversion, $block) {
+    global $DB, $CFG;
+
+    if ($oldversion < 2015022200) {
+        // Only migrate if the block_activity_results is installed.
+        if (!check_dir_exists($CFG->dirroot . '/blocks/activity_results', false)) {
+
+            // Migrate all instances of block_quiz_results to block_activity_results.
+            $records = $DB->get_records('block_instances', array('blockname' => 'quiz_results'));
+            foreach ($records as $record) {
+                $config = unserialize(base64_decode($record->configdata));
+                $config->activityparent = 'quiz';
+                $config->activityparentid = $config->quizid;
+
+                // Set the decimal valuue as appropriate.
+                if ($config->gradeformat == 1) {
+                    // This block is using percentages, do not display any decimal places.
+                    $config->decimalpoints = 0;
+                } else {
+                    // Get the decimal value from the corresponding quiz.
+                    $config->decimalpoints = $DB->get_field('quiz', 'decimalpoints', array('id' => $config->activityparentid));
+                }
+
+                // Get the grade_items record to set the activitygradeitemid.
+                $info = $DB->get_record('grade_items',
+                        array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
+                $config->activitygradeitemid = $info->id;
+                unset($config->quizid);
+
+                // Save the new configuration and update the record.
+                $record->configdata = base64_encode(serialize($config));
+                $record->blockname = 'activity_results';
+                $DB->update_record('block_instances', $record);
+            }
+
+            // Disable the Quiz_results block.
+            if ($block = $DB->get_record("block", array("name" => "quiz_results"))) {
+                $DB->set_field("block", "visible", "0", array("id" => $block->id));
+            }
+
+        }
+        upgrade_block_savepoint(true, 2015022200, 'quiz_results');
+    }
+
+    // Moodle v2.8.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
\ No newline at end of file
diff --git a/blocks/quiz_results/edit_form.php b/blocks/quiz_results/edit_form.php
deleted file mode 100644 (file)
index bddb705..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Defines the form for editing Quiz results block instances.
- *
- * @package    block_quiz_results
- * @copyright 2009 Tim Hunt
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-
-/**
- * Form for editing Quiz results block instances.
- *
- * @copyright 2009 Tim Hunt
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class block_quiz_results_edit_form extends block_edit_form {
-    protected function specific_definition($mform) {
-        global $DB;
-
-        // Fields for editing HTML block title and contents.
-        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
-
-        if (!$this->block->get_owning_quiz()) {
-            $quizzes = $DB->get_records_menu('quiz', array('course' => $this->page->course->id), '', 'id, name');
-            if(empty($quizzes)) {
-                $mform->addElement('static', 'noquizzeswarning', get_string('config_select_quiz', 'block_quiz_results'),
-                        get_string('config_no_quizzes_in_course', 'block_quiz_results'));
-            } else {
-                foreach($quizzes as $id => $name) {
-                    $quizzes[$id] = strip_tags(format_string($name));
-                }
-                $mform->addElement('select', 'config_quizid', get_string('config_select_quiz', 'block_quiz_results'), $quizzes);
-            }
-        }
-
-        $mform->addElement('text', 'config_showbest', get_string('config_show_best', 'block_quiz_results'), array('size' => 3));
-        $mform->setDefault('config_showbest', 3);
-        $mform->setType('config_showbest', PARAM_INT);
-
-        $mform->addElement('text', 'config_showworst', get_string('config_show_worst', 'block_quiz_results'), array('size' => 3));
-        $mform->setDefault('config_showworst', 0);
-        $mform->setType('config_showworst', PARAM_INT);
-
-        $mform->addElement('selectyesno', 'config_usegroups', get_string('config_use_groups', 'block_quiz_results'));
-
-        $nameoptions = array(
-            B_QUIZRESULTS_NAME_FORMAT_FULL => get_string('config_names_full', 'block_quiz_results'),
-            B_QUIZRESULTS_NAME_FORMAT_ID => get_string('config_names_id', 'block_quiz_results'),
-            B_QUIZRESULTS_NAME_FORMAT_ANON => get_string('config_names_anon', 'block_quiz_results')
-        );
-        $mform->addElement('select', 'config_nameformat', get_string('config_name_format', 'block_quiz_results'), $nameoptions);
-        $mform->setDefault('config_nameformat', B_QUIZRESULTS_NAME_FORMAT_FULL);
-
-        $gradeeoptions = array(
-            B_QUIZRESULTS_GRADE_FORMAT_PCT => get_string('config_format_percentage', 'block_quiz_results'),
-            B_QUIZRESULTS_GRADE_FORMAT_FRA => get_string('config_format_fraction', 'block_quiz_results'),
-            B_QUIZRESULTS_GRADE_FORMAT_ABS => get_string('config_format_absolute', 'block_quiz_results')
-        );
-        $mform->addElement('select', 'config_gradeformat', get_string('config_grade_format', 'block_quiz_results'), $gradeeoptions);
-        $mform->setDefault('config_gradeformat', B_QUIZRESULTS_GRADE_FORMAT_PCT);
-    }
-}
\ No newline at end of file
index f6d758a..03bcd16 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['pluginname'] = 'Quiz results (disabled)';
+$string['quiz_results:addinstance'] = 'Add a new quiz results block';
+
+// Deprecated since Moodle 2.9.
 $string['bestgrade'] = 'The highest grade:';
 $string['bestgrades'] = 'The {$a} highest grades:';
 $string['bestgroupgrade'] = 'The group with the highest average:';
@@ -43,8 +47,6 @@ $string['config_use_groups'] = 'Show groups instead of students (only if the qui
 $string['error_emptyquizid'] = 'There is an error right now with this block: you need to select which quiz it should display results from.';
 $string['error_emptyquizrecord'] = 'There is an error right now with this block: the selected quiz does not seem to exist in the database.';
 $string['error_nogroupsexist'] = 'There is an error right now with this block: it is set to display grades in group mode, but the course has no defined groups.';
-$string['pluginname'] = 'Quiz results';
-$string['quiz_results:addinstance'] = 'Add a new quiz results block';
 $string['worstgrade'] = 'The lowest grade:';
 $string['worstgrades'] = 'The {$a} lowest grades:';
 $string['worstgroupgrade'] = 'The group with the lowest average:';
diff --git a/blocks/quiz_results/lang/en/depreciated.txt b/blocks/quiz_results/lang/en/depreciated.txt
new file mode 100644 (file)
index 0000000..af64c64
--- /dev/null
@@ -0,0 +1,25 @@
+bestgrade,block_quiz_results
+bestgrades,block_quiz_results
+bestgroupgrade,block_quiz_results
+bestgroupgrades,block_quiz_results
+config_format_absolute,block_quiz_results
+config_format_fraction,block_quiz_results
+config_format_percentage,block_quiz_results
+config_grade_format,block_quiz_results
+config_name_format,block_quiz_results
+config_names_anon,block_quiz_results
+config_names_full,block_quiz_results
+config_names_id,block_quiz_results
+config_no_quizzes_in_course,block_quiz_results
+config_select_quiz,block_quiz_results
+config_show_best,block_quiz_results
+config_show_worst,block_quiz_results
+configuredtoshownothing,block_quiz_results
+config_use_groups,block_quiz_results
+error_emptyquizid,block_quiz_results
+error_emptyquizrecord,block_quiz_results
+error_nogroupsexist,block_quiz_results
+worstgrade,block_quiz_results
+worstgrades,block_quiz_results
+worstgroupgrade,block_quiz_results
+worstgroupgrades,block_quiz_results
\ No newline at end of file
diff --git a/blocks/quiz_results/styles.css b/blocks/quiz_results/styles.css
deleted file mode 100644 (file)
index 0f2dda9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-.block_quiz_results {text-align: center;}
-.block_quiz_results h1 {margin: 4px;font-size: 1.1em;}
-.block_quiz_results table.grades {text-align: left;width: 100%;}
-.block_quiz_results table.grades .number,
-.block_quiz_results table.grades .grade {text-align: right;width: 10%;}
-.block_quiz_results table.grades caption {margin: 1em 0px 0px 0px;border-bottom-width: 1px;border-bottom-style: solid;font-weight: bold;}
index 88308e5..be5bfde 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014111000;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2015022200;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2014110400;        // Requires this Moodle version
 $plugin->component = 'block_quiz_results'; // Full name of the plugin (used for diagnostics)
 
index 572238a..605c328 100644 (file)
@@ -659,8 +659,14 @@ function calendar_add_event_metadata($event) {
         $event->courselink = calendar_get_courselink($event->courseid);
         $event->cssclass = 'calendar_event_course';
     } else if ($event->groupid) {                                    // Group event
-        $event->icon = '<img src="'.$OUTPUT->pix_url('i/groupevent') . '" alt="'.get_string('groupevent', 'calendar').'" class="icon" />';
-        $event->courselink = calendar_get_courselink($event->courseid);
+        if ($group = calendar_get_group_cached($event->groupid)) {
+            $groupname = format_string($group->name, true, context_course::instance($group->courseid));
+        } else {
+            $groupname = '';
+        }
+        $event->icon = html_writer::empty_tag('image', array('src' => $OUTPUT->pix_url('i/groupevent'),
+            'alt' => get_string('groupevent', 'calendar'), 'title' => $groupname, 'class' => 'icon'));
+        $event->courselink = calendar_get_courselink($event->courseid) . ', ' . $groupname;
         $event->cssclass = 'calendar_event_group';
     } else if($event->userid) {                                      // User event
         $event->icon = '<img src="'.$OUTPUT->pix_url('i/userevent') . '" alt="'.get_string('userevent', 'calendar').'" class="icon" />';
@@ -1415,6 +1421,20 @@ function calendar_get_course_cached(&$coursecache, $courseid) {
     return $coursecache[$courseid];
 }
 
+/**
+ * Get group from groupid for calendar display
+ *
+ * @param int $groupid
+ * @return stdClass group object with fields 'id', 'name' and 'courseid'
+ */
+function calendar_get_group_cached($groupid) {
+    static $groupscache = array();
+    if (!isset($groupscache[$groupid])) {
+        $groupscache[$groupid] = groups_get_group($groupid, 'id,name,courseid');
+    }
+    return $groupscache[$groupid];
+}
+
 /**
  * Returns the courses to load events for, the
  *
@@ -2947,7 +2967,7 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timez
     $name = $event->properties['SUMMARY'][0]->value;
     $name = str_replace('\n', '<br />', $name);
     $name = str_replace('\\', '', $name);
-    $name = preg_replace('/\s+/', ' ', $name);
+    $name = preg_replace('/\s+/u', ' ', $name);
 
     $eventrecord = new stdClass;
     $eventrecord->name = clean_param($name, PARAM_NOTAGS);
@@ -2959,7 +2979,7 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timez
         $description = clean_param($description, PARAM_NOTAGS);
         $description = str_replace('\n', '<br />', $description);
         $description = str_replace('\\', '', $description);
-        $description = preg_replace('/\s+/', ' ', $description);
+        $description = preg_replace('/\s+/u', ' ', $description);
     }
     $eventrecord->description = $description;
 
index 619590c..de0e752 100644 (file)
@@ -9,12 +9,20 @@ Feature: Perform basic calendar functionality
       | username | firstname | lastname | email |
       | student1 | Student | 1 | student1@asd.com |
       | student2 | Student | 2 | student2@asd.com |
+      | student3 | Student | 3 | student3@asd.com |
     And the following "courses" exist:
       | fullname | shortname | format |
       | Course 1 | C1 | topics |
     And the following "course enrolments" exist:
       | user | course | role |
       | student1 | C1 | student |
+      | student3 | C1 | student |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+    And the following "group members" exist:
+      | user | group |
+      | student1 | G1 |
     When I log in as "admin"
     And I follow "Course 1"
     And I turn editing mode on
@@ -50,6 +58,23 @@ Feature: Perform basic calendar functionality
     And I follow "This month"
     And I should not see "Really awesome event!"
 
+  Scenario: Create a group event
+    And I create a calendar event with form data:
+      | Type of event | group |
+      | Group | Group 1 |
+      | Event title | Really awesome event! |
+      | Description | Come join this awesome event |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I follow "This month"
+    And I follow "Really awesome event!"
+    And "Group 1" "text" should exist in the ".eventlist" "css_element"
+    And I log out
+    And I log in as "student3"
+    And I follow "This month"
+    And I should not see "Really awesome event!"
+
   Scenario: Create a user event
     And I create a calendar event with form data:
       | Type of event | user |
diff --git a/completion/classes/external.php b/completion/classes/external.php
new file mode 100644 (file)
index 0000000..4d9c32e
--- /dev/null
@@ -0,0 +1,117 @@
+<?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/>.
+
+/**
+ * Completion external API
+ *
+ * @package    core_completion
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 2.9
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once("$CFG->libdir/externallib.php");
+require_once("$CFG->libdir/completionlib.php");
+
+/**
+ * Completion external functions
+ *
+ * @package    core_completion
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 2.9
+ */
+class core_completion_external extends external_api {
+
+    /**
+     * Describes the parameters for update_activity_completion_status_manually.
+     *
+     * @return external_external_function_parameters
+     * @since Moodle 2.9
+     */
+    public static function update_activity_completion_status_manually_parameters() {
+        return new external_function_parameters (
+            array(
+                'cmid' => new external_value(PARAM_INT, 'course module id'),
+                'completed' => new external_value(PARAM_BOOL, 'activity completed or not'),
+            )
+        );
+    }
+
+    /**
+     * Update completion status for the current user in an activity, only for activities with manual tracking.
+     * @param  int $cmid      Course module id
+     * @param  bool $completed Activity completed or not
+     * @return array            Result and possible warnings
+     * @since Moodle 2.9
+     * @throws moodle_exception
+     */
+    public static function update_activity_completion_status_manually($cmid,  $completed) {
+
+        // Validate and normalize parameters.
+        $params = self::validate_parameters(self::update_activity_completion_status_manually_parameters(),
+            array('cmid' => $cmid, 'completed' => $completed));
+        $cmid = $params['cmid'];
+        $completed = $params['completed'];
+
+        $warnings = array();
+
+        $context = context_module::instance($cmid);
+        self::validate_context($context);
+
+        list($course, $cm) = get_course_and_cm_from_cmid($cmid);
+
+        // Set up completion object and check it is enabled.
+        $completion = new completion_info($course);
+        if (!$completion->is_enabled()) {
+            throw new moodle_exception('completionnotenabled', 'completion');
+        }
+
+        // Check completion state is manual.
+        if ($cm->completion != COMPLETION_TRACKING_MANUAL) {
+            throw new moodle_exception('cannotmanualctrack', 'error');
+        }
+
+        $targetstate = ($completed) ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
+        $completion->update_state($cm, $targetstate);
+
+        $result = array();
+        $result['status'] = true;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Describes the update_activity_completion_status_manually return value.
+     *
+     * @return external_single_structure
+     * @since Moodle 2.9
+     */
+    public static function update_activity_completion_status_manually_returns() {
+
+        return new external_single_structure(
+            array(
+                'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
+                'warnings'  => new external_warnings(),
+            )
+        );
+    }
+
+}
diff --git a/completion/tests/externallib_test.php b/completion/tests/externallib_test.php
new file mode 100644 (file)
index 0000000..24ee1a7
--- /dev/null
@@ -0,0 +1,90 @@
+<?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/>.
+
+/**
+ * External completion functions unit tests
+ *
+ * @package    core_completion
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 2.9
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+
+/**
+ * External completion functions unit tests
+ *
+ * @package    core_completion
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 2.9
+ */
+class core_completion_externallib_testcase extends externallib_advanced_testcase {
+
+    /**
+     * Test update_activity_completion_status_manually
+     */
+    public function test_update_activity_completion_status_manually() {
+        global $DB, $CFG;
+
+        $this->resetAfterTest(true);
+
+        $CFG->enablecompletion = true;
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
+        $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id),
+                                                             array('completion' => 1));
+        $cm = get_coursemodule_from_id('data', $data->cmid);
+
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
+
+        $this->setUser($user);
+
+        $result = core_completion_external::update_activity_completion_status_manually($data->cmid, true);
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $result = external_api::clean_returnvalue(
+            core_completion_external::update_activity_completion_status_manually_returns(), $result);
+
+        // Check in DB.
+        $this->assertEquals(1, $DB->get_field('course_modules_completion', 'completionstate',
+                            array('coursemoduleid' => $data->cmid)));
+
+        // Check using the API.
+        $completion = new completion_info($course);
+        $completiondata = $completion->get_data($cm);
+        $this->assertEquals(1, $completiondata->completionstate);
+        $this->assertTrue($result['status']);
+
+        $result = core_completion_external::update_activity_completion_status_manually($data->cmid, false);
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $result = external_api::clean_returnvalue(
+            core_completion_external::update_activity_completion_status_manually_returns(), $result);
+
+        $this->assertEquals(0, $DB->get_field('course_modules_completion', 'completionstate',
+                            array('coursemoduleid' => $data->cmid)));
+        $completiondata = $completion->get_data($cm);
+        $this->assertEquals(0, $completiondata->completionstate);
+        $this->assertTrue($result['status']);
+    }
+}
index 60864a8..d1c1fff 100644 (file)
@@ -8,6 +8,6 @@
     "require-dev": {
         "phpunit/phpunit": "3.7.*",
         "phpunit/dbUnit": "1.2.*",
-        "moodlehq/behat-extension": "1.29.3"
+        "moodlehq/behat-extension": "1.29.4"
     }
 }
index 234e3ad..aaa87e9 100644 (file)
@@ -189,6 +189,10 @@ if (!empty($add)) {
                                              'iteminstance'=>$data->instance, 'courseid'=>$course->id))) {
         // add existing outcomes
         foreach ($items as $item) {
+            if (!empty($item->gradepass)) {
+                $decimalpoints = $item->get_decimals();
+                $data->gradepass = format_float($item->gradepass, $decimalpoints);
+            }
             if (!empty($item->outcomeid)) {
                 $data->{'outcome_'.$item->outcomeid} = 1;
             }
index 9a44714..ed653ce 100644 (file)
@@ -191,8 +191,16 @@ function edit_module_post_actions($moduleinfo, $course) {
     // Sync idnumber with grade_item.
     if ($hasgrades && $grade_item = grade_item::fetch(array('itemtype'=>'mod', 'itemmodule'=>$moduleinfo->modulename,
                  'iteminstance'=>$moduleinfo->instance, 'itemnumber'=>0, 'courseid'=>$course->id))) {
+        $gradeupdate = false;
         if ($grade_item->idnumber != $moduleinfo->cmidnumber) {
             $grade_item->idnumber = $moduleinfo->cmidnumber;
+            $gradeupdate = true;
+        }
+        if (isset($moduleinfo->gradepass) && $grade_item->gradepass != $moduleinfo->gradepass) {
+            $grade_item->gradepass = $moduleinfo->gradepass;
+            $gradeupdate = true;
+        }
+        if ($gradeupdate) {
             $grade_item->update();
         }
     }
index 6a3a845..ef638b3 100644 (file)
@@ -299,6 +299,22 @@ abstract class moodleform_mod extends moodleform {
             $errors['assessed'] = get_string('scaleselectionrequired', 'rating');
         }
 
+        // Grade to pass: ensure that the grade to pass is valid for points and scales.
+        // If we are working with a scale, convert into a positive number for validation.
+
+        if (isset($data['gradepass']) && (isset($data['grade']) || isset($data['scale']))) {
+            $scale = isset($data['grade']) ? $data['grade'] : $data['scale'];
+            if ($scale < 0) {
+                $scalevalues = $DB->get_record('scale', array('id' => -$scale));
+                $grade = count(explode(',', $scalevalues->scale));
+            } else {
+                $grade = $scale;
+            }
+            if ($data['gradepass'] > $grade) {
+                $errors['gradepass'] = get_string('gradepassgreaterthangrade', 'grades', $grade);
+            }
+        }
+
         // Completion: Don't let them choose automatic completion without turning
         // on some conditions. Ignore this check when completion settings are
         // locked, as the options are then disabled.
@@ -624,6 +640,9 @@ abstract class moodleform_mod extends moodleform {
                     $mform->addElement('select', 'advancedgradingmethod_'.$areaname,
                         get_string('gradingmethod', 'core_grading'), $this->current->_advancedgradingdata['methods']);
                     $mform->addHelpButton('advancedgradingmethod_'.$areaname, 'gradingmethod', 'core_grading');
+                    if (!$this->_features->rating) {
+                        $mform->disabledIf('advancedgradingmethod_'.$areaname, 'grade[modgrade_type]', 'eq', 'none');
+                    }
 
                 } else {
                     // the module defines multiple gradable areas, display a selector
@@ -644,6 +663,19 @@ abstract class moodleform_mod extends moodleform {
                         get_string('gradecategoryonmodform', 'grades'),
                         grade_get_categories_menu($COURSE->id, $this->_outcomesused));
                 $mform->addHelpButton('gradecat', 'gradecategoryonmodform', 'grades');
+                if (!$this->_features->rating) {
+                    $mform->disabledIf('gradecat', 'grade[modgrade_type]', 'eq', 'none');
+                }
+            }
+
+            // Grade to pass.
+            $mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
+            $mform->addHelpButton('gradepass', 'gradepass', 'grades');
+            $mform->setDefault('gradepass', '');
+            $mform->setType('gradepass', PARAM_FLOAT);
+            $mform->addRule('gradepass', null, 'numeric', null, 'client');
+            if (!$this->_features->rating) {
+                $mform->disabledIf('gradepass', 'grade[modgrade_type]', 'eq', 'none');
             }
         }
     }
index 17db276..08ce8ea 100644 (file)
Binary files a/course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop-debug.js and b/course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop-debug.js differ
index 8a8b5b6..0af8c1b 100644 (file)
Binary files a/course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop-min.js and b/course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop-min.js differ
index df6d54b..9da1d7d 100644 (file)
Binary files a/course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop.js and b/course/yui/build/moodle-course-dragdrop/moodle-course-dragdrop.js differ
index 14f9129..db57c73 100644 (file)
@@ -93,6 +93,18 @@ Y.extend(DRAGRESOURCE, M.core.dragdrop, {
      */
     setup_for_resource: function(baseselector) {
         Y.Node.all(baseselector).each(function(resourcesnode) {
+            var draggroups = resourcesnode.getData('draggroups');
+            if (!draggroups) {
+                // This Drop Node has not been set up. Configure it now.
+                resourcesnode.setAttribute('data-draggroups', this.groups.join(' '));
+                // Define empty ul as droptarget, so that item could be moved to empty list
+                new Y.DD.Drop({
+                    node: resourcesnode,
+                    groups: this.groups,
+                    padding: '20 0 20 0'
+                });
+            }
+
             // Replace move icons
             var move = resourcesnode.one('a.' + CSS.EDITINGMOVE);
             if (move) {
index 6dfe3cc..845e2e4 100644 (file)
@@ -60,7 +60,21 @@ class enrol_paypal_plugin extends enrol_plugin {
      * @return array of pix_icon
      */
     public function get_info_icons(array $instances) {
-        return array(new pix_icon('icon', get_string('pluginname', 'enrol_paypal'), 'enrol_paypal'));
+        $found = false;
+        foreach ($instances as $instance) {
+            if ($instance->enrolstartdate != 0 && $instance->enrolstartdate > time()) {
+                continue;
+            }
+            if ($instance->enrolenddate != 0 && $instance->enrolenddate < time()) {
+                continue;
+            }
+            $found = true;
+            break;
+        }
+        if ($found) {
+            return array(new pix_icon('icon', get_string('pluginname', 'enrol_paypal'), 'enrol_paypal'));
+        }
+        return array();
     }
 
     public function roles_protected() {
index 3565ef6..4a896ea 100644 (file)
@@ -563,8 +563,8 @@ class gradingform_guide_controller extends gradingform_controller {
             return $this->get_instance($instance);
         }
         if ($itemid && $raterid) {
-            if ($rs = $DB->get_records('grading_instances', array('raterid' => $raterid, 'itemid' => $itemid),
-                'timemodified DESC', '*', 0, 1)) {
+            $params = array('definitionid' => $this->definition->id, 'raterid' => $raterid, 'itemid' => $itemid);
+            if ($rs = $DB->get_records('grading_instances', $params, 'timemodified DESC', '*', 0, 1)) {
                 $record = reset($rs);
                 $currentinstance = $this->get_current_instance($raterid, $itemid);
                 if ($record->status == gradingform_guide_instance::INSTANCE_STATUS_INCOMPLETE &&
diff --git a/grade/grading/form/guide/tests/guide_test.php b/grade/grading/form/guide/tests/guide_test.php
new file mode 100644 (file)
index 0000000..5bf953e
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for Marking Guide grading method.
+ *
+ * @package    gradingform_guide
+ * @category   test
+ * @copyright  2015 Nikita Kalinin <nixorv@gmail.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/grade/grading/lib.php');
+require_once($CFG->dirroot . '/grade/grading/form/guide/lib.php');
+
+/**
+ * Test cases for the Marking Guide.
+ *
+ * @package    gradingform_guide
+ * @category   test
+ * @copyright  2015 Nikita Kalinin <nixorv@gmail.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class gradingform_guide_testcase extends advanced_testcase {
+    /**
+     * Unit test to get draft instance and create new instance.
+     */
+    public function test_get_or_create_instance() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Create fake areas.
+        $fakearea = (object)array(
+            'contextid'    => 1,
+            'component'    => 'mod_assign',
+            'areaname'     => 'submissions',
+            'activemethod' => 'guide'
+        );
+        $fakearea1id = $DB->insert_record('grading_areas', $fakearea);
+        $fakearea->contextid = 2;
+        $fakearea2id = $DB->insert_record('grading_areas', $fakearea);
+
+        // Create fake definitions.
+        $fakedefinition = (object)array(
+            'areaid'       => $fakearea1id,
+            'method'       => 'guide',
+            'name'         => 'fakedef',
+            'status'       => gradingform_controller::DEFINITION_STATUS_READY,
+            'timecreated'  => 0,
+            'usercreated'  => 1,
+            'timemodified' => 0,
+            'usermodified' => 1,
+        );
+        $fakedef1id = $DB->insert_record('grading_definitions', $fakedefinition);
+        $fakedefinition->areaid = $fakearea2id;
+        $fakedef2id = $DB->insert_record('grading_definitions', $fakedefinition);
+
+        // Create fake guide instance in first area.
+        $fakeinstance = (object)array(
+            'definitionid'   => $fakedef1id,
+            'raterid'        => 1,
+            'itemid'         => 1,
+            'rawgrade'       => null,
+            'status'         => 0,
+            'feedback'       => null,
+            'feedbackformat' => 0,
+            'timemodified'   => 0
+        );
+        $fakeinstanceid = $DB->insert_record('grading_instances', $fakeinstance);
+
+        $manager1 = get_grading_manager($fakearea1id);
+        $manager2 = get_grading_manager($fakearea2id);
+        $controller1 = $manager1->get_controller('guide');
+        $controller2 = $manager2->get_controller('guide');
+
+        $instance1 = $controller1->get_or_create_instance(0, 1, 1);
+        $instance2 = $controller2->get_or_create_instance(0, 1, 1);
+
+        // Definitions should not be the same.
+        $this->assertEquals(false, $instance1->get_data('definitionid') == $instance2->get_data('definitionid'));
+    }
+}
index 614ccca..a17da1c 100644 (file)
@@ -19,6 +19,9 @@
     min-width: 4.5em;
     vertical-align: top;
 }
+.dir-rtl.path-grade-report-user .user-grade td {
+    direction: ltr;
+}
 .path-grade-report-user .user-grade .b1l {
     padding: 0;
     width:24px;
diff --git a/grade/tests/behat/grade_to_pass.feature b/grade/tests/behat/grade_to_pass.feature
new file mode 100644 (file)
index 0000000..8ac6e30
--- /dev/null
@@ -0,0 +1,251 @@
+@core @core_grades
+Feature: We can set the grade to pass value
+  In order to set the grade to pass value
+  As a teacher
+  I assign a grade to pass to an activity while editing the activity.
+  I need to ensure that the grade to pass is visible in the gradebook.
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+    And the following "courses" exist:
+      | fullname | shortname | format | numsections |
+      | Course 1 | C1 | weeks | 5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And the following "scales" exist:
+      | name | scale |
+      | Test Scale 1 | Disappointing, Good, Very good, Excellent |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+
+  @javascript
+  Scenario: Validate that switching the type of grading used correctly disables grade to pass
+    When I turn editing mode on
+    And I add a "Assignment" to section "1"
+    And I expand all fieldsets
+    And I set the field "grade[modgrade_type]" to "Point"
+    Then the "Grade to pass" "field" should be enabled
+    And I set the field "grade[modgrade_type]" to "None"
+    And the "Grade to pass" "field" should be disabled
+    And I press "Save and return to course"
+
+  @javascript
+  Scenario: Create an activity with a Grade to pass value greater than the maximum grade
+    When I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test Assignment 1 |
+      | Description | Submit your online text |
+      | assignsubmission_onlinetext_enabled | 1 |
+      | grade[modgrade_type] | Point |
+      | grade[modgrade_point] | 50 |
+      | Grade to pass | 100 |
+    Then I should see "The grade to pass can not be greater than the maximum possible grade 50"
+    And I press "Cancel"
+
+  @javascript
+  Scenario: Set a valid grade to pass for an assignment activity using points
+    When I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test Assignment 1 |
+      | Description | Submit your online text |
+      | assignsubmission_onlinetext_enabled | 1 |
+      | grade[modgrade_type] | Point |
+      | grade[modgrade_point] | 50 |
+      | Grade to pass | 25 |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  assign Test Assignment 1" "link"
+    Then the field "Grade to pass" matches value "25"
+    And I follow "Course 1"
+    And I follow "Test Assignment 1"
+    And I follow "Edit settings"
+    And I expand all fieldsets
+    And I set the field "Grade to pass" to "30"
+    And I press "Save and return to course"
+    And I follow "Grades"
+    And I click on "Edit  assign Test Assignment 1" "link"
+    And the field "Grade to pass" matches value "30"
+
+  @javascript
+  Scenario: Set a valid grade to pass for an assignment activity using scales
+    When I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test Assignment 1 |
+      | Description | Submit your online text |
+      | grade[modgrade_type] | Scale |
+      | grade[modgrade_scale] | Test Scale 1 |
+      | Grade to pass | 3 |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  assign Test Assignment 1" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "3"
+    And I set the field "Grade to pass" to "4"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Assignment 1"
+    And I follow "Edit settings"
+    And the field "Grade to pass" matches value "4"
+
+  @javascript
+  Scenario: Set a invalid grade to pass for an assignment activity using scales
+    When I turn editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test Assignment 1 |
+      | Description | Submit your online text |
+      | grade[modgrade_type] | Scale |
+      | grade[modgrade_scale] | Test Scale 1 |
+      | Grade to pass | 10 |
+    Then I should see "The grade to pass can not be greater than the maximum possible grade 4"
+
+  @javascript
+  Scenario: Set a valid grade to pass for workshop activity
+    When I turn editing mode on
+    And I add a "Workshop" to section "1" and I fill the form with:
+      | Workshop name | Test Workshop 1 |
+      | Description | Test workshop |
+      | grade | 80 |
+      | Submission grade to pass | 40 |
+      | gradinggrade | 20 |
+      | Assessment grade to pass | 10 |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  workshop Test Workshop 1 (submission)" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "40"
+    And I set the field "Grade to pass" to "45"
+    And I press "Save changes"
+    And I click on "Edit  workshop Test Workshop 1 (assessment)" "link"
+    And I follow "Show more..."
+    And the field "Grade to pass" matches value "10"
+    And I set the field "Grade to pass" to "15"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Workshop 1"
+    And I follow "Edit settings"
+    And the field "Submission grade to pass" matches value "45"
+    And the field "Assessment grade to pass" matches value "15"
+
+  @javascript
+  Scenario: Set an invalid grade to pass for workshop activity
+    When I turn editing mode on
+    And I add a "Workshop" to section "1" and I fill the form with:
+      | Workshop name | Test Workshop 1 |
+      | Description | Test workshop |
+      | grade | 80 |
+      | Submission grade to pass | 90 |
+      | gradinggrade | 20 |
+      | Assessment grade to pass | 30 |
+    Then "The grade to pass can not be greater than the maximum possible grade 80" "text" should exist in the "#fitem_id_submissiongradepass .error" "css_element"
+    Then "The grade to pass can not be greater than the maximum possible grade 20" "text" should exist in the "#fitem_id_gradinggradepass .error" "css_element"
+
+  @javascript
+  Scenario: Set a valid grade to pass for quiz activity
+    When I turn editing mode on
+    And I add a "Quiz" to section "1" and I fill the form with:
+      | Name | Test Quiz 1 |
+      | Grade to pass | 9.5 |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  quiz Test Quiz 1" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "9.5"
+    And I set the field "Grade to pass" to "8"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Quiz 1"
+    And I follow "Edit settings"
+    And the field "Grade to pass" matches value "8.00"
+
+  @javascript
+  Scenario: Set a valid grade to pass for lesson activity
+    When I turn editing mode on
+    And I add a "Lesson" to section "1" and I fill the form with:
+      | Name          | Test Lesson 1 |
+      | Description   | Test          |
+      | Grade to pass | 90            |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  lesson Test Lesson 1" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "90"
+    And I set the field "Grade to pass" to "80"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Lesson 1"
+    And I follow "Edit settings"
+    And the field "Grade to pass" matches value "80"
+
+  @javascript
+  Scenario: Set a valid grade to pass for database activity
+    When I turn editing mode on
+    And I add a "Database" to section "1" and I fill the form with:
+      | Name           | Test Database 1    |
+      | Description    | Test               |
+      | Grade to pass  | 90                 |
+      | Aggregate type | Average of ratings |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  data Test Database 1" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "90"
+    And I set the field "Grade to pass" to "80"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Database 1"
+    And I follow "Edit settings"
+    And the field "Grade to pass" matches value "80"
+
+  @javascript
+  Scenario: Set an invalid grade to pass for forum activity
+    When I turn editing mode on
+    And I add a "Forum" to section "1" and I fill the form with:
+      | Forum name     | Test Forum 1    |
+      | Description    | Test               |
+      | Grade to pass  | 90                 |
+      | Aggregate type | Average of ratings |
+      | scale[modgrade_point] | 60 |
+    Then I should see "The grade to pass can not be greater than the maximum possible grade 60"
+
+  @javascript
+  Scenario: Set a valid grade to pass for forum activity
+    When I turn editing mode on
+    And I add a "Forum" to section "1" and I fill the form with:
+      | Forum name     | Test Forum 1    |
+      | Description    | Test               |
+      | Grade to pass  | 90                 |
+      | Aggregate type | Average of ratings |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  forum Test Forum 1" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "90"
+    And I set the field "Grade to pass" to "80"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Forum 1"
+    And I follow "Edit settings"
+    And the field "Grade to pass" matches value "80"
+
+  @javascript
+  Scenario: Set a valid grade to pass for glossary activity
+    When I turn editing mode on
+    And I add a "Glossary" to section "1" and I fill the form with:
+      | Name           | Test Glossary 1    |
+      | Description    | Test               |
+      | Grade to pass  | 90                 |
+      | Aggregate type | Average of ratings |
+    And I follow "Grades"
+    And I turn editing mode on
+    And I click on "Edit  glossary Test Glossary 1" "link"
+    And I follow "Show more..."
+    Then the field "Grade to pass" matches value "90"
+    And I set the field "Grade to pass" to "80"
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I follow "Test Glossary 1"
+    And I follow "Edit settings"
+    And the field "Grade to pass" matches value "80"
index e80d92e..a15d522 100644 (file)
@@ -296,6 +296,7 @@ $string['gradeoutcomes'] = 'Outcomes';
 $string['gradeoutcomescourses'] = 'Course outcomes';
 $string['gradepass'] = 'Grade to pass';
 $string['gradepass_help'] = 'This setting determines the minimum grade required to pass. The value is used in activity and course completion, and in the gradebook, where pass grades are highlighted in green and fail grades in red.';
+$string['gradepassgreaterthangrade'] = 'The grade to pass can not be greater than the maximum possible grade {$a}';
 $string['gradepointdefault'] = 'Grade point default';
 $string['gradepointdefault_help'] = 'This setting determines the default value for the grade point value available in an activity.';
 $string['gradepointdefault_validateerror'] = 'This setting must be an integer between 1 and the grade point maximum.';
index 4b1272c..0590bd1 100644 (file)
@@ -1118,7 +1118,9 @@ $string['maxsizeandattachmentsandareasize'] = 'Maximum size for new files: {$a->
 $string['memberincourse'] = 'People in the course';
 $string['messagebody'] = 'Message body';
 $string['messagedselectedusers'] = 'Selected users have been messaged and the recipient list has been reset.';
+$string['messagedselecteduserfailed'] = 'The message was not sent to user {$a->fullname}.';
 $string['messagedselectedusersfailed'] = 'Something went wrong while messaging selected users.  Some may have received the email.';
+$string['messagedselectedcountusersfailed'] = 'A problem occurred and {$a} messages have not been sent.';
 $string['messageprovider:availableupdate'] = 'Available update notifications';
 $string['messageprovider:backup'] = 'Backup notifications';
 $string['messageprovider:badgecreatornotice'] = 'Badge creator notifications';
@@ -1330,7 +1332,7 @@ $string['notenrolled'] = '{$a} is not enrolled in this course.';
 $string['notenrolledprofile'] = 'This profile is not available because this user is not enrolled in this course.';
 $string['noteusercannotrolldatesoncontext'] = '<strong>Note:</strong> The ability to roll dates when restoring this backup has been disabled because you lack the required permissions.';
 $string['noteuserschangednonetocourse'] = '<strong>Note:</strong> Course users need to be restored when restoring user data (in activities, files or messages). This setting has been changed for you.';
-$string['nothingnew'] = 'Nothing new since your last login';
+$string['nothingnew'] = 'No recent activity';
 $string['nothingtodisplay'] = 'Nothing to display';
 $string['notice'] = 'Notice';
 $string['noticenewerbackup'] = 'This backup file has been created with Moodle {$a->backuprelease} ({$a->backupversion}) and it\'s newer than your currently installed Moodle {$a->serverrelease} ({$a->serverversion}). This could cause some inconsistencies because backwards compatibility of backup files cannot be guaranteed.';
index dde8b7e..8fd87a2 100644 (file)
@@ -967,8 +967,8 @@ class core_plugin_manager {
             ),
 
             'block' => array(
-                'activity_modules', 'admin_bookmarks', 'badges', 'blog_menu',
-                'blog_recent', 'blog_tags', 'calendar_month',
+                'activity_modules', 'activity_results', 'admin_bookmarks', 'badges',
+                'blog_menu', 'blog_recent', 'blog_tags', 'calendar_month',
                 'calendar_upcoming', 'comments', 'community',
                 'completionstatus', 'course_list', 'course_overview',
                 'course_summary', 'feedback', 'glossary_random', 'html',
index 9c525e5..aedfceb 100644 (file)
@@ -35,11 +35,17 @@ abstract class scheduled_task extends task_base {
     const MINUTEMIN = 0;
     /** Maximum minute value. */
     const MINUTEMAX = 59;
+
     /** Minimum hour value. */
     const HOURMIN = 0;
     /** Maximum hour value. */
     const HOURMAX = 23;
 
+    /** Minimum dayofweek value. */
+    const DAYOFWEEKMIN = 0;
+    /** Maximum dayofweek value. */
+    const DAYOFWEEKMAX = 6;
+
     /** @var string $hour - Pattern to work out the valid hours */
     private $hour = '*';
 
@@ -173,6 +179,9 @@ abstract class scheduled_task extends task_base {
      * @param string $dayofweek
      */
     public function set_day_of_week($dayofweek) {
+        if ($dayofweek === 'R') {
+            $dayofweek = mt_rand(self::DAYOFWEEKMIN, self::DAYOFWEEKMAX);
+        }
         $this->dayofweek = $dayofweek;
     }
 
index a027c55..d9609b4 100644 (file)
@@ -1562,6 +1562,9 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
         require_once($CFG->libdir.'/questionlib.php');
         require_once($CFG->dirroot.'/cohort/lib.php');
 
+        // Make sure we won't timeout when deleting a lot of courses.
+        $settimeout = core_php_time_limit::raise();
+
         $deletedcourses = array();
 
         // Get children. Note, we don't want to use cache here because it would be rebuilt too often.
index 00d90d1..47eb28c 100644 (file)
@@ -957,6 +957,14 @@ $functions = array(
         'description' => 'Load a template for a renderable',
         'type'        => 'read'
     ),
+
+    // Completion related functions.
+    'core_completion_update_activity_completion_status_manually' => array(
+        'classname'   => 'core_completion_external',
+        'methodname'  => 'update_activity_completion_status_manually',
+        'description' => 'Update completion status for the current user in an activity, only for activities with manual tracking.',
+        'type'        => 'write',
+    ),
 );
 
 $services = array(
@@ -1013,7 +1021,9 @@ $services = array(
             'gradereport_user_get_grades_table',
             'core_group_get_course_user_groups',
             'core_user_remove_user_device',
-            'core_course_get_courses'
+            'core_course_get_courses',
+            'core_completion_update_activity_completion_status_manually',
+            'mod_data_get_databases_by_courses'
             ),
         'enabled' => 0,
         'restrictedusers' => 0,
index 8dc4f4e..6c4d7d2 100644 (file)
@@ -215,10 +215,10 @@ $tasks = array(
     array(
         'classname' => 'core\task\registration_cron_task',
         'blocking' => 0,
-        'minute' => '0',
-        'hour' => '3',
+        'minute' => 'R',
+        'hour' => 'R',
         'day' => '*',
-        'dayofweek' => '*',
+        'dayofweek' => 'R',
         'month' => '*'
     ),
     array(
index f4df15b..f5461f7 100644 (file)
@@ -4247,6 +4247,11 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2015031400.00);
     }
 
+    if ($oldversion < 2015031900.01) {
+        unset_config('crontime', 'registration');
+        upgrade_main_savepoint(true, 2015031900.01);
+    }
+
     if ($oldversion < 2015032000.00) {
         $table = new xmldb_table('badge_criteria');
 
index 52d04bf..4ee2923 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 6a50ded..516fb57 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index f01c730..cefa893 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index 89ccac7..2f6e5ca 100644 (file)
@@ -84,52 +84,236 @@ EditorClean.prototype = {
      * @return {String} The cleaned HTML
      */
     _cleanHTML: function(content) {
-        // What are we doing ?
-        // We are cleaning random HTML from all over the shop into a set of useful html suitable for content.
-        // We are allowing styles etc, but not e.g. font tags, class="MsoNormal" etc.
+        // Removing limited things that can break the page or a disallowed, like unclosed comments, style blocks, etc.
 
         var rules = [
-            // Source: "http://stackoverflow.com/questions/2875027/clean-microsoft-word-pasted-text-using-javascript"
-            // Source: "http://stackoverflow.com/questions/1068280/javascript-regex-multiline-flag-doesnt-work"
-
-            // Remove all HTML comments.
-            {regex: /<!--[\s\S]*?-->/gi, replace: ""},
-            // Source: "http://www.1stclassmedia.co.uk/developers/clean-ms-word-formatting.php"
-            // Remove <?xml>, <\?xml>.
-            {regex: /<\\?\?xml[^>]*>/gi, replace: ""},
-            // Remove <o:blah>, <\o:blah>.
-            {regex: /<\/?\w+:[^>]*>/gi, replace: ""}, // e.g. <o:p...
-            // Remove MSO-blah, MSO:blah (e.g. in style attributes)
-            {regex: /\s*MSO[-:][^;"']*;?/gi, replace: ""},
-            // Remove empty spans
-            {regex: /<span[^>]*>(&nbsp;|\s)*<\/span>/gi, replace: ""},
-            // Remove class="Msoblah"
-            {regex: /class="Mso[^"]*"/gi, replace: ""},
+            // Remove any style blocks. Some browsers do not work well with them in a contenteditable.
+            // Plus style blocks are not allowed in body html, except with "scoped", which most browsers don't support as of 2015.
+            // Reference: "http://stackoverflow.com/questions/1068280/javascript-regex-multiline-flag-doesnt-work"
+            {regex: /<style[^>]*>[\s\S]*?<\/style>/gi, replace: ""},
+
+            // Remove any open HTML comment opens that are not followed by a close. This can completely break page layout.
+            {regex: /<!--(?![\s\S]*?-->)/gi, replace: ""},
 
             // Source: "http://www.codinghorror.com/blog/2006/01/cleaning-words-nasty-html.html"
-            // Remove forbidden tags for content, title, meta, style, st0-9, head, font, html, body.
-            {regex: /<(\/?title|\/?meta|\/?style|\/?st\d|\/?head|\/?font|\/?html|\/?body|!\[)[^>]*?>/gi, replace: ""},
-
-            // Source: "http://www.tim-jarrett.com/labs_javascript_scrub_word.php"
-            // Replace extended chars with simple text.
-            {regex: new RegExp(String.fromCharCode(8220), 'gi'), replace: '"'},
-            {regex: new RegExp(String.fromCharCode(8216), 'gi'), replace: "'"},
-            {regex: new RegExp(String.fromCharCode(8217), 'gi'), replace: "'"},
-            {regex: new RegExp(String.fromCharCode(8211), 'gi'), replace: '-'},
-            {regex: new RegExp(String.fromCharCode(8212), 'gi'), replace: '--'},
-            {regex: new RegExp(String.fromCharCode(189), 'gi'), replace: '1/2'},
-            {regex: new RegExp(String.fromCharCode(188), 'gi'), replace: '1/4'},
-            {regex: new RegExp(String.fromCharCode(190), 'gi'), replace: '3/4'},
-            {regex: new RegExp(String.fromCharCode(169), 'gi'), replace: '(c)'},
-            {regex: new RegExp(String.fromCharCode(174), 'gi'), replace: '(r)'},
-            {regex: new RegExp(String.fromCharCode(8230), 'gi'), replace: '...'}
+            // Remove forbidden tags for content, title, meta, style, st0-9, head, font, html, body, link.
+            {regex: /<\/?(?:title|meta|style|st\d|head|font|html|body|link|!\[)[^>]*?>/gi, replace: ""}
         ];
 
+        return this._filterContentWithRules(content, rules);
+    },
+
+    /**
+     * Take the supplied content and run on the supplied regex rules.
+     *
+     * @method _filterContentWithRules
+     * @private
+     * @param {String} content The content to clean
+     * @param {Array} rules An array of structures: [ {regex: /something/, replace: "something"}, {...}, ...]
+     * @return {String} The cleaned content
+     */
+    _filterContentWithRules: function(content, rules) {
         var i = 0;
         for (i = 0; i < rules.length; i++) {
             content = content.replace(rules[i].regex, rules[i].replace);
         }
 
+        return content;
+    },
+
+    /**
+     * Intercept and clean html paste events.
+     *
+     * @method pasteCleanup
+     * @param {Object} sourceEvent The YUI EventFacade  object
+     * @return {Boolean} True if the passed event should continue, false if not.
+     */
+    pasteCleanup: function(sourceEvent) {
+        // We only expect paste events, but we will check anyways.
+        if (sourceEvent.type === 'paste') {
+            // The YUI event wrapper doesn't provide paste event info, so we need the underlying event.
+            var event = sourceEvent._event;
+            // Check if we have a valid clipboardData object in the event.
+            // IE has a clipboard object at window.clipboardData, but as of IE 11, it does not provide HTML content access.
+            if (event && event.clipboardData && event.clipboardData.getData) {
+                // Check if there is HTML type to be pasted, this is all we care about.
+                var types = event.clipboardData.types;
+                var isHTML = false;
+                // Different browsers use different things to hold the types, so test various functions.
+                if (!types) {
+                    isHTML = false;
+                } else if (typeof types.contains === 'function') {
+                    isHTML = types.contains('text/html');
+                } else if (typeof types.indexOf === 'function') {
+                    isHTML = (types.indexOf('text/html') > -1);
+                    if (!isHTML) {
+                        if ((types.indexOf('com.apple.webarchive') > -1) || (types.indexOf('com.apple.iWork.TSPNativeData') > -1)) {
+                            // This is going to be a specialized Apple paste paste. We cannot capture this, so clean everything.
+                            this.fallbackPasteCleanupDelayed();
+                            return true;
+                        }
+                    }
+                } else {
+                    // We don't know how to handle the clipboard info, so wait for the clipboard event to finish then fallback.
+                    this.fallbackPasteCleanupDelayed();
+                    return true;
+                }
+
+                if (isHTML) {
+                    // Get the clipboard content.
+                    var content;
+                    try {
+                        content = event.clipboardData.getData('text/html');
+                    } catch (error) {
+                        // Something went wrong. Fallback.
+                        this.fallbackPasteCleanupDelayed();
+                        return true;
+                    }
+
+                    // Stop the original paste.
+                    sourceEvent.preventDefault();
+
+                    // Scrub the paste content.
+                    content = this._cleanPasteHTML(content);
+
+                    // Save the current selection.
+                    // Using saveSelection as it produces a more consistent experience.
+                    var selection = window.rangy.saveSelection();
+
+                    // Insert the content.
+                    this.insertContentAtFocusPoint(content);
+
+                    // Restore the selection, and collapse to end.
+                    window.rangy.restoreSelection(selection);
+                    window.rangy.getSelection().collapseToEnd();
+
+                    // Update the text area.
+                    this.updateOriginal();
+                    return false;
+                } else {
+                    // This is a non-html paste event, we can just let this continue on and call updateOriginalDelayed.
+                    this.updateOriginalDelayed();
+                    return true;
+                }
+            } else {
+                // If we reached a here, this probably means the browser has limited (or no) clipboard support.
+                // Wait for the clipboard event to finish then fallback.
+                this.fallbackPasteCleanupDelayed();
+                return true;
+            }
+        }
+
+        // We should never get here - we must have received a non-paste event for some reason.
+        // Um, just call updateOriginalDelayed() - it's safe.
+        this.updateOriginalDelayed();
+        return true;
+    },
+
+    /**
+     * Cleanup code after a paste event if we couldn't intercept the paste content.
+     *
+     * @method fallbackPasteCleanup
+     * @chainable
+     */
+    fallbackPasteCleanup: function() {
+        Y.log('Using fallbackPasteCleanup for atto cleanup', 'debug', LOGNAME);
+
+        // Save the current selection (cursor position).
+        var selection = window.rangy.saveSelection();
+
+        // Get, clean, and replace the content in the editable.
+        var content = this.editor.get('innerHTML');
+        this.editor.set('innerHTML', this._cleanPasteHTML(content));
+
+        // Update the textarea.
+        this.updateOriginal();
+
+        // Restore the selection (cursor position).
+        window.rangy.restoreSelection(selection);
+
+        return this;
+    },
+
+    /**
+     * Calls fallbackPasteCleanup on a short timer to allow the paste event handlers to complete.
+     *
+     * @method fallbackPasteCleanupDelayed
+     * @chainable
+     */
+    fallbackPasteCleanupDelayed: function() {
+        Y.soon(Y.bind(this.fallbackPasteCleanup, this));
+
+        return this;
+    },
+
+    /**
+     * Cleanup html that comes from WYSIWYG paste events. These are more likely to contain messy code that we should strip.
+     *
+     * @method _cleanPasteHTML
+     * @private
+     * @param {String} content The html content to clean
+     * @return {String} The cleaned HTML
+     */
+    _cleanPasteHTML: function(content) {
+        // Return an empty string if passed an invalid or empty object.
+        if (!content || content.length === 0) {
+            return "";
+        }
+
+        // Rules that get rid of the real-nasties and don't care about normalize code (correct quotes, white spaces, etc).
+        var rules = [
+            // Stuff that is specifically from MS Word and similar office packages.
+            // Remove if comment blocks.
+            {regex: /<!--\[if[\s\S]*?endif\]-->/gi, replace: ""},
+            // Remove start and end fragment comment blocks.
+            {regex: /<!--(Start|End)Fragment-->/gi, replace: ""},
+            // Remove any xml blocks.
+            {regex: /<xml[^>]*>[\s\S]*?<\/xml>/gi, replace: ""},
+            // Remove any <?xml><\?xml> blocks.
+            {regex: /<\?xml[^>]*>[\s\S]*?<\\\?xml>/gi, replace: ""},
+            // Remove <o:blah>, <\o:blah>.
+            {regex: /<\/?\w+:[^>]*>/gi, replace: ""}
+        ];
+
+        // Apply the first set of harsher rules.
+        content = this._filterContentWithRules(content, rules);
+
+        // Apply the standard rules, which mainly cleans things like headers, links, and style blocks.
+        content = this._cleanHTML(content);
+
+        // Check if the string is empty or only contains whitespace.
+        if (content.length === 0 || !content.match(/\S/)) {
+            return content;
+        }
+
+        // Now we let the browser normalize the code by loading it into the DOM and then get the html back.
+        // This gives us well quoted, well formatted code to continue our work on. Word may provide very poorly formatted code.
+        var holder = document.createElement('div');
+        holder.innerHTML = content;
+        content = holder.innerHTML;
+        // Free up the DOM memory.
+        holder.innerHTML = "";
+
+        // Run some more rules that care about quotes and whitespace.
+        rules = [
+            // Remove MSO-blah, MSO:blah in style attributes. Only removes one or more that appear in succession.
+            {regex: /(<[^>]*?style\s*?=\s*?"[^>"]*?)(?:[\s]*MSO[-:][^>;"]*;?)+/gi, replace: "$1"},
+            // Remove MSO classes in class attributes. Only removes one or more that appear in succession.
+            {regex: /(<[^>]*?class\s*?=\s*?"[^>"]*?)(?:[\s]*MSO[_a-zA-Z0-9\-]*)+/gi, replace: "$1"},
+            // Remove Apple- classes in class attributes. Only removes one or more that appear in succession.
+            {regex: /(<[^>]*?class\s*?=\s*?"[^>"]*?)(?:[\s]*Apple-[_a-zA-Z0-9\-]*)+/gi, replace: "$1"},
+            // Remove OLE_LINK# anchors that may litter the code.
+            {regex: /<a [^>]*?name\s*?=\s*?"OLE_LINK\d*?"[^>]*?>\s*?<\/a>/gi, replace: ""},
+            // Remove empty spans.
+            {regex: /<span[^>]*>(&nbsp;|\s)*<\/span>/gi, replace: ""}
+        ];
+
+        // Apply the rules.
+        content = this._filterContentWithRules(content, rules);
+
+        // Reapply the standard cleaner to the content.
+        content = this._cleanHTML(content);
+
         return content;
     }
 };
index 93e4ede..8089a11 100644 (file)
@@ -296,7 +296,8 @@ Y.extend(Editor, Y.Base, {
      * @chainable
      */
     setupAutomaticPolling: function() {
-        this._registerEventHandle(this.editor.on(['keyup', 'paste', 'cut'], this.updateOriginal, this));
+        this._registerEventHandle(this.editor.on(['keyup', 'cut'], this.updateOriginal, this));
+        this._registerEventHandle(this.editor.on('paste', this.pasteCleanup, this));
 
         // Call this.updateOriginal after dropped content has been processed.
         this._registerEventHandle(this.editor.on('drop', this.updateOriginalDelayed, this));
index 675ba26..7b74a70 100644 (file)
@@ -1102,7 +1102,7 @@ function clean_param($param, $type) {
             // Remove some nasties.
             $param = preg_replace('~[[:cntrl:]]|[<>`]~u', '', $param);
             // Convert many whitespace chars into one.
-            $param = preg_replace('/\s+/', ' ', $param);
+            $param = preg_replace('/\s+/u', ' ', $param);
             $param = core_text::substr(trim($param), 0, TAG_MAX_LENGTH);
             return $param;
 
index a405408..a2ce75f 100644 (file)
@@ -352,6 +352,18 @@ class behat_data_generators extends behat_base {
             $data['enrol'] = 'manual';
         }
 
+        if (!isset($data['timestart'])) {
+            $data['timestart'] = 0;
+        }
+
+        if (!isset($data['timeend'])) {
+            $data['timeend'] = 0;
+        }
+
+        if (!isset($data['status'])) {
+            $data['status'] = null;
+        }
+
         // If the provided course shortname is the site shortname we consider it a system role assign.
         if ($data['courseid'] == $SITE->id) {
             // Frontpage course assign.
@@ -360,7 +372,8 @@ class behat_data_generators extends behat_base {
 
         } else {
             // Course assign.
-            $this->datagenerator->enrol_user($data['userid'], $data['courseid'], $data['roleid'], $data['enrol']);
+            $this->datagenerator->enrol_user($data['userid'], $data['courseid'], $data['roleid'], $data['enrol'],
+                    $data['timestart'], $data['timeend'], $data['status']);
         }
 
     }
diff --git a/lib/tests/regex_test.php b/lib/tests/regex_test.php
new file mode 100644 (file)
index 0000000..c8dd97e
--- /dev/null
@@ -0,0 +1,47 @@
+<?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/>.
+
+/**
+ * Test PHP regex capability - this may also serve as an example for devs.
+ *
+ * @package   core
+ * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author    Petr Skoda <petr.skoda@totaralms.com>
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Test PHP regex capability - this may also serve as an example for devs.
+ *
+ * @package   core
+ * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author    Petr Skoda <petr.skoda@totaralms.com>
+ */
+class core_regex_testcase extends advanced_testcase {
+    public function test_whitespace_replacement_with_u() {
+        $unicode = "Теорія і практика використання системи управління навчанням Moo
+dleКиївський національний університет будівництва і архітектури, 21-22 тра
+вня 2015 р.http://2015.moodlemoot.in.ua/";
+
+        $whitespaced = preg_replace('/\s+/u', ' ', $unicode);
+        $this->assertSame(str_replace("\n", ' ', $unicode), $whitespaced);
+    }
+}
+
+
index 2d5e205..95a5a0d 100644 (file)
@@ -329,6 +329,7 @@ class core_scheduled_task_testcase extends advanced_testcase {
         // Set a random value.
         $testclass->set_minute('R');
         $testclass->set_hour('R');
+        $testclass->set_day_of_week('R');
 
         // Verify the minute has changed within allowed bounds.
         $minute = $testclass->get_minute();
@@ -341,6 +342,12 @@ class core_scheduled_task_testcase extends advanced_testcase {
         $this->assertInternalType('int', $hour);
         $this->assertGreaterThanOrEqual(0, $hour);
         $this->assertLessThanOrEqual(23, $hour);
+
+        // Verify the dayofweek has changed within allowed bounds.
+        $dayofweek = $testclass->get_day_of_week();
+        $this->assertInternalType('int', $dayofweek);
+        $this->assertGreaterThanOrEqual(0, $dayofweek);
+        $this->assertLessThanOrEqual(6, $dayofweek);
     }
 
     /**
index aec6317..25ca9bf 100644 (file)
Binary files a/lib/yui/build/moodle-core-checknet/moodle-core-checknet-debug.js and b/lib/yui/build/moodle-core-checknet/moodle-core-checknet-debug.js differ
index 0dc73e0..cd16c7b 100644 (file)
Binary files a/lib/yui/build/moodle-core-checknet/moodle-core-checknet-min.js and b/lib/yui/build/moodle-core-checknet/moodle-core-checknet-min.js differ
index a08ce4d..a89d4d1 100644 (file)
Binary files a/lib/yui/build/moodle-core-checknet/moodle-core-checknet.js and b/lib/yui/build/moodle-core-checknet/moodle-core-checknet.js differ
index 42e92db..04572af 100644 (file)
@@ -144,10 +144,10 @@ Y.extend(CheckNet, Y.Base, {
          *
          * @attribute timeout
          * @type Number
-         * @value 2000
+         * @value 4000
          */
         timeout: {
-            value: 2000
+            value: 4000
         },
 
         /**
@@ -157,10 +157,10 @@ Y.extend(CheckNet, Y.Base, {
          * @attribute frequency
          * @writeOnce
          * @type Number
-         * @value 5000
+         * @value 10000
          */
         frequency: {
-            value: 5000
+            value: 10000
         },
 
         /**
index 061b738..415ada9 100644 (file)
@@ -41,7 +41,7 @@ class backup_choice_activity_structure_step extends backup_activity_structure_st
             'name', 'intro', 'introformat', 'publish',
             'showresults', 'display', 'allowupdate', 'showunanswered',
             'limitanswers', 'timeopen', 'timeclose', 'timemodified',
-            'completionsubmit', 'showpreview'));
+            'completionsubmit', 'showpreview', 'includeinactive'));
 
         $options = new backup_nested_element('options');
 
index 8291b8e..0e3cdcb 100644 (file)
@@ -18,6 +18,7 @@
         <FIELD NAME="allowupdate" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="allowmultiple" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="showunanswered" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="includeinactive" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
         <FIELD NAME="limitanswers" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="timeopen" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="timeclose" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
index d745ff3..53f932a 100644 (file)
@@ -80,6 +80,21 @@ function xmldb_choice_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2014111001, 'choice');
     }
 
+    if ($oldversion < 2014111002) {
+
+        // Define field includeinactive to be added to choice.
+        $table = new xmldb_table('choice');
+        $field = new xmldb_field('includeinactive', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1', 'showunanswered');
+
+        // Conditionally launch add field includeactive.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Choice savepoint reached.
+        upgrade_mod_savepoint(true, 2014111002, 'choice');
+    }
+
     return true;
 }
 
index f3d60bc..8e57741 100644 (file)
@@ -62,6 +62,7 @@ $string['choicesaved'] = 'Your choice has been saved';
 $string['choicetext'] = 'Choice text';
 $string['chooseaction'] = 'Choose an action ...';
 $string['description'] = 'Description';
+$string['includeinactive'] = 'Include responses from inactive/suspended users';
 $string['limit'] = 'Limit';
 $string['limitno'] = 'Limit {no}';
 $string['limitanswers'] = 'Limit the number of responses allowed';
index fff0e08..8d62076 100644 (file)
@@ -697,9 +697,10 @@ function choice_reset_userdata($data) {
  * @param object $choice
  * @param object $cm
  * @param int $groupmode
+ * @param bool $onlyactive Whether to get response data for active users only.
  * @return array
  */
-function choice_get_response_data($choice, $cm, $groupmode) {
+function choice_get_response_data($choice, $cm, $groupmode, $onlyactive) {
     global $CFG, $USER, $DB;
 
     $context = context_module::instance($cm->id);
@@ -716,7 +717,8 @@ function choice_get_response_data($choice, $cm, $groupmode) {
 
 /// First get all the users who have access here
 /// To start with we assume they are all "unanswered" then move them later
-    $allresponses[0] = get_enrolled_users($context, 'mod/choice:choose', $currentgroup, user_picture::fields('u', array('idnumber')));
+    $allresponses[0] = get_enrolled_users($context, 'mod/choice:choose', $currentgroup,
+            user_picture::fields('u', array('idnumber')), null, 0, 0, $onlyactive);
 
 /// Get all the recorded responses for this choice
     $rawresponses = $DB->get_records('choice_answers', array('choiceid' => $choice->id));
@@ -790,10 +792,14 @@ function choice_extend_settings_navigation(settings_navigation $settings, naviga
         if ($groupmode) {
             groups_get_activity_group($PAGE->cm, true);
         }
-        // We only actually need the choice id here
-        $choice = new stdClass;
-        $choice->id = $PAGE->cm->instance;
-        $allresponses = choice_get_response_data($choice, $PAGE->cm, $groupmode);   // Big function, approx 6 SQL calls per user
+
+        $choice = choice_get_choice($PAGE->cm->instance);
+
+        // Check if we want to include responses from inactive users.
+        $onlyactive = $choice->includeinactive ? false : true;
+
+        // Big function, approx 6 SQL calls per user.
+        $allresponses = choice_get_response_data($choice, $PAGE->cm, $groupmode, $onlyactive);
 
         $responsecount =0;
         foreach($allresponses as $optionid => $userlist) {
index 9b9e495..0e5cfbc 100644 (file)
@@ -93,6 +93,8 @@ class mod_choice_mod_form extends moodleform_mod {
 
         $mform->addElement('selectyesno', 'showunanswered', get_string("showunanswered", "choice"));
 
+        $mform->addElement('selectyesno', 'includeinactive', get_string('includeinactive', 'choice'));
+        $mform->setDefault('includeinactive', 0);
 
 //-------------------------------------------------------------------------------
         $this->standard_coursemodule_elements();
index d5c2f4a..9620cf1 100644 (file)
     } else {
         $groupmode = groups_get_activity_groupmode($cm);
     }
-    $users = choice_get_response_data($choice, $cm, $groupmode);
+
+    // Check if we want to include responses from inactive users.
+    $onlyactive = $choice->includeinactive ? false : true;
+
+    $users = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);
 
     if ($download == "ods" && has_capability('mod/choice:downloadresponses', $context)) {
         require_once("$CFG->libdir/odslib.class.php");
diff --git a/mod/choice/tests/behat/include_inactive.feature b/mod/choice/tests/behat/include_inactive.feature
new file mode 100644 (file)
index 0000000..0352f0f
--- /dev/null
@@ -0,0 +1,143 @@
+@mod @mod_choice
+Feature: Include responses from inactive users
+  In order to view responses from inactive or suspended users in choice results
+  As a teacher
+  I need to enable the choice include inactive option
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+      | student1 | Student | 1 | student1@asd.com |
+      | student2 | Student | 2 | student2@asd.com |
+      | student3 | Student | 3 | student3@asd.com |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+
+  @javascript
+  Scenario: Enable the choice include inactive option and check that responses from inactive students are visible
+    Given I add a "Choice" to section "1" and I fill the form with:
+      | Choice name | Choice name |
+      | Description | Choice Description |
+      | option[0] | Option 1 |
+      | option[1] | Option 2 |
+      | option[2] | Option 3 |
+      | Include responses from inactive/suspended users | Yes |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I choose "Option 1" from "Choice name" choice activity
+    And I log out
+    And I log in as "student2"
+    And I follow "Course 1"
+    And I choose "Option 2" from "Choice name" choice activity
+    And I log out
+    And I log in as "student3"
+    And I follow "Course 1"
+    And I choose "Option 3" from "Choice name" choice activity
+    And I log out
+    And the following "course enrolments" exist:
+      | user | course | role | status |
+      | student1 | C1 | student | 1 |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Choice name"
+    Then I should see "View 3 responses"
+    And I follow "View 3 responses"
+    And I should see "Student 1"
+    And I should see "Student 2"
+    And I should see "Student 3"
+    And I log out
+    And the following "course enrolments" exist:
+      | user | course | role | timestart |
+      | student2 | C1 | student | 2145830400 |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Choice name"
+    Then I should see "View 3 responses"
+    And I follow "View 3 responses"
+    And I should see "Student 1"
+    And I should see "Student 2"
+    And I should see "Student 3"
+    And I log out
+    And the following "course enrolments" exist:
+      | user | course | role | timeend |
+      | student3 | C1 | student | 1425168000 |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Choice name"
+    Then I should see "View 3 responses"
+    And I follow "View 3 responses"
+    And I should see "Student 1"
+    And I should see "Student 2"
+    And I should see "Student 3"
+    And I log out
+
+  @javascript
+  Scenario: Disable the choice include inactive option and check that responses from inactive students are not visible
+    Given I add a "Choice" to section "1" and I fill the form with:
+      | Choice name | Choice name |
+      | Description | Choice Description |
+      | option[0] | Option 1 |
+      | option[1] | Option 2 |
+      | option[2] | Option 3 |
+      | Include responses from inactive/suspended users | No |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I choose "Option 1" from "Choice name" choice activity
+    And I log out
+    And I log in as "student2"
+    And I follow "Course 1"
+    And I choose "Option 2" from "Choice name" choice activity
+    And I log out
+    And I log in as "student3"
+    And I follow "Course 1"
+    And I choose "Option 3" from "Choice name" choice activity
+    And I log out
+    And the following "course enrolments" exist:
+      | user | course | role | status |
+      | student1 | C1 | student | 1 |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Choice name"
+    Then I should see "View 2 responses"
+    And I follow "View 2 responses"
+    And I should not see "Student 1"
+    And I should see "Student 2"
+    And I should see "Student 3"
+    And I log out
+    And the following "course enrolments" exist:
+      | user | course | role | timestart |
+      | student2 | C1 | student | 2145830400 |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Choice name"
+    Then I should see "View 1 responses"
+    And I follow "View 1 responses"
+    And I should not see "Student 1"
+    And I should not see "Student 2"
+    And I should see "Student 3"
+    And I log out
+    And the following "course enrolments" exist:
+      | user | course | role | timeend |
+      | student3 | C1 | student | 1425168000 |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Choice name"
+    Then I should see "View 0 responses"
+    And I follow "View 0 responses"
+    And I should not see "Student 1"
+    And I should not see "Student 2"
+    And I should not see "Student 3"
+    And I log out
index 0de84a5..154814c 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014111001;       // The current module version (Date: YYYYMMDDXX)