Merge branch 'mdl36506-master' of git://github.com/tlock/moodle
authorDavid Monllao <davidm@moodle.com>
Mon, 30 Mar 2015 02:31:44 +0000 (10:31 +0800)
committerDavid Monllao <davidm@moodle.com>
Mon, 30 Mar 2015 02:31:44 +0000 (10:31 +0800)
119 files changed:
admin/registration/lib.php
admin/repository.php
admin/tool/behat/cli/init.php
admin/tool/behat/cli/run.php
backup/moodle2/backup_stepslib.php
backup/moodle2/restore_stepslib.php
badges/criteria/award_criteria.php
badges/criteria/award_criteria_course.php
badges/criteria/award_criteria_overall.php
badges/criteria_action.php
badges/criteria_form.php
badges/criteria_settings.php
badges/renderer.php
badges/tests/badgeslib_test.php
badges/tests/behat/award_badge.feature
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
completion/classes/external.php [new file with mode: 0644]
completion/tests/externallib_test.php [new file with mode: 0644]
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/tests/guide_test.php
grade/report/user/styles.css
install/lang/oc_lnc/install.php [new file with mode: 0644]
lang/en/badges.php
lang/en/moodle.php
lib/classes/plugin_manager.php
lib/classes/plugininfo/repository.php
lib/classes/task/scheduled_task.php
lib/db/access.php
lib/db/install.xml
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/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
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/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/lesson.php
mod/lesson/locallib.php
mod/lesson/renderer.php
mod/lesson/tests/events_test.php
mod/lesson/version.php
mod/scorm/locallib.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/less/moodle/core.less
theme/bootstrapbase/style/moodle.css
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/messageselect.php
version.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 31fd40c..e01490e 100644 (file)
@@ -264,6 +264,7 @@ if (($action == 'edit') || ($action == 'new')) {
     $strshow = get_string('on', 'repository');
     $strhide = get_string('off', 'repository');
     $strdelete = get_string('disabled', 'repository');
+    $struninstall = get_string('uninstallplugin', 'core_admin');
 
     $actionchoicesforexisting = array(
         'show' => $strshow,
@@ -286,9 +287,9 @@ if (($action == 'edit') || ($action == 'new')) {
 
     // Table to list plug-ins
     $table = new html_table();
-    $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
+    $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr, $struninstall);
 
-    $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
+    $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
     $table->id = 'repositoriessetting';
     $table->data = array();
     $table->attributes['class'] = 'admintable generaltable';
@@ -384,7 +385,12 @@ if (($action == 'edit') || ($action == 'new')) {
 
             $updowncount++;
 
-            $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings);
+            $uninstall = '';
+            if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('repository_' . $typename, 'manage')) {
+                $uninstall = html_writer::link($uninstallurl, $struninstall);
+            }
+
+            $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings, $uninstall);
 
             if (!in_array($typename, $alreadyplugins)) {
                 $alreadyplugins[] = $typename;
@@ -400,7 +406,11 @@ if (($action == 'edit') || ($action == 'new')) {
             if (!in_array($plugin, $alreadyplugins)) {
                 $select = new single_select(repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
                 $select->set_label(get_string('action'), array('class' => 'accesshide'));
-                $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
+                $uninstall = '';
+                if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('repository_' . $plugin, 'manage')) {
+                    $uninstall = html_writer::link($uninstallurl, $struninstall);
+                }
+                $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '', $uninstall);
             }
         }
     }
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 . '"';
 }
index c761eba..edad7c9 100644 (file)
@@ -825,7 +825,7 @@ class backup_badges_structure_step extends backup_structure_step {
 
         $criteria = new backup_nested_element('criteria');
         $criterion = new backup_nested_element('criterion', array('id'), array('badgeid',
-                'criteriatype', 'method'));
+                'criteriatype', 'method', 'description', 'descriptionformat'));
 
         $parameters = new backup_nested_element('parameters');
         $parameter = new backup_nested_element('parameter', array('id'), array('critid',
index ca66102..209f97d 100644 (file)
@@ -2269,9 +2269,11 @@ class restore_badges_structure_step extends restore_structure_step {
         $data = (object)$data;
 
         $params = array(
-                'badgeid'      => $this->get_new_parentid('badge'),
-                'criteriatype' => $data->criteriatype,
-                'method'       => $data->method
+                'badgeid'           => $this->get_new_parentid('badge'),
+                'criteriatype'      => $data->criteriatype,
+                'method'            => $data->method,
+                'description'       => isset($data->description) ? $data->description : '',
+                'descriptionformat' => isset($data->descriptionformat) ? $data->descriptionformat : 0,
         );
         $newid = $DB->insert_record('badge_criteria', $params);
         $this->set_mapping('criterion', $data->id, $newid);
index 8cc0a08..58ccf86 100644 (file)
@@ -88,9 +88,40 @@ $BADGE_CRITERIA_TYPES = array(
  */
 abstract class award_criteria {
 
+    /**
+     * ID of the criterion.
+     * @var integer
+     */
     public $id;
+
+    /**
+     * Aggregation method [BADGE_CRITERIA_AGGREGATION_ANY, BADGE_CRITERIA_AGGREGATION_ALL].
+     * @var integer
+     */
     public $method;
+
+    /**
+     * ID of a badge this criterion belongs to.
+     * @var integer
+     */
     public $badgeid;
+
+    /**
+     * Criterion HTML/plain text description.
+     * @var string
+     */
+    public $description;
+
+    /**
+     * Format of the criterion description.
+     * @var integer
+     */
+    public $descriptionformat;
+
+    /**
+     * Any additional parameters.
+     * @var array
+     */
     public $params = array();
 
     /**
@@ -102,6 +133,8 @@ abstract class award_criteria {
         $this->id = isset($params['id']) ? $params['id'] : 0;
         $this->method = isset($params['method']) ? $params['method'] : BADGE_CRITERIA_AGGREGATION_ANY;
         $this->badgeid = $params['badgeid'];
+        $this->description = isset($params['description']) ? $params['description'] : '';
+        $this->descriptionformat = isset($params['descriptionformat']) ? $params['descriptionformat'] : FORMAT_HTML;
         if (isset($params['id'])) {
             $this->params = $this->get_params($params['id']);
         }
@@ -220,6 +253,14 @@ abstract class award_criteria {
         }
         echo $OUTPUT->heading($this->get_title() . $OUTPUT->help_icon('criteria_' . $this->criteriatype, 'badges'), 3, 'main help');
 
+        if (!empty($this->description)) {
+            $badge = new badge($this->badgeid);
+            echo $OUTPUT->box(
+                format_text($this->description, $this->descriptionformat, array('context' => $badge->get_context())),
+                'criteria-description'
+                );
+        }
+
         if (!empty($this->params)) {
             if (count($this->params) > 1) {
                 echo $OUTPUT->box(get_string('criteria_descr_' . $this->criteriatype, 'badges',
@@ -305,23 +346,38 @@ abstract class award_criteria {
 
     /**
      * Saves intial criteria records with required parameters set up.
+     *
+     * @param array $params Values from the form or any other array.
      */
     public function save($params = array()) {
         global $DB;
+
+        // Figure out criteria description.
+        // If it is coming from the form editor, it is an array(text, format).
+        $description = '';
+        $descriptionformat = FORMAT_HTML;
+        if (isset($params['description']['text'])) {
+            $description = $params['description']['text'];
+            $descriptionformat = $params['description']['format'];
+        } else if (isset($params['description'])) {
+            $description = $params['description'];
+        }
+
         $fordb = new stdClass();
         $fordb->criteriatype = $this->criteriatype;
-        $fordb->method = isset($params->agg) ? $params->agg : $params['agg'];
+        $fordb->method = isset($params['agg']) ? $params['agg'] : BADGE_CRITERIA_AGGREGATION_ALL;
         $fordb->badgeid = $this->badgeid;
+        $fordb->description = $description;
+        $fordb->descriptionformat = $descriptionformat;
         $t = $DB->start_delegated_transaction();
 
-        // Unset unnecessary parameters supplied with form.
-        if (isset($params->agg)) {
-            unset($params->agg);
-        } else {
-            unset($params['agg']);
-        }
-        unset($params->submitbutton);
-        $params = array_filter((array)$params);
+        // Pick only params that are required by this criterion.
+        // Filter out empty values first.
+        $params = array_filter($params);
+        // Find out which param matches optional and required ones.
+        $match = array_merge($this->optional_params, array($this->required_param));
+        $regex = implode('|', array_map(create_function('$a', 'return $a . "_";'), $match));
+        $requiredkeys = preg_grep('/^(' . $regex . ').*$/', array_keys($params));
 
         if ($this->id !== 0) {
             $cid = $this->id;
@@ -331,7 +387,7 @@ abstract class award_criteria {
             $DB->update_record('badge_criteria', $fordb, true);
 
             $existing = $DB->get_fieldset_select('badge_criteria_param', 'name', 'critid = ?', array($cid));
-            $todelete = array_diff($existing, array_keys($params));
+            $todelete = array_diff($existing, $requiredkeys);
 
             if (!empty($todelete)) {
                 // A workaround to add some disabled elements that are still being submitted from the form.
@@ -349,32 +405,32 @@ abstract class award_criteria {
                 $DB->delete_records_select('badge_criteria_param', 'critid = :critid AND name ' . $sql, $sqlparams);
             }
 
-            foreach ($params as $key => $value) {
+            foreach ($requiredkeys as $key) {
                 if (in_array($key, $existing)) {
                     $updp = $DB->get_record('badge_criteria_param', array('name' => $key, 'critid' => $cid));
-                    $updp->value = $value;
+                    $updp->value = $params[$key];
                     $DB->update_record('badge_criteria_param', $updp, true);
                 } else {
                     $newp = new stdClass();
                     $newp->critid = $cid;
                     $newp->name = $key;
-                    $newp->value = $value;
+                    $newp->value = $params[$key];
                     $DB->insert_record('badge_criteria_param', $newp);
                 }
             }
         } else {
             $cid = $DB->insert_record('badge_criteria', $fordb, true);
             if ($cid) {
-                foreach ($params as $key => $value) {
+                foreach ($requiredkeys as $key) {
                     $newp = new stdClass();
                     $newp->critid = $cid;
                     $newp->name = $key;
-                    $newp->value = $value;
+                    $newp->value = $params[$key];
                     $DB->insert_record('badge_criteria_param', $newp, false, true);
                 }
             }
-         }
-         $t->allow_commit();
+        }
+        $t->allow_commit();
     }
 
     /**
@@ -387,6 +443,8 @@ abstract class award_criteria {
         $fordb->criteriatype = $this->criteriatype;
         $fordb->method = $this->method;
         $fordb->badgeid = $newbadgeid;
+        $fordb->description = $this->description;
+        $fordb->descriptionformat = $this->descriptionformat;
         if (($newcrit = $DB->insert_record('badge_criteria', $fordb, true)) && isset($this->params)) {
             foreach ($this->params as $k => $param) {
                 foreach ($param as $key => $value) {
index 295d927..2582365 100644 (file)
@@ -75,6 +75,15 @@ class award_criteria_course extends award_criteria {
         }
         echo $OUTPUT->heading($this->get_title() . $OUTPUT->help_icon('criteria_' . $this->criteriatype, 'badges'), 3, 'main help');
 
+        if (!empty($this->description)) {
+            echo $OUTPUT->box(
+                format_text($this->description, $this->descriptionformat,
+                        array('context' => context_course::instance($this->courseid))
+                ),
+                'criteria-description'
+            );
+        }
+
         if (!empty($this->params)) {
             echo $OUTPUT->box(get_string('criteria_descr_' . $this->criteriatype, 'badges') . $this->get_details(), array('clearfix'));
         }
index 91a6a9d..7d6aad8 100644 (file)
@@ -45,10 +45,27 @@ class award_criteria_overall extends award_criteria {
         $prefix = 'criteria-' . $this->id;
         if (count($data->criteria) > 2) {
             echo $OUTPUT->box_start();
+            if (!empty($this->description)) {
+                $badge = new badge($this->badgeid);
+                echo $OUTPUT->box(
+                    format_text($this->description, $this->descriptionformat, array('context' => $badge->get_context())),
+                    'criteria-description');
+            }
             echo $OUTPUT->heading($this->get_title(), 2);
 
             $agg = $data->get_aggregation_methods();
             if (!$data->is_locked() && !$data->is_active()) {
+                $editurl = new moodle_url('/badges/criteria_settings.php',
+                               array('badgeid' => $this->badgeid,
+                                   'edit' => true,
+                                   'type' => $this->criteriatype,
+                                   'crit' => $this->id
+                               )
+                        );
+                $editaction = $OUTPUT->action_icon($editurl, new pix_icon('t/edit', get_string('edit')), null,
+                              array('class' => 'criteria-action'));
+                echo $OUTPUT->box($editaction, array('criteria-header'));
+
                 $url = new moodle_url('criteria.php', array('id' => $data->id, 'sesskey' => sesskey()));
                 $table = new html_table();
                 $table->attributes = array('class' => 'clearfix');
@@ -155,4 +172,38 @@ class award_criteria_overall extends award_criteria {
      */
     public function get_params($cid) {
     }
-}
\ No newline at end of file
+
+    /**
+     * Saves overall badge criteria description.
+     *
+     * @param array $params Values from the form or any other array.
+     */
+    public function save($params = array()) {
+        global $DB;
+
+        // Sort out criteria description.
+        // If it is coming from the form editor, it is an array of (text, format).
+        $description = '';
+        $descriptionformat = FORMAT_HTML;
+        if (isset($params['description']['text'])) {
+            $description = $params['description']['text'];
+            $descriptionformat = $params['description']['format'];
+        } else if (isset($params['description'])) {
+            $description = $params['description'];
+        }
+
+        $fordb = new stdClass();
+        $fordb->criteriatype = $this->criteriatype;
+        $fordb->badgeid = $this->badgeid;
+        $fordb->description = $description;
+        $fordb->descriptionformat = $descriptionformat;
+        if ($this->id !== 0) {
+            $fordb->id = $this->id;
+            $DB->update_record('badge_criteria', $fordb);
+        } else {
+            // New record in DB, set aggregation to ALL by default.
+            $fordb->method = BADGE_CRITERIA_AGGREGATION_ALL;
+            $DB->insert_record('badge_criteria', $fordb);
+        }
+    }
+}
index 3af6984..aef6ca0 100644 (file)
@@ -61,6 +61,9 @@ $PAGE->set_heading($badge->name);
 $PAGE->set_title($badge->name);
 
 if ($delete && has_capability('moodle/badges:configurecriteria', $context)) {
+    if ($type == BADGE_CRITERIA_TYPE_OVERALL) {
+        redirect($return, get_string('error:cannotdeletecriterion', 'badges'));
+    }
     if (!$confirm) {
         $optionsyes = array('confirm' => 1, 'sesskey' => sesskey(), 'badgeid' => $badgeid, 'delete' => true, 'type' => $type);
 
index 208060d..c8d18d1 100644 (file)
@@ -55,6 +55,15 @@ class edit_criteria_form extends moodleform {
                 $mform->addElement('html', html_writer::tag('div', $message));
                 $mform->addElement('submit', 'cancel', get_string('continue'));
             } else {
+                $mform->addElement('header', 'description_header', get_string('description'));
+                $mform->addElement('editor', 'description', '', null, null);
+                $mform->setType('description', PARAM_RAW);
+                $mform->setDefault('description', array(
+                        'text' => $criteria->description,
+                        'format' => $criteria->descriptionformat
+                    )
+                );
+
                 $mform->closeHeaderBefore('buttonar');
                 $this->add_action_buttons(true, get_string('save', 'badges'));
             }
@@ -69,7 +78,7 @@ class edit_criteria_form extends moodleform {
         $errors = parent::validation($data, $files);
         $addcourse = $this->_customdata['addcourse'];
 
-        if (!$addcourse) {
+        if (!$addcourse && isset($this->_customdata['criteria']->required_param)) {
             $required = $this->_customdata['criteria']->required_param;
             $pattern1 = '/^' . $required . '_(\d+)$/';
             $pattern2 = '/^' . $required . '_(\w+)$/';
@@ -91,4 +100,4 @@ class edit_criteria_form extends moodleform {
         }
         return $errors;
     }
-}
\ No newline at end of file
+}
index 32efa61..d31f3ab 100644 (file)
@@ -65,8 +65,9 @@ if ($badge->type == BADGE_TYPE_COURSE) {
     navigation_node::override_active_url($navurl, true);
 }
 
+$urlparams = array('badgeid' => $badgeid, 'edit' => $edit, 'type' => $type, 'crit' => $crit);
 $PAGE->set_context($context);
-$PAGE->set_url('/badges/criteria_settings.php');
+$PAGE->set_url('/badges/criteria_settings.php', $urlparams);
 $PAGE->set_heading($badge->name);
 $PAGE->set_title($badge->name);
 $PAGE->navbar->add($badge->name, new moodle_url('overview.php', array('id' => $badge->id)))->add(get_string('criteria_' . $type, 'badges'));
@@ -100,7 +101,7 @@ if (!empty($addcourse)) {
         $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
         $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL));
     }
-    $criteria->save($data);
+    $criteria->save((array)$data);
     $return->param('msg', $msg);
     redirect($return);
 }
index 3632182..d4fad08 100644 (file)
@@ -704,32 +704,81 @@ class core_badges_renderer extends plugin_renderer_base {
         return null;
     }
 
-    // Prints badge criteria.
+    /**
+     * Returns information about badge criteria in a list form.
+     *
+     * @param badge $badge Badge objects
+     * @param string $short Indicates whether to print full info about this badge
+     * @return string $output HTML string to output
+     */
     public function print_badge_criteria(badge $badge, $short = '') {
-        $output = "";
         $agg = $badge->get_aggregation_methods();
         if (empty($badge->criteria)) {
             return get_string('nocriteria', 'badges');
-        } else if (count($badge->criteria) == 2) {
+        }
+
+        $overalldescr = '';
+        $overall = $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL];
+        if (!$short && !empty($overall->description)) {
+            $overalldescr = $this->output->box(
+                format_text($overall->description, $overall->descriptionformat, array('context' => $badge->get_context())),
+                'criteria-description'
+                );
+        }
+
+        // Get the condition string.
+        if (count($badge->criteria) == 2) {
+            $condition = '';
             if (!$short) {
-                $output .= get_string('criteria_descr', 'badges');
+                $condition = get_string('criteria_descr', 'badges');
             }
         } else {
-            $output .= get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
-                                    core_text::strtoupper($agg[$badge->get_aggregation_method()]));
+            $condition = get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
+                                      core_text::strtoupper($agg[$badge->get_aggregation_method()]));
         }
-        $items = array();
+
         unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
-        foreach ($badge->criteria as $type => $c) {
+
+        $items = array();
+        // If only one criterion left, make sure its description goe to the top.
+        if (count($badge->criteria) == 1) {
+            $c = reset($badge->criteria);
+            if (!$short && !empty($c->description)) {
+                $overalldescr = $this->output->box(
+                    format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
+                    'criteria-description'
+                    );
+            }
             if (count($c->params) == 1) {
-                $items[] = get_string('criteria_descr_single_' . $short . $type , 'badges') . $c->get_details($short);
+                $items[] = get_string('criteria_descr_single_' . $short . $c->criteriatype , 'badges') .
+                           $c->get_details($short);
             } else {
-                $items[] = get_string('criteria_descr_' . $short . $type , 'badges',
-                        core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) . $c->get_details($short);
+                $items[] = get_string('criteria_descr_' . $short . $c->criteriatype, 'badges',
+                        core_text::strtoupper($agg[$badge->get_aggregation_method($c->criteriatype)])) .
+                        $c->get_details($short);
+            }
+        } else {
+            foreach ($badge->criteria as $type => $c) {
+                $criteriadescr = '';
+                if (!$short && !empty($c->description)) {
+                    $criteriadescr = $this->output->box(
+                        format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
+                        'criteria-description'
+                        );
+                }
+                if (count($c->params) == 1) {
+                    $items[] = get_string('criteria_descr_single_' . $short . $type , 'badges') .
+                               $c->get_details($short) . $criteriadescr;
+                } else {
+                    $items[] = get_string('criteria_descr_' . $short . $type , 'badges',
+                            core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) .
+                            $c->get_details($short) .
+                            $criteriadescr;
+                }
             }
         }
-        $output .= html_writer::alist($items, array(), 'ul');
-        return $output;
+
+        return $overalldescr . $condition . html_writer::alist($items, array(), 'ul');;
     }
 
     // Prints criteria actions for badge editing.
index dc3f151..b628431 100644 (file)
@@ -152,6 +152,28 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
         $this->assertCount(2, $badge->get_criteria());
     }
 
+    public function test_add_badge_criteria_description() {
+        $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $this->badgeid));
+        $criteriaoverall->save(array(
+                'agg' => BADGE_CRITERIA_AGGREGATION_ALL,
+                'description' => 'Overall description',
+                'descriptionformat' => FORMAT_HTML
+        ));
+
+        $criteriaprofile = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $this->badgeid));
+        $params = array(
+                'agg' => BADGE_CRITERIA_AGGREGATION_ALL,
+                'field_address' => 'address',
+                'description' => 'Description',
+                'descriptionformat' => FORMAT_HTML
+        );
+        $criteriaprofile->save($params);
+
+        $badge = new badge($this->badgeid);
+        $this->assertEquals('Overall description', $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->description);
+        $this->assertEquals('Description', $badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->description);
+    }
+
     public function test_delete_badge_criteria() {
         $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $this->badgeid));
         $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL));
index bf504b0..a4e5cd4 100644 (file)
@@ -16,13 +16,17 @@ Feature: Award badges
     And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
     And I press "Create badge"
     And I set the field "type" to "Profile completion"
+    And I expand all fieldsets
     And I set the field "First name" to "1"
     And I set the field "Email address" to "1"
     And I set the field "Phone" to "1"
+    And I set the field "id_description" to "Criterion description"
     When I press "Save"
     Then I should see "Profile completion"
     And I should see "First name"
     And I should see "Email address"
+    And I should see "Phone"
+    And I should see "Criterion description"
     And I should not see "Criteria for this badge have not been set up yet."
     And I press "Enable access"
     And I press "Continue"
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..85cceef
--- /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 (is_dir($CFG->dirroot . '/blocks/activity_results')) {
+
+            // 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 10805f6..605c328 100644 (file)
@@ -2967,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);
@@ -2979,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;
 
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 ef638b3..3d485ae 100644 (file)
@@ -302,8 +302,8 @@ abstract class moodleform_mod extends moodleform {
         // 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 (isset($data['gradepass']) && (!empty($data['grade']) || !empty($data['scale']))) {
+            $scale = !empty($data['grade']) ? $data['grade'] : $data['scale'];
             if ($scale < 0) {
                 $scalevalues = $DB->get_record('scale', array('id' => -$scale));
                 $grade = count(explode(',', $scalevalues->scale));
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 f736bbc..5bf953e 100644 (file)
@@ -18,7 +18,7 @@
  * Unit tests for Marking Guide grading method.
  *
  * @package    gradingform_guide
- * @category   phpunit
+ * @category   test
  * @copyright  2015 Nikita Kalinin <nixorv@gmail.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -33,7 +33,7 @@ require_once($CFG->dirroot . '/grade/grading/form/guide/lib.php');
  * Test cases for the Marking Guide.
  *
  * @package    gradingform_guide
- * @category   phpunit
+ * @category   test
  * @copyright  2015 Nikita Kalinin <nixorv@gmail.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 614ccca..7695995 100644 (file)
     min-width: 4.5em;
     vertical-align: top;
 }
+.dir-rtl.path-grade-report-user .user-grade td {
+    direction: ltr;
+}
+.dir-rtl.path-grade-report-user table.user-grade {
+    border-collapse: separate;
+}
 .path-grade-report-user .user-grade .b1l {
     padding: 0;
     width:24px;
@@ -59,4 +65,4 @@
 .dir-rtl.path-grade-report-user .user-grade .column-itemname.baggt,
 .dir-rtl.path-grade-report-user .user-grade .column-itemname.baggb {
     padding-right: 24px;
-}
\ No newline at end of file
+}
diff --git a/install/lang/oc_lnc/install.php b/install/lang/oc_lnc/install.php
new file mode 100644 (file)
index 0000000..5c232b0
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['availablelangs'] = 'Paquetatges de lenga disponibles';
+$string['chooselanguagehead'] = 'Causissètz una lenga';
+$string['databasehost'] = 'Servidor de banca de donadas';
+$string['databasename'] = 'Nom de la banca de donadas';
+$string['databasetypehead'] = 'Seleccionar un pilòt de banca de donadas';
index ce03b75..7169f37 100644 (file)
@@ -218,6 +218,7 @@ $string['error:backpackproblem'] = 'There was a problem connecting to your backp
 $string['error:badjson'] = 'The connection attempt returned invalid data.';
 $string['error:cannotact'] = 'Cannot activate the badge. ';
 $string['error:cannotawardbadge'] = 'Cannot award badge to a user.';
+$string['error:cannotdeletecriterion'] = 'This criterion cannot be deleted. ';
 $string['error:connectionunknownreason'] = 'The connection was unsuccessful but no reason was given.';
 $string['error:clone'] = 'Cannot clone the badge.';
 $string['error:duplicatename'] = 'Badge with such name already exists in the system.';
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 487b137..861b24d 100644 (file)
@@ -67,4 +67,34 @@ class repository extends base {
     public static function get_manage_url() {
         return new moodle_url('/admin/repository.php');
     }
+
+    /**
+     * Defines if there should be a way to uninstall the plugin via the administration UI.
+     * @return boolean
+     */
+    public function is_uninstall_allowed() {
+        if ($this->name === 'upload' || $this->name === 'coursefiles' || $this->name === 'user' || $this->name === 'recent') {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Pre-uninstall hook.
+     * This is intended for disabling of plugin, some DB table purging, etc.
+     * Converts all linked files to standard files when repository is removed
+     * and cleans up all records in the DB for that repository.
+     */
+    public function uninstall_cleanup() {
+        global $CFG;
+        require_once($CFG->dirroot.'/repository/lib.php');
+
+        $repo = \repository::get_type_by_typename($this->name);
+        if ($repo) {
+            $repo->delete(true);
+        }
+
+        parent::uninstall_cleanup();
+    }
 }
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 08a8c86..e8fac11 100644 (file)
@@ -1982,6 +1982,7 @@ $capabilities = array(
 
     // Set up/edit criteria of earning a badge.
     'moodle/badges:configurecriteria' => array(
+        'riskbitmask'  => RISK_XSS,
         'captype'      => 'write',
         'contextlevel' => CONTEXT_COURSE,
         'archetypes'   => array(
index a9ea1a8..da0ef3b 100644 (file)
         <FIELD NAME="badgeid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="criteriatype" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The criteria type we are aggregating"/>
         <FIELD NAME="method" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="1 = all, 2 = any"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
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 a198c09..f5461f7 100644 (file)
@@ -4247,5 +4247,28 @@ 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');
+
+        $field = new xmldb_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
+        // Conditionally add description field to the badge_criteria table.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        $field = new xmldb_field('descriptionformat', XMLDB_TYPE_INTEGER, 2, null, XMLDB_NOTNULL, null, 0);
+        // Conditionally add description format field to the badge_criteria table.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        upgrade_main_savepoint(true, 2015032000.00);
+    }
+
     return true;
 }
index 4cf531c..f0a64d2 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 ee5d8be..4a2dac8 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 51da696..07dbddc 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 e801fe1..f7a3ecf 100644 (file)
@@ -84,49 +84,35 @@ 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, link.
-            {regex: /<(\/?title|\/?meta|\/?style|\/?st\d|\/?head|\/?font|\/?html|\/?body|\/?link|!\[)[^>]*?>/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: '...'}
+            {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);
@@ -188,7 +174,7 @@ EditorClean.prototype = {
                     sourceEvent.preventDefault();
 
                     // Scrub the paste content.
-                    content = this._cleanHTML(content);
+                    content = this._cleanPasteHTML(content);
 
                     // Save the current selection.
                     // Using saveSelection as it produces a more consistent experience.
@@ -237,7 +223,7 @@ EditorClean.prototype = {
 
         // Get, clean, and replace the content in the editable.
         var content = this.editor.get('innerHTML');
-        this.editor.set('innerHTML', this._cleanHTML(content));
+        this.editor.set('innerHTML', this._cleanPasteHTML(content));
 
         // Update the textarea.
         this.updateOriginal();
@@ -258,6 +244,79 @@ EditorClean.prototype = {
         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 all garbage after closing html tag.
+            {regex: /<\s*\/html\s*>([\s\S]+)$/gi, replace: ""},
+            // 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, but not ones from Rangy.
+            {regex: /<span(?![^>]*?rangySelectionBoundary[^>]*?)[^>]*>(&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 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 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"