Compare commits
263 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c948f378b9 | |||
| 9ecb4e3abd | |||
| 17bb213dd3 | |||
| 3c23a2cd2e | |||
| 461f479dde | |||
| 8946171eca | |||
| 038b33f0fd | |||
| ff6fe05733 | |||
| 9ca6dcd3ba | |||
| 7d803c4c52 | |||
| 5ab9f04410 | |||
| 9b84c81dfd | |||
| 4a6ed0cf53 | |||
| c81c8a2ae8 | |||
| e6ad444ea1 | |||
| e87f4d63c3 | |||
| a809a8dcce | |||
| 6314335c49 | |||
| 3cb39c2a04 | |||
| 30e59bbc21 | |||
| e228ce6e04 | |||
| d2cb356582 | |||
| 46460a2303 | |||
| 0b715c77f2 | |||
| adb234e19d | |||
| 5656fdb9c9 | |||
| 5710353976 | |||
| 9580c08e9e | |||
| a2f36ceef5 | |||
| d3e9d99ccb | |||
| a603cb5af4 | |||
| f9b6810d4e | |||
| 0b89c8dd85 | |||
| f521c1e769 | |||
| 4ca8ff532b | |||
| d5720db41e | |||
| b04406e697 | |||
| 064cfdff92 | |||
| dfec225a37 | |||
| b4faba939d | |||
| 5409b5a7ec | |||
| 8f683efff3 | |||
| d68806edf9 | |||
| a8646c70fa | |||
| d783a8fba7 | |||
| 147aca3043 | |||
| 532acaf5ac | |||
| bc7b926591 | |||
| b3892e62a5 | |||
| e09d38647b | |||
| 005ead1f8a | |||
| c5bc16fe8a | |||
| cdca00ca81 | |||
| b29b31dc12 | |||
| 4342a37310 | |||
| 824bbbcb3f | |||
| fd954ad01b | |||
| 5edd9315d1 | |||
| 9c4b068082 | |||
| e806e2c9f7 | |||
| ba0e10425f | |||
| 0c2db45a76 | |||
| 3f33350e0d | |||
| c9f8064b23 | |||
| e107f6227c | |||
| f5273c374f | |||
| 0e1a2090b8 | |||
| 1ee0876d3d | |||
| a6640dcbe5 | |||
| 73441dca38 | |||
| f8cc4ea4a1 | |||
| 9d1d7caafd | |||
| d88fa5e681 | |||
| 76ef7726e2 | |||
| 5ac3194c6f | |||
| 497e490a6b | |||
| 5b41ec52f7 | |||
| 45ced3d17d | |||
| 200e4da537 | |||
| 11189884a8 | |||
| ca587e8819 | |||
| bffd9c6ad2 | |||
| 0aa98ebda1 | |||
| 78c315db76 | |||
| 8ceecd98a8 | |||
| 775f5d6a9f | |||
| 99f4c550f2 | |||
| f102573e45 | |||
| b848eeacc8 | |||
| c74f2c3e70 | |||
| 95554b45b6 | |||
| 2bea2a1918 | |||
| f934fdf46c | |||
| 7d1d36e036 | |||
| ca4c8b1942 | |||
| d0a5d336f7 | |||
| 893d5e69a0 | |||
| f74ae05201 | |||
| 14e7f3c3b7 | |||
| 7c6d8dd8e0 | |||
| e82c2eb2b1 | |||
| 87cd84ddb7 | |||
| 531908df75 | |||
| ced7d04d07 | |||
| d16724b42b | |||
| e0a114e4f5 | |||
| 0d7f387b37 | |||
| b8e8cbf3bb | |||
| 887d0618cc | |||
| ab4665046a | |||
| 72e0a56673 | |||
| eaf0d255b4 | |||
| ebae161cdf | |||
| 691c2913bb | |||
| fce1153108 | |||
| 2817ff06ae | |||
| 61c8747a39 | |||
| 6e0401d61f | |||
| 3391ece9f8 | |||
| 6be25bc988 | |||
| 3eb9b4a316 | |||
| f872eef1e9 | |||
| 0624b774d0 | |||
| 3783dde956 | |||
| 98a8ef2777 | |||
| e3cd190100 | |||
| 9b1539c5d6 | |||
| d4990e4c94 | |||
| 99422f333b | |||
| 128a866390 | |||
| 1187ce03ec | |||
| 8f1d67ea09 | |||
| 97c9eaefa8 | |||
| ca0042ca80 | |||
| bc10960447 | |||
| 7d0bdbe264 | |||
| 4c07dea461 | |||
| b09e7b4c7d | |||
| c0be92c749 | |||
| ee4c6f78c6 | |||
| e003e65ea8 | |||
| b25bb3cf29 | |||
| 5d8cfda315 | |||
| 1f2fbac207 | |||
| 7955318e45 | |||
| 2799e8f70e | |||
| 69ece23a48 | |||
| a81d590726 | |||
| c3661ca0cc | |||
| 5be5d4d2c9 | |||
| 629f298ce7 | |||
| 8172729a07 | |||
| 78285d5c9c | |||
| 1fab00298d | |||
| e27f30b7c8 | |||
| 3af357dd2c | |||
| c5e83ccab0 | |||
| ea20d927ad | |||
| 6964dc6e73 | |||
| 80f8e00bd7 | |||
| 53f0b8ae3c | |||
| 377ec4c107 | |||
| 659c60614b | |||
| f0a7bbcd14 | |||
| 3372a99e13 | |||
| 6f7bf269b2 | |||
| a48f97d414 | |||
| 8f4a31ce65 | |||
| 4f27bea28b | |||
| caaf4113ce | |||
| 5ed79f4e97 | |||
| 1f797413d4 | |||
| 28e427c0f9 | |||
| 71b448e27d | |||
| 47596be087 | |||
| 199fbeb647 | |||
| 8389e416a4 | |||
| 3143816be1 | |||
| 5a561e90c3 | |||
| 314eb4342c | |||
| b73491b280 | |||
| d91491569c | |||
| a38b6660e4 | |||
| 18dd4e5d9b | |||
| 3d944b0454 | |||
| a8b977172a | |||
| deb125fa6d | |||
| 1cb3091780 | |||
| 3ac8f0c5e3 | |||
| 7ee737690a | |||
| e600df800c | |||
| b77a45c3a2 | |||
| 0e0e83abdf | |||
| 777f822fad | |||
| a694acd9b8 | |||
| 0676b9c186 | |||
| 5c5fb8bd8f | |||
| cdd1fcbf45 | |||
| 55cf90e9db | |||
| f59d6a6fcf | |||
| ad9131d75d | |||
| 6e54261fe8 | |||
| fdfea113b5 | |||
| 267238bac4 | |||
| 83a061c8e8 | |||
| e1cd01e60e | |||
| 32eb50d49b | |||
| c3b65cc9e9 | |||
| 544a4f57ec | |||
| 44ad175eda | |||
| 628bee355e | |||
| fcd6880e1e | |||
| 159a8fda78 | |||
| ecdadf2a18 | |||
| c1813cf5d9 | |||
| ed97ad100b | |||
| 609e3cfc0b | |||
| f2a6afba21 | |||
| 60fa8157f2 | |||
| 723f9b73eb | |||
| 4cf3969700 | |||
| 73cc1d04c9 | |||
| bd13927c47 | |||
| 198c3fb3f0 | |||
| 690725416b | |||
| 058b07958b | |||
| d5307d89e3 | |||
| d5df44623f | |||
| dfa7e964c5 | |||
| 7c964c9fac | |||
| d014bdea09 | |||
| 5c57e2ad47 | |||
| 7e41013038 | |||
| 35a0d15031 | |||
| aff87a12e2 | |||
| 954626a2b9 | |||
| 41c398aa5c | |||
| 0809c38938 | |||
| 69afba56e6 | |||
| 44be211cb2 | |||
| 3dd7be272f | |||
| ea3f6e2b75 | |||
| 22d4ded11f | |||
| 0161f4f957 | |||
| 383aa049c0 | |||
| 3257b829a8 | |||
| 38a659dc10 | |||
| 356c4ae63e | |||
| 3f87e8e54b | |||
| 859aac85c4 | |||
| 55f468ff62 | |||
| 2138e7eddc | |||
| f47d844c68 | |||
| f007447294 | |||
| 4590d1be1e | |||
| a236699367 | |||
| f461827532 | |||
| 406af5521c | |||
| a229c2fb0f | |||
| 057cf60bd7 | |||
| cd3cd9ffc3 | |||
| 5e236840b0 | |||
| 2107531f3c |
@@ -0,0 +1,103 @@
|
||||
<?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 script fixes orphaned question categories.
|
||||
*
|
||||
* Orphaned question categories have had their associated context deleted
|
||||
* but the category itself remains in the database with an invalid context.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage cli
|
||||
* @copyright 2013 Tyler Bannister (tyler.bannister@remote-learner.net)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php');
|
||||
require_once($CFG->libdir.'/questionlib.php');
|
||||
|
||||
$long = array('fix' => false, 'help' => false);
|
||||
$short = array('f' => 'fix', 'h' => 'help');
|
||||
|
||||
// Now get cli options.
|
||||
list($options, $unrecognized) = cli_get_params($long, $short);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help']) {
|
||||
$help =
|
||||
"Fix orphaned question categories.
|
||||
|
||||
This scripts detects question categories that have had their
|
||||
context deleted, thus severing them from their original purpose.
|
||||
|
||||
This script will find the orphaned categories and delete the unused
|
||||
questions in each category found. Used questions will not be
|
||||
deleted, instead they will be moved to a rescue question category.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
-f, --fix Fix the orphaned question categories in the DB.
|
||||
If not specified only check and report problems to STDERR.
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_question_categories.php
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_question_categories.php -f
|
||||
";
|
||||
|
||||
echo $help;
|
||||
die;
|
||||
}
|
||||
|
||||
cli_heading('Checking for orphaned categories');
|
||||
|
||||
|
||||
$sql = 'SELECT qc.id, qc.contextid, qc.name
|
||||
FROM {question_categories} qc
|
||||
LEFT JOIN {context} c ON qc.contextid = c.id
|
||||
WHERE c.id IS NULL';
|
||||
$categories = $DB->get_recordset_sql($sql);
|
||||
|
||||
$i = 0;
|
||||
foreach ($categories as $category) {
|
||||
$i += 1;
|
||||
echo "Found orphaned category: {$category->name}\n";
|
||||
if (!empty($options['fix'])) {
|
||||
echo "Cleaning...";
|
||||
// One transaction per category.
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
question_category_delete_safe($category);
|
||||
$transaction->allow_commit();
|
||||
echo " Done!\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (($i > 0) && !empty($options['fix'])) {
|
||||
echo "Found and removed {$i} orphaned question categories\n";
|
||||
} else if ($i > 0) {
|
||||
echo "Found {$i} orphaned question categories. To fix, run:\n";
|
||||
echo "\$sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_question_categories.php --fix\n";
|
||||
} else {
|
||||
echo "No orphaned question categories found.\n";
|
||||
}
|
||||
|
||||
|
||||
$categories->close();
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
echo '<div class="phpinfo">';
|
||||
|
||||
ob_start();
|
||||
phpinfo(INFO_GENERAL + INFO_CONFIGURATION + INFO_MODULES);
|
||||
phpinfo(INFO_GENERAL + INFO_CONFIGURATION + INFO_MODULES + INFO_VARIABLES);
|
||||
$html = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
|
||||
@@ -472,7 +472,9 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
}
|
||||
|
||||
protected function get_description_field($id) {
|
||||
return print_textarea(true, 10, 50, 50, 10, 'description', $this->role->description, 0, true);
|
||||
return '<textarea class="form-textarea" id="'. s($id) .'" name="description" rows="10" cols="50">' .
|
||||
htmlspecialchars($this->role->description) .
|
||||
'</textarea>';
|
||||
}
|
||||
|
||||
protected function get_archetype_field($id) {
|
||||
|
||||
@@ -46,7 +46,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$ADMIN->add('courses',
|
||||
new admin_externalpage('restorecourse', new lang_string('restorecourse', 'admin'),
|
||||
new moodle_url('/backup/restorefile.php', array('contextid' => context_system::instance()->id)),
|
||||
array('moodle/course:create')
|
||||
array('moodle/restore:restorecourse')
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
$temp->add(new admin_setting_special_gradepointdefault());
|
||||
|
||||
$temp->add(new admin_setting_special_grademinmaxtouse());
|
||||
|
||||
$temp->add(new admin_setting_my_grades_report());
|
||||
|
||||
$temp->add(new admin_setting_configtext('gradereport_mygradeurl', new lang_string('externalurl', 'grades'),
|
||||
|
||||
@@ -97,7 +97,7 @@ if (!empty($options['help'])) {
|
||||
$cwd = getcwd();
|
||||
|
||||
// For drop option check if parallel site.
|
||||
if ((empty($options['parallel'])) && $options['drop']) {
|
||||
if ((empty($options['parallel'])) && ($options['drop']) || $options['updatesteps']) {
|
||||
// Get parallel run info from first run.
|
||||
$options['parallel'] = behat_config_manager::get_parallel_test_runs($options['fromrun']);
|
||||
}
|
||||
@@ -172,6 +172,26 @@ if ($options['diag'] || $options['enable'] || $options['disable']) {
|
||||
}
|
||||
}
|
||||
|
||||
} else if ($options['updatesteps']) {
|
||||
// Rewrite config file to ensure we have all the features covered.
|
||||
if (empty($options['parallel'])) {
|
||||
behat_config_manager::update_config_file();
|
||||
} else {
|
||||
// Update config file, ensuring we have up-to-date behat.yml.
|
||||
for ($i = $options['fromrun']; $i <= $options['torun']; $i++) {
|
||||
$CFG->behatrunprocess = $i;
|
||||
behat_config_manager::update_config_file();
|
||||
}
|
||||
unset($CFG->behatrunprocess);
|
||||
}
|
||||
|
||||
// Do it sequentially as it's fast and need to be displayed nicely.
|
||||
foreach (array_chunk($cmds, 1, true) as $cmd) {
|
||||
$processes = cli_execute_parallel($cmd, __DIR__);
|
||||
print_sequential_output($processes);
|
||||
}
|
||||
exit(0);
|
||||
|
||||
} else {
|
||||
// We should never reach here.
|
||||
echo $help;
|
||||
|
||||
@@ -199,9 +199,6 @@ if ($options['install']) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Rewrite config file to ensure we have all the features covered.
|
||||
behat_config_manager::update_config_file();
|
||||
|
||||
// Run behat command to get steps in feature files.
|
||||
$featurestepscmd = behat_command::get_behat_command(true);
|
||||
$featurestepscmd .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
|
||||
@@ -263,6 +260,10 @@ function print_update_step_output($process, $featurestepfile) {
|
||||
$steps[$step[0]] = $step[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($existing = @json_decode(file_get_contents($featurestepfile), true)) {
|
||||
$steps = array_merge($existing, $steps);
|
||||
}
|
||||
arsort($steps);
|
||||
|
||||
if (!@file_put_contents($featurestepfile, json_encode($steps, JSON_PRETTY_PRINT))) {
|
||||
|
||||
@@ -51,5 +51,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,40 @@ class manager implements \core\log\manager {
|
||||
if (empty($interface) || ($reader instanceof $interface)) {
|
||||
$return[$plugin] = $reader;
|
||||
}
|
||||
// TODO MDL-49291 These conditions should be removed as part of the 2nd stage deprecation.
|
||||
if ($reader instanceof \core\log\sql_internal_reader) {
|
||||
debugging('\core\log\sql_internal_reader has been deprecated in favour of \core\log\sql_internal_table_reader.' .
|
||||
' Update ' . get_class($reader) . ' to use the new interface.', DEBUG_DEVELOPER);
|
||||
} else if ($reader instanceof \core\log\sql_select_reader) {
|
||||
debugging('\core\log\sql_select_reader has been deprecated in favour of \core\log\sql_reader. Update ' .
|
||||
get_class($reader) . ' to use the new interface.', DEBUG_DEVELOPER);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO MDL-49291 This section below (until the final return) should be removed as part of the 2nd stage deprecation.
|
||||
$isselectreader = (ltrim($interface, '\\') === 'core\log\sql_select_reader');
|
||||
$isinternalreader = (ltrim($interface, '\\') === 'core\log\sql_internal_reader');
|
||||
if ($isselectreader || $isinternalreader) {
|
||||
|
||||
if ($isselectreader) {
|
||||
$alternative = '\core\log\sql_reader';
|
||||
} else {
|
||||
$alternative = '\core\log\sql_internal_table_reader';
|
||||
}
|
||||
|
||||
if (count($return) === 0) {
|
||||
// If there are no classes implementing the provided interface and the provided interface is one of
|
||||
// the deprecated ones, we return the non-deprecated alternatives. It should be safe as the new interface
|
||||
// is adding a new method but not changing the existing ones.
|
||||
debugging($interface . ' has been deprecated in favour of ' . $alternative . '. Returning ' . $alternative .
|
||||
' instances instead. Please call get_readers() using the new interface.', DEBUG_DEVELOPER);
|
||||
$return = $this->get_readers($alternative);
|
||||
} else {
|
||||
debugging($interface . ' has been deprecated in favour of ' . $alternative .
|
||||
'. Please call get_readers() using the new interface.', DEBUG_DEVELOPER);
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,5 +49,8 @@ function xmldb_tool_log_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -39,5 +39,8 @@ function xmldb_logstore_database_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -117,5 +117,8 @@ function xmldb_logstore_standard_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,9 +41,9 @@ if ($hassiteconfig) {
|
||||
$settings->add(new admin_setting_heading('messageinbound_mailboxconfiguration',
|
||||
new lang_string('mailboxconfiguration', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundmailboxconfiguration_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_mailbox',
|
||||
$settings->add(new admin_setting_configtext_with_maxlength('messageinbound_mailbox',
|
||||
new lang_string('mailbox', 'tool_messageinbound'),
|
||||
null, '', PARAM_RAW));
|
||||
null, '', PARAM_RAW, null, 15));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_domain',
|
||||
new lang_string('domain', 'tool_messageinbound'),
|
||||
null, '', PARAM_RAW));
|
||||
|
||||
@@ -53,5 +53,8 @@ function xmldb_tool_monitor_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+7
-2
@@ -190,9 +190,14 @@
|
||||
// We don't need to check the fullnamedisplay setting here as the fullname function call further down has
|
||||
// the override parameter set to true.
|
||||
$fullnamesetting = $CFG->alternativefullnameformat;
|
||||
// If we are using language or it is empty, then retrieve all of the user's names.
|
||||
// If we are using language or it is empty, then retrieve the default user names of just 'firstname' and 'lastname'.
|
||||
if ($fullnamesetting == 'language' || empty($fullnamesetting)) {
|
||||
$fullnamesetting = implode(' ', $allusernamefields);
|
||||
// Set $a variables to return 'firstname' and 'lastname'.
|
||||
$a = new stdClass();
|
||||
$a->firstname = 'firstname';
|
||||
$a->lastname = 'lastname';
|
||||
// Getting the fullname display will ensure that the order in the language file is maintained.
|
||||
$fullnamesetting = get_string('fullnamedisplay', null, $a);
|
||||
}
|
||||
|
||||
// Order in string will ensure that the name columns are in the correct order.
|
||||
|
||||
@@ -71,5 +71,8 @@ function xmldb_auth_cas_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2014111001, 'auth', 'cas');
|
||||
}
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+7
-3
@@ -534,6 +534,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
*
|
||||
* @param object $user new user object
|
||||
* @param boolean $notify print notice with link and terminate
|
||||
* @return boolean success
|
||||
*/
|
||||
function user_signup($user, $notify=true) {
|
||||
global $CFG, $DB, $PAGE, $OUTPUT;
|
||||
@@ -889,7 +890,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
foreach ($users as $user) {
|
||||
echo "\t"; print_string('auth_dbupdatinguser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id));
|
||||
if (!$this->update_user_record($user->username, $updatekeys)) {
|
||||
if (!$this->update_user_record($user->username, $updatekeys, true)) {
|
||||
echo ' - '.get_string('skipped');
|
||||
}
|
||||
echo "\n";
|
||||
@@ -987,8 +988,11 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
*
|
||||
* @param string $username username
|
||||
* @param boolean $updatekeys true to update the local record with the external LDAP values.
|
||||
* @param bool $triggerevent set false if user_updated event should not be triggered.
|
||||
* This will not affect user_password_updated event triggering.
|
||||
* @return stdClass|bool updated user record or false if there is no new info to update.
|
||||
*/
|
||||
function update_user_record($username, $updatekeys = false) {
|
||||
function update_user_record($username, $updatekeys = false, $triggerevent = false) {
|
||||
global $CFG, $DB;
|
||||
|
||||
// Just in case check text case
|
||||
@@ -1030,7 +1034,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
}
|
||||
}
|
||||
user_update_user($newuser, false, false);
|
||||
user_update_user($newuser, false, $triggerevent);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -61,5 +61,8 @@ function xmldb_auth_ldap_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2014111001, 'auth', 'ldap');
|
||||
}
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,9 +136,25 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$auth = get_auth_plugin('ldap');
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, 5 users created with 2 users having roles.
|
||||
$this->assertCount(7, $events);
|
||||
foreach ($events as $index => $event) {
|
||||
$usercreatedindex = array(0, 2, 4, 5, 6);
|
||||
$roleassignedindex = array (1, 3);
|
||||
if (in_array($index, $usercreatedindex)) {
|
||||
$this->assertInstanceOf('\core\event\user_created', $event);
|
||||
}
|
||||
if (in_array($index, $roleassignedindex)) {
|
||||
$this->assertInstanceOf('\core\event\role_assigned', $event);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(2, $DB->count_records('role_assignments'));
|
||||
$this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
|
||||
@@ -150,9 +166,15 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$this->delete_ldap_user($connection, $topdn, 1);
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, no new event.
|
||||
$this->assertCount(0, $events);
|
||||
|
||||
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
|
||||
@@ -166,9 +188,17 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$auth = get_auth_plugin('ldap');
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, 1 user got updated.
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
|
||||
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('auth'=>'nologin', 'username'=>'username1')));
|
||||
$this->assertEquals(1, $DB->count_records('user', array('auth'=>'ldap', 'suspended'=>'1', 'username'=>'username1')));
|
||||
@@ -179,9 +209,17 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$this->create_ldap_user($connection, $topdn, 1);
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, 1 user got updated.
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
|
||||
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
|
||||
@@ -191,9 +229,17 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$DB->set_field('user', 'auth', 'nologin', array('username'=>'username1'));
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, 1 user got updated.
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
|
||||
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
|
||||
@@ -208,9 +254,19 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$this->delete_ldap_user($connection, $topdn, 1);
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, 2 events role_unassigned and user_deleted.
|
||||
$this->assertCount(2, $events);
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\user_deleted', $event);
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\role_unassigned', $event);
|
||||
|
||||
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('username'=>'username1')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
|
||||
@@ -221,9 +277,19 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$this->create_ldap_user($connection, $topdn, 1);
|
||||
|
||||
ob_start();
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->sync_users(true);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
ob_end_clean();
|
||||
|
||||
// Check events, 2 events role_assigned and user_created.
|
||||
$this->assertCount(2, $events);
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\role_assigned', $event);
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\user_created', $event);
|
||||
|
||||
$this->assertEquals(6, $DB->count_records('user', array('auth'=>'ldap')));
|
||||
$this->assertEquals(1, $DB->count_records('user', array('username'=>'username1')));
|
||||
$this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
This files describes API changes in the auth_ldap code.
|
||||
=== 2.9.1 ===
|
||||
* auth_plugin_ldap::update_user_record() accepts an additional (optional) param
|
||||
to trigger update event.
|
||||
@@ -53,5 +53,8 @@ function xmldb_auth_manual_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -53,5 +53,8 @@ function xmldb_auth_mnet_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ class condition extends \core_availability\condition {
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get cmid.
|
||||
if (isset($structure->cm) && is_int($structure->cm)) {
|
||||
$this->cmid = $structure->cm;
|
||||
if (isset($structure->cm) && is_number($structure->cm)) {
|
||||
$this->cmid = (int)$structure->cm;
|
||||
} else {
|
||||
throw new \coding_exception('Missing or invalid ->cm for completion condition');
|
||||
}
|
||||
|
||||
@@ -939,6 +939,7 @@ class backup_gradebook_structure_step extends backup_structure_step {
|
||||
}
|
||||
|
||||
protected function define_structure() {
|
||||
global $CFG, $DB;
|
||||
|
||||
// are we including user info?
|
||||
$userinfo = $this->get_setting_value('users');
|
||||
@@ -999,6 +1000,13 @@ class backup_gradebook_structure_step extends backup_structure_step {
|
||||
$gradebook->add_child($grade_settings);
|
||||
$grade_settings->add_child($grade_setting);
|
||||
|
||||
// Add attribute with gradebook calculation freeze date if needed.
|
||||
$gradebookcalculationfreeze = get_config('core', 'gradebook_calculations_freeze_' . $this->get_courseid());
|
||||
if ($gradebookcalculationfreeze) {
|
||||
$gradebook->add_attributes(array('calculations_freeze'));
|
||||
$gradebook->get_attribute('calculations_freeze')->set_value($gradebookcalculationfreeze);
|
||||
}
|
||||
|
||||
// Define sources
|
||||
|
||||
//Include manual, category and the course grade item
|
||||
@@ -1023,7 +1031,18 @@ class backup_gradebook_structure_step extends backup_structure_step {
|
||||
|
||||
$letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
|
||||
|
||||
$grade_setting->set_source_table('grade_settings', array('courseid' => backup::VAR_COURSEID));
|
||||
// Set the grade settings source, forcing the inclusion of minmaxtouse if not present.
|
||||
$settings = array();
|
||||
$rs = $DB->get_recordset('grade_settings', array('courseid' => $this->get_courseid()));
|
||||
foreach ($rs as $record) {
|
||||
$settings[$record->name] = $record;
|
||||
}
|
||||
$rs->close();
|
||||
if (!isset($settings['minmaxtouse'])) {
|
||||
$settings['minmaxtouse'] = (object) array('name' => 'minmaxtouse', 'value' => $CFG->grade_minmaxtouse);
|
||||
}
|
||||
$grade_setting->set_source_array($settings);
|
||||
|
||||
|
||||
// Annotations (both as final as far as they are going to be exported in next steps)
|
||||
$grade_item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
|
||||
|
||||
@@ -142,6 +142,18 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
}
|
||||
|
||||
protected function process_gradebook($data) {
|
||||
// For non-merge restore types:
|
||||
// Unset 'gradebook_calculations_freeze_' in the course and replace with the one from the backup.
|
||||
$target = $this->get_task()->get_target();
|
||||
if ($target == backup::TARGET_CURRENT_DELETING || $target == backup::TARGET_EXISTING_DELETING) {
|
||||
set_config('gradebook_calculations_freeze_' . $this->get_courseid(), null);
|
||||
}
|
||||
if (!empty($data['calculations_freeze'])) {
|
||||
if ($target == backup::TARGET_NEW_COURSE || $target == backup::TARGET_CURRENT_DELETING ||
|
||||
$target == backup::TARGET_EXISTING_DELETING) {
|
||||
set_config('gradebook_calculations_freeze_' . $this->get_courseid(), $data['calculations_freeze']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function process_grade_item($data) {
|
||||
@@ -323,13 +335,23 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
|
||||
$data->courseid = $this->get_courseid();
|
||||
|
||||
$target = $this->get_task()->get_target();
|
||||
if ($data->name == 'minmaxtouse' &&
|
||||
($target == backup::TARGET_CURRENT_ADDING || $target == backup::TARGET_EXISTING_ADDING)) {
|
||||
// We never restore minmaxtouse during merge.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$DB->record_exists('grade_settings', array('courseid' => $data->courseid, 'name' => $data->name))) {
|
||||
$newitemid = $DB->insert_record('grade_settings', $data);
|
||||
} else {
|
||||
$newitemid = $data->id;
|
||||
}
|
||||
|
||||
$this->set_mapping('grade_setting', $oldid, $newitemid);
|
||||
if (!empty($oldid)) {
|
||||
// In rare cases (minmaxtouse), it is possible that there wasn't any ID associated with the setting.
|
||||
$this->set_mapping('grade_setting', $oldid, $newitemid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,9 +473,104 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Check what to do with the minmaxtouse setting.
|
||||
$this->check_minmaxtouse();
|
||||
|
||||
// Freeze gradebook calculations if needed.
|
||||
$this->gradebook_calculation_freeze();
|
||||
|
||||
// Restore marks items as needing update. Update everything now.
|
||||
grade_regrade_final_grades($this->get_courseid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Freeze gradebook calculation if needed.
|
||||
*
|
||||
* This is similar to various upgrade scripts that check if the freeze is needed.
|
||||
*/
|
||||
protected function gradebook_calculation_freeze() {
|
||||
global $CFG;
|
||||
$gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $this->get_courseid());
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
|
||||
// Extra credits need adjustments only for backups made between 2.8 release (20141110) and the fix release (20150619).
|
||||
if (!$gradebookcalculationsfreeze && $backupbuild >= 20141110 && $backupbuild < 20150619) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_extra_credit_weightoverride($this->get_courseid());
|
||||
}
|
||||
// Calculated grade items need recalculating for backups made between 2.8 release (20141110) and the fix release (20150627).
|
||||
if (!$gradebookcalculationsfreeze && $backupbuild >= 20141110 && $backupbuild < 20150627) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_calculated_grade_items($this->get_courseid());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks what should happen with the course grade setting minmaxtouse.
|
||||
*
|
||||
* This is related to the upgrade step at the time the setting was added.
|
||||
*
|
||||
* @see MDL-48618
|
||||
* @return void
|
||||
*/
|
||||
protected function check_minmaxtouse() {
|
||||
global $CFG, $DB;
|
||||
require_once($CFG->libdir . '/gradelib.php');
|
||||
|
||||
$userinfo = $this->task->get_setting_value('users');
|
||||
$settingname = 'minmaxtouse';
|
||||
$courseid = $this->get_courseid();
|
||||
$minmaxtouse = $DB->get_field('grade_settings', 'value', array('courseid' => $courseid, 'name' => $settingname));
|
||||
$version28start = 2014111000.00;
|
||||
$version28last = 2014111006.05;
|
||||
$version29start = 2015051100.00;
|
||||
$version29last = 2015060400.02;
|
||||
|
||||
$target = $this->get_task()->get_target();
|
||||
if ($minmaxtouse === false &&
|
||||
($target != backup::TARGET_CURRENT_ADDING && $target != backup::TARGET_EXISTING_ADDING)) {
|
||||
// The setting was not found because this setting did not exist at the time the backup was made.
|
||||
// And we are not restoring as merge, in which case we leave the course as it was.
|
||||
$version = $this->get_task()->get_info()->moodle_version;
|
||||
|
||||
if ($version < $version28start) {
|
||||
// We need to set it to use grade_item, but only if the site-wide setting is different. No need to notice them.
|
||||
if ($CFG->grade_minmaxtouse != GRADE_MIN_MAX_FROM_GRADE_ITEM) {
|
||||
grade_set_setting($courseid, $settingname, GRADE_MIN_MAX_FROM_GRADE_ITEM);
|
||||
}
|
||||
|
||||
} else if (($version >= $version28start && $version < $version28last) ||
|
||||
($version >= $version29start && $version < $version29last)) {
|
||||
// They should be using grade_grade when the course has inconsistencies.
|
||||
|
||||
$sql = "SELECT gi.id
|
||||
FROM {grade_items} gi
|
||||
JOIN {grade_grades} gg
|
||||
ON gg.itemid = gi.id
|
||||
WHERE gi.courseid = ?
|
||||
AND (gi.itemtype != ? AND gi.itemtype != ?)
|
||||
AND (gg.rawgrademax != gi.grademax OR gg.rawgrademin != gi.grademin)";
|
||||
|
||||
// The course can only have inconsistencies when we restore the user info,
|
||||
// we do not need to act on existing grades that were not restored as part of this backup.
|
||||
if ($userinfo && $DB->record_exists_sql($sql, array($courseid, 'course', 'category'))) {
|
||||
|
||||
// Display the notice as we do during upgrade.
|
||||
set_config('show_min_max_grades_changed_' . $courseid, 1);
|
||||
|
||||
if ($CFG->grade_minmaxtouse != GRADE_MIN_MAX_FROM_GRADE_GRADE) {
|
||||
// We need set the setting as their site-wise setting is not GRADE_MIN_MAX_FROM_GRADE_GRADE.
|
||||
// If they are using the site-wide grade_grade setting, we only want to notice them.
|
||||
grade_set_setting($courseid, $settingname, GRADE_MIN_MAX_FROM_GRADE_GRADE);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// This should never happen because from now on minmaxtouse is always saved in backups.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,7 @@ class course_restore_form extends moodleform {
|
||||
$mform->addElement('hidden', 'contextid', $contextid);
|
||||
$mform->setType('contextid', PARAM_INT);
|
||||
$mform->addElement('filepicker', 'backupfile', get_string('files'));
|
||||
$mform->addRule('backupfile', get_string('required'), 'required');
|
||||
$submit_string = get_string('restore');
|
||||
$this->add_action_buttons(false, $submit_string);
|
||||
}
|
||||
|
||||
@@ -167,4 +167,48 @@ class backup_anonymizer_helper {
|
||||
public static function process_user_imagealt($value) {
|
||||
return ''; // No user imagealt
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymises user's phonetic name field
|
||||
* @param string $value value of the user field
|
||||
* @return string anonymised phonetic name
|
||||
*/
|
||||
public static function process_user_firstnamephonetic($value) {
|
||||
static $counter = 0;
|
||||
$counter++;
|
||||
return 'anonfirstnamephonetic' . $counter; // Just a counter.
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymises user's phonetic last name field
|
||||
* @param string $value value of the user field
|
||||
* @return string anonymised last phonetic name
|
||||
*/
|
||||
public static function process_user_lastnamephonetic($value) {
|
||||
static $counter = 0;
|
||||
$counter++;
|
||||
return 'anonlastnamephonetic' . $counter; // Just a counter.
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymises user's middle name field
|
||||
* @param string $value value of the user field
|
||||
* @return string anonymised middle name
|
||||
*/
|
||||
public static function process_user_middlename($value) {
|
||||
static $counter = 0;
|
||||
$counter++;
|
||||
return 'anonmiddlename' . $counter; // Just a counter.
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymises user's alternate name field
|
||||
* @param string $value value of the user field
|
||||
* @return string anonymised alternate name
|
||||
*/
|
||||
public static function process_user_alternatename($value) {
|
||||
static $counter = 0;
|
||||
$counter++;
|
||||
return 'anonalternatename' . $counter; // Just a counter.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ Feature: Award badges
|
||||
And I follow "Course completion"
|
||||
And I set the field "id_overall_aggregation" to "2"
|
||||
And I click on "Condition: Activity completion" "link"
|
||||
And I set the field "Assign - Test assignment name" to "1"
|
||||
And I set the field "Assignment - Test assignment name" to "1"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Add a new badge" node in "Course administration > Badges"
|
||||
|
||||
@@ -76,5 +76,8 @@ function xmldb_block_badges_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,5 +76,8 @@ function xmldb_block_calendar_month_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,5 +76,8 @@ function xmldb_block_calendar_upcoming_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -66,5 +66,8 @@ function xmldb_block_community_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,5 +73,8 @@ function xmldb_block_completionstatus_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ if (empty($completions)) {
|
||||
echo html_writer::start_tag('tr');
|
||||
echo html_writer::start_tag('td', array('colspan' => '2'));
|
||||
echo html_writer::start_tag('br');
|
||||
echo $OUTPUT->box(get_string('err_nocriteria', 'completion'), 'noticebox');
|
||||
echo $OUTPUT->box(get_string('nocriteriaset', 'completion'), 'noticebox');
|
||||
echo html_writer::end_tag('td');
|
||||
echo html_writer::end_tag('tr');
|
||||
echo html_writer::end_tag('tbody');
|
||||
|
||||
@@ -112,7 +112,7 @@ class block_course_overview extends block_base {
|
||||
* @return array
|
||||
*/
|
||||
public function applicable_formats() {
|
||||
return array('my-index' => true);
|
||||
return array('my' => true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,4 +125,4 @@ class block_course_overview extends block_base {
|
||||
$config = get_config('block_course_overview');
|
||||
return !empty($config->showwelcomearea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,5 +77,8 @@ function xmldb_block_course_summary_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -53,5 +53,8 @@ function xmldb_block_html_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -78,5 +78,8 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -101,5 +101,8 @@ function xmldb_block_quiz_results_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -87,5 +87,8 @@ function xmldb_block_recent_activity_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -89,5 +89,8 @@ function xmldb_block_section_links_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,5 +77,8 @@ function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -78,5 +78,8 @@ function xmldb_block_settings_upgrade($oldversion, $block) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
+3
-1
@@ -76,7 +76,9 @@ $sitecontext = context_system::instance();
|
||||
|
||||
if (isset($userid) && $USER->id == $userid) {
|
||||
$blognode = $PAGE->navigation->find('siteblog', null);
|
||||
$blognode->make_inactive();
|
||||
if ($blognode) {
|
||||
$blognode->make_inactive();
|
||||
}
|
||||
}
|
||||
|
||||
// Check basic permissions.
|
||||
|
||||
@@ -1023,12 +1023,16 @@ function blog_page_type_list($pagetype, $parentcontext, $currentcontext) {
|
||||
* @return bool
|
||||
*/
|
||||
function core_blog_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) {
|
||||
global $CFG;
|
||||
if (!blog_is_enabled_for_user() || isguestuser($user)) {
|
||||
// The guest user cannot post, so it is not possible to view any posts.
|
||||
// Also blogs might be disabled.
|
||||
// May as well just bail aggressively here.
|
||||
return true;
|
||||
}
|
||||
if (!blog_user_can_view_user_entry($user->id)) {
|
||||
return true;
|
||||
}
|
||||
$url = new moodle_url("/blog/index.php", array('userid' => $user->id));
|
||||
if (!empty($course)) {
|
||||
$url->param('courseid', $course->id);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
@core @core_blog
|
||||
Feature: Blogs can be set to be only visible by the author.
|
||||
In order to make blogs personal only
|
||||
As a user
|
||||
I need to set the blog level to Users can only see their own blogs.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| testuser | Test | User | moodle@example.com |
|
||||
| testuser2 | Test2 | User2 | moodle2@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| testuser | C1 | student |
|
||||
| testuser2 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I navigate to "Blog" node in "Site administration > Appearance"
|
||||
And I set the following fields to these values:
|
||||
| Blog visibility | Users can only see their own blog |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: A student can not see another student's blog entries.
|
||||
Given I log in as "testuser"
|
||||
And I follow "Course 1"
|
||||
And I follow "Participants"
|
||||
And I follow "Test2 User2"
|
||||
And I should see "Miscellaneous"
|
||||
Then I should not see "Blog entries"
|
||||
And I follow "Profile" in the user menu
|
||||
And I follow "Blog entries"
|
||||
And I should see "User blog: Test User"
|
||||
Vendored
+2
@@ -318,6 +318,8 @@ class cache_helper {
|
||||
$definitionkey = $definition->get_component().'/'.$definition->get_area();
|
||||
if (isset($inuse[$definitionkey])) {
|
||||
$inuse[$definitionkey]->purge();
|
||||
} else {
|
||||
cache::make($definition->get_component(), $definition->get_area())->purge();
|
||||
}
|
||||
|
||||
// We should only log events for application and session caches.
|
||||
|
||||
@@ -106,7 +106,9 @@ class behat_calendar extends behat_base {
|
||||
* @return Given[]
|
||||
*/
|
||||
public function i_hover_over_today_in_the_calendar() {
|
||||
$todaysday = trim(strftime('%e'));
|
||||
// For window's compatibility, using %d and not %e.
|
||||
$todaysday = trim(strftime('%d'));
|
||||
$todaysday = ltrim($todaysday, '0');
|
||||
return $this->i_hover_over_day_of_this_month_in_calendar($todaysday);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-11
@@ -118,6 +118,7 @@ echo $search;
|
||||
echo $OUTPUT->paging_bar($cohorts['totalcohorts'], $page, 25, $baseurl);
|
||||
|
||||
$data = array();
|
||||
$editcolumnisempty = true;
|
||||
foreach($cohorts['cohorts'] as $cohort) {
|
||||
$line = array();
|
||||
$cohortcontext = context::instance_by_id($cohort->contextid);
|
||||
@@ -148,27 +149,29 @@ foreach($cohorts['cohorts'] as $cohort) {
|
||||
|
||||
$urlparams = array('id' => $cohort->id, 'returnurl' => $baseurl->out_as_local_url());
|
||||
$showhideurl = new moodle_url('/cohort/edit.php', $urlparams + array('sesskey' => sesskey()));
|
||||
if ($cohort->visible) {
|
||||
$showhideurl->param('hide', 1);
|
||||
$visibleimg = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/hide'), 'alt' => get_string('hide'), 'class' => 'iconsmall'));
|
||||
$buttons[] = html_writer::link($showhideurl, $visibleimg, array('title' => get_string('hide')));
|
||||
} else {
|
||||
$showhideurl->param('show', 1);
|
||||
$visibleimg = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/show'), 'alt' => get_string('show'), 'class' => 'iconsmall'));
|
||||
$buttons[] = html_writer::link($showhideurl, $visibleimg, array('title' => get_string('show')));
|
||||
}
|
||||
if ($cohortmanager) {
|
||||
if ($cohort->visible) {
|
||||
$showhideurl->param('hide', 1);
|
||||
$visibleimg = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/hide'), 'alt' => get_string('hide'), 'class' => 'iconsmall'));
|
||||
$buttons[] = html_writer::link($showhideurl, $visibleimg, array('title' => get_string('hide')));
|
||||
} else {
|
||||
$showhideurl->param('show', 1);
|
||||
$visibleimg = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/show'), 'alt' => get_string('show'), 'class' => 'iconsmall'));
|
||||
$buttons[] = html_writer::link($showhideurl, $visibleimg, array('title' => get_string('show')));
|
||||
}
|
||||
$buttons[] = html_writer::link(new moodle_url('/cohort/edit.php', $urlparams + array('delete' => 1)),
|
||||
html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/delete'), 'alt' => get_string('delete'), 'class' => 'iconsmall')),
|
||||
array('title' => get_string('delete')));
|
||||
$buttons[] = html_writer::link(new moodle_url('/cohort/edit.php', $urlparams),
|
||||
html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/edit'), 'alt' => get_string('edit'), 'class' => 'iconsmall')),
|
||||
array('title' => get_string('edit')));
|
||||
$editcolumnisempty = false;
|
||||
}
|
||||
if ($cohortcanassign) {
|
||||
$buttons[] = html_writer::link(new moodle_url('/cohort/assign.php', $urlparams),
|
||||
html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('i/users'), 'alt' => get_string('assign', 'core_cohort'), 'class' => 'iconsmall')),
|
||||
array('title' => get_string('assign', 'core_cohort')));
|
||||
$editcolumnisempty = false;
|
||||
}
|
||||
}
|
||||
$line[] = implode(' ', $buttons);
|
||||
@@ -180,12 +183,21 @@ foreach($cohorts['cohorts'] as $cohort) {
|
||||
}
|
||||
$table = new html_table();
|
||||
$table->head = array(get_string('name', 'cohort'), get_string('idnumber', 'cohort'), get_string('description', 'cohort'),
|
||||
get_string('memberscount', 'cohort'), get_string('component', 'cohort'), get_string('edit'));
|
||||
$table->colclasses = array('leftalign name', 'leftalign id', 'leftalign description', 'leftalign size','centeralign source', 'centeralign action');
|
||||
get_string('memberscount', 'cohort'), get_string('component', 'cohort'));
|
||||
$table->colclasses = array('leftalign name', 'leftalign id', 'leftalign description', 'leftalign size','centeralign source');
|
||||
if ($showall) {
|
||||
array_unshift($table->head, get_string('category'));
|
||||
array_unshift($table->colclasses, 'leftalign category');
|
||||
}
|
||||
if (!$editcolumnisempty) {
|
||||
$table->head[] = get_string('edit');
|
||||
$table->colclasses[] = 'centeralign action';
|
||||
} else {
|
||||
// Remove last column from $data.
|
||||
foreach ($data as $row) {
|
||||
array_pop($row->cells);
|
||||
}
|
||||
}
|
||||
$table->id = 'cohorts';
|
||||
$table->attributes['class'] = 'admintable generaltable';
|
||||
$table->data = $data;
|
||||
|
||||
@@ -301,7 +301,7 @@ class core_completion_external extends external_api {
|
||||
|
||||
$completions = $info->get_completions($user->id);
|
||||
if (empty($completions)) {
|
||||
throw new moodle_exception('err_nocriteria', 'completion');
|
||||
throw new moodle_exception('nocriteriaset', 'completion');
|
||||
}
|
||||
|
||||
// Load course completion.
|
||||
|
||||
@@ -60,7 +60,11 @@ class completion_criteria_activity extends completion_criteria {
|
||||
* @param stdClass $data details of various modules
|
||||
*/
|
||||
public function config_form_display(&$mform, $data = null) {
|
||||
$mform->addElement('checkbox', 'criteria_activity['.$data->id.']', ucfirst(self::get_mod_name($data->module)).' - '.$data->name);
|
||||
$modnames = get_module_types_names();
|
||||
$mform->addElement('checkbox', 'criteria_activity['.$data->id.']',
|
||||
$modnames[self::get_mod_name($data->module)].
|
||||
' - '.
|
||||
format_string($data->name));
|
||||
|
||||
if ($this->id) {
|
||||
$mform->setDefault('criteria_activity['.$data->id.']', 1);
|
||||
@@ -177,7 +181,8 @@ class completion_criteria_activity extends completion_criteria {
|
||||
$module = $DB->get_record('course_modules', array('id' => $this->moduleinstance));
|
||||
$activity = $DB->get_record($this->module, array('id' => $module->instance));
|
||||
|
||||
return shorten_text(urldecode($activity->name));
|
||||
return shorten_text(format_string($activity->name, true,
|
||||
array('context' => context_module::instance($module->id))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,6 +41,12 @@ Feature: Allow teachers to manually mark users as complete when configured
|
||||
And I follow "View course report"
|
||||
And I should see "Student First"
|
||||
And I follow "Click to mark user complete"
|
||||
# Running cron just after clicking sometimes fail, so navigate back
|
||||
# and ensure the student completion is updated before running cron.
|
||||
And I am on site homepage
|
||||
And I follow "Completion course"
|
||||
And I follow "View course report"
|
||||
And "//img[contains(@alt, 'Completed')]" "xpath_element" should exist in the "student1" "table_row"
|
||||
And I trigger cron
|
||||
And I am on site homepage
|
||||
And I log out
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.*",
|
||||
"phpunit/dbUnit": "1.2.*",
|
||||
"moodlehq/behat-extension": "1.29.4"
|
||||
"moodlehq/behat-extension": "1.29.5"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+54
-58
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "8851ae0a65874465e2e9fef68335e110",
|
||||
"hash": "e57a3c4f1934098d77de54215b059ba1",
|
||||
"packages": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
@@ -405,16 +405,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "v1.2.3",
|
||||
"version": "v1.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4"
|
||||
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4",
|
||||
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b5202eb9e83f8db52e0e58867e0a46e63be8332e",
|
||||
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -469,20 +469,20 @@
|
||||
"docblock",
|
||||
"parser"
|
||||
],
|
||||
"time": "2014-12-20 20:49:38"
|
||||
"time": "2014-12-23 22:40:37"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.4.0",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
|
||||
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
|
||||
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/c9eadeb743ac6199f7eec423cb9426bc518b7b03",
|
||||
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -493,13 +493,13 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=3.7",
|
||||
"predis/predis": "~0.8",
|
||||
"predis/predis": "~1.0",
|
||||
"satooshi/php-coveralls": "~0.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
"dev-master": "1.5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -539,25 +539,28 @@
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2015-01-15 20:38:55"
|
||||
"time": "2015-04-15 00:11:59"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.2",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
|
||||
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
|
||||
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -574,17 +577,6 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com",
|
||||
"homepage": "http://www.jwage.com/",
|
||||
"role": "Creator"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com",
|
||||
"homepage": "http://www.instaclick.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
@@ -593,11 +585,17 @@
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "https://github.com/schmittjoh",
|
||||
"role": "Developer of wrapped JMSSerializerBundle"
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Collections Abstraction library",
|
||||
@@ -607,7 +605,7 @@
|
||||
"collections",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2014-02-03 23:07:43"
|
||||
"time": "2015-04-14 22:21:58"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/common",
|
||||
@@ -1011,16 +1009,16 @@
|
||||
},
|
||||
{
|
||||
"name": "moodlehq/behat-extension",
|
||||
"version": "v1.29.4",
|
||||
"version": "v1.29.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/moodlehq/moodle-behat-extension.git",
|
||||
"reference": "ccc3027ba9959a23761e056a1cb570c66baa95ba"
|
||||
"reference": "0ea55a59bfbfef4e8dcf47067c56779e5a02cd63"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/moodlehq/moodle-behat-extension/zipball/ccc3027ba9959a23761e056a1cb570c66baa95ba",
|
||||
"reference": "ccc3027ba9959a23761e056a1cb570c66baa95ba",
|
||||
"url": "https://api.github.com/repos/moodlehq/moodle-behat-extension/zipball/0ea55a59bfbfef4e8dcf47067c56779e5a02cd63",
|
||||
"reference": "0ea55a59bfbfef4e8dcf47067c56779e5a02cd63",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1031,7 +1029,7 @@
|
||||
"behat/mink-selenium2-driver": "1.1.1",
|
||||
"guzzlehttp/guzzle": "~3.1",
|
||||
"php": ">=5.4.4",
|
||||
"symfony/symfony": "2.4.4"
|
||||
"symfony/symfony": "2.4.10"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -1057,9 +1055,9 @@
|
||||
"Moodle"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/moodlehq/moodle-behat-extension/tree/v1.29.4"
|
||||
"source": "https://github.com/moodlehq/moodle-behat-extension/tree/v1.29.5"
|
||||
},
|
||||
"time": "2015-03-20 02:42:46"
|
||||
"time": "2015-05-15 02:00:06"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/dbunit",
|
||||
@@ -1576,16 +1574,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/symfony",
|
||||
"version": "v2.4.4",
|
||||
"version": "v2.4.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/symfony.git",
|
||||
"reference": "4697c33cdfb520dcf83fd6e4f7864fa26ddaebea"
|
||||
"reference": "daed178afd4700dd18f4fb0ea6b72dcfd9a4792a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/symfony/zipball/4697c33cdfb520dcf83fd6e4f7864fa26ddaebea",
|
||||
"reference": "4697c33cdfb520dcf83fd6e4f7864fa26ddaebea",
|
||||
"url": "https://api.github.com/repos/symfony/symfony/zipball/daed178afd4700dd18f4fb0ea6b72dcfd9a4792a",
|
||||
"reference": "daed178afd4700dd18f4fb0ea6b72dcfd9a4792a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1593,7 +1591,7 @@
|
||||
"php": ">=5.3.3",
|
||||
"psr/log": "~1.0",
|
||||
"symfony/icu": "~1.0",
|
||||
"twig/twig": "~1.11"
|
||||
"twig/twig": "~1.12"
|
||||
},
|
||||
"replace": {
|
||||
"symfony/browser-kit": "self.version",
|
||||
@@ -1671,15 +1669,13 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "The Symfony PHP framework",
|
||||
@@ -1687,24 +1683,24 @@
|
||||
"keywords": [
|
||||
"framework"
|
||||
],
|
||||
"time": "2014-04-27 13:39:18"
|
||||
"time": "2014-09-28 17:03:37"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.18.0",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
|
||||
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
|
||||
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
|
||||
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
"php": ">=5.2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -1744,7 +1740,7 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2015-01-25 17:32:08"
|
||||
"time": "2015-04-19 08:30:27"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
||||
+25
-5
@@ -146,7 +146,7 @@ M.course_dndupload = {
|
||||
styletopunit = styletop.replace(/^\d+/, '');
|
||||
styletop = parseInt(styletop.replace(/\D*$/, ''), 10);
|
||||
|
||||
var fadeanim = new Y.Anim({
|
||||
var fadein = new Y.Anim({
|
||||
node: '#dndupload-status',
|
||||
from: {
|
||||
opacity: 0.0,
|
||||
@@ -159,11 +159,31 @@ M.course_dndupload = {
|
||||
},
|
||||
duration: 0.5
|
||||
});
|
||||
fadeanim.once('end', function(e) {
|
||||
this.set('reverse', 1);
|
||||
Y.later(3000, this, 'run', null, false);
|
||||
|
||||
var fadeout = new Y.Anim({
|
||||
node: '#dndupload-status',
|
||||
from: {
|
||||
opacity: 1.0,
|
||||
top: styletop.toString() + styletopunit
|
||||
},
|
||||
|
||||
to: {
|
||||
opacity: 0.0,
|
||||
top: (styletop - 30).toString() + styletopunit
|
||||
},
|
||||
duration: 0.5
|
||||
});
|
||||
|
||||
fadein.run();
|
||||
fadein.on('end', function(e) {
|
||||
Y.later(3000, this, function() {
|
||||
fadeout.run();
|
||||
});
|
||||
});
|
||||
|
||||
fadeout.on('end', function(e) {
|
||||
Y.one('#dndupload-status').remove(true);
|
||||
});
|
||||
fadeanim.run();
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+6
-2
@@ -1633,7 +1633,7 @@ function set_coursemodule_visible($id, $visible) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will handles the whole deletion process of a module. This includes calling
|
||||
* This function will handle the whole deletion process of a module. This includes calling
|
||||
* the modules delete_instance function, deleting files, events, grades, conditional data,
|
||||
* the data in the course_module and course_sections table and adding a module deletion
|
||||
* event to the DB.
|
||||
@@ -1645,9 +1645,10 @@ function course_delete_module($cmid) {
|
||||
global $CFG, $DB;
|
||||
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
require_once($CFG->libdir.'/questionlib.php');
|
||||
require_once($CFG->dirroot.'/blog/lib.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
// Get the course module.
|
||||
if (!$cm = $DB->get_record('course_modules', array('id' => $cmid))) {
|
||||
@@ -1679,6 +1680,9 @@ function course_delete_module($cmid) {
|
||||
"Cannot delete this module as the function {$modulename}_delete_instance is missing in mod/$modulename/lib.php.");
|
||||
}
|
||||
|
||||
// Delete activity context questions and question categories.
|
||||
question_delete_activity($cm);
|
||||
|
||||
// Call the delete_instance function, if it returns false throw an exception.
|
||||
if (!$deleteinstancefunction($cm->instance)) {
|
||||
throw new moodle_exception('cannotdeletemoduleinstance', '', '', null,
|
||||
|
||||
@@ -262,6 +262,12 @@ if ($mform->is_cancelled()) {
|
||||
redirect(course_get_url($course, $cw->section, array('sr' => $sectionreturn)));
|
||||
}
|
||||
} else if ($fromform = $mform->get_data()) {
|
||||
// Convert the grade pass value - we may be using a language which uses commas,
|
||||
// rather than decimal points, in numbers. These need to be converted so that
|
||||
// they can be added to the DB.
|
||||
if (isset($fromform->gradepass)) {
|
||||
$fromform->gradepass = unformat_float($fromform->gradepass);
|
||||
}
|
||||
|
||||
if (!empty($fromform->update)) {
|
||||
list($cm, $fromform) = update_moduleinfo($cm, $fromform, $course, $mform);
|
||||
|
||||
@@ -299,10 +299,19 @@ abstract class moodleform_mod extends moodleform {
|
||||
$errors['assessed'] = get_string('scaleselectionrequired', 'rating');
|
||||
}
|
||||
|
||||
// Check that the grade pass is a valid number.
|
||||
$gradepassvalid = false;
|
||||
if (isset($data['gradepass'])) {
|
||||
if (unformat_float($data['gradepass'], true) === false) {
|
||||
$errors['gradepass'] = get_string('err_numeric', 'form');
|
||||
} else {
|
||||
$gradepassvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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']) && (!empty($data['grade']) || !empty($data['scale']))) {
|
||||
if ($gradepassvalid && 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));
|
||||
@@ -672,8 +681,7 @@ abstract class moodleform_mod extends moodleform {
|
||||
$mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
|
||||
$mform->addHelpButton('gradepass', 'gradepass', 'grades');
|
||||
$mform->setDefault('gradepass', '');
|
||||
$mform->setType('gradepass', PARAM_FLOAT);
|
||||
$mform->addRule('gradepass', null, 'numeric', null, 'client');
|
||||
$mform->setType('gradepass', PARAM_RAW);
|
||||
if (!$this->_features->rating) {
|
||||
$mform->disabledIf('gradepass', 'grade[modgrade_type]', 'eq', 'none');
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ foreach ($cms as $cm) {
|
||||
$icon = '<img src="'.$cm->get_icon_url().'" class="activityicon" alt="'.$cm->get_module_type_name().'" /> ';
|
||||
|
||||
if (isset($resource->intro) && isset($resource->introformat)) {
|
||||
$intro = format_module_intro('resource', $resource, $cm->id);
|
||||
$intro = format_module_intro($cm->modname, $resource, $cm->id);
|
||||
} else {
|
||||
$intro = '';
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ class behat_course extends behat_base {
|
||||
// Clicks the selected activity if it exists.
|
||||
$activityxpath = "//div[@id='chooseform']/descendant::label" .
|
||||
"/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
|
||||
"[contains(., $activityliteral)]" .
|
||||
"[normalize-space(.)=$activityliteral]" .
|
||||
"/parent::label/child::input";
|
||||
$activitynode = $this->find('xpath', $activityxpath);
|
||||
$activitynode->doubleClick();
|
||||
@@ -190,7 +190,7 @@ class behat_course extends behat_base {
|
||||
|
||||
// Selecting the option from the select box which contains the option.
|
||||
$selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[contains(., $activityliteral)]";
|
||||
"/descendant::select[option[normalize-space(.)=$activityliteral]]";
|
||||
$selectnode = $this->find('xpath', $selectxpath);
|
||||
$selectnode->selectOption($activity);
|
||||
|
||||
|
||||
@@ -539,7 +539,23 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
return $moduleinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for course_delete module
|
||||
*
|
||||
* @return array An array of arrays contain test data
|
||||
*/
|
||||
public function provider_course_delete_module() {
|
||||
$data = array();
|
||||
|
||||
$data['assign'] = array('assign', array('duedate' => time()));
|
||||
$data['quiz'] = array('quiz', array('duedate' => time()));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the create_course function
|
||||
*/
|
||||
public function test_create_course() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
@@ -1476,51 +1492,92 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($pagecm->visible, 0);
|
||||
}
|
||||
|
||||
public function test_course_delete_module() {
|
||||
/**
|
||||
* Tests the function that deletes a course module
|
||||
*
|
||||
* @param string $type The type of module for the test
|
||||
* @param array $options The options for the module creation
|
||||
* @dataProvider provider_course_delete_module
|
||||
*/
|
||||
public function test_course_delete_module($type, $options) {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create course and modules.
|
||||
$course = $this->getDataGenerator()->create_course(array('numsections' => 5));
|
||||
$options['course'] = $course->id;
|
||||
|
||||
// Generate an assignment with due date (will generate a course event).
|
||||
$assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id));
|
||||
$module = $this->getDataGenerator()->create_module($type, $options);
|
||||
|
||||
// Get the module context.
|
||||
$modcontext = context_module::instance($assign->cmid);
|
||||
$modcontext = context_module::instance($module->cmid);
|
||||
|
||||
// Verify context exists.
|
||||
$this->assertInstanceOf('context_module', $modcontext);
|
||||
|
||||
// Add some tags to this assignment.
|
||||
tag_set('assign', $assign->id, array('Tag 1', 'Tag 2', 'Tag 3'), 'mod_assign', $modcontext->id);
|
||||
// Make module specific messes.
|
||||
switch ($type) {
|
||||
case 'assign':
|
||||
// Add some tags to this assignment.
|
||||
tag_set('assign', $module->id, array('Tag 1', 'Tag 2', 'Tag 3'), 'mod_assign', $modcontext->id);
|
||||
|
||||
// Confirm the tag instances were added.
|
||||
$this->assertEquals(3, $DB->count_records('tag_instance', array('component' => 'mod_assign', 'contextid' =>
|
||||
$modcontext->id)));
|
||||
// Confirm the tag instances were added.
|
||||
$criteria = array('component' => 'mod_assign', 'contextid' => $modcontext->id);
|
||||
$this->assertEquals(3, $DB->count_records('tag_instance', $criteria));
|
||||
|
||||
// Verify event assignment event has been generated.
|
||||
$eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign'));
|
||||
$this->assertEquals(1, $eventcount);
|
||||
// Verify event assignment event has been generated.
|
||||
$eventcount = $DB->count_records('event', array('instance' => $module->id, 'modulename' => $type));
|
||||
$this->assertEquals(1, $eventcount);
|
||||
|
||||
break;
|
||||
case 'quiz':
|
||||
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$qcat = $qgen->create_question_category(array('contextid' => $modcontext->id));
|
||||
$questions = array(
|
||||
$qgen->create_question('shortanswer', null, array('category' => $qcat->id)),
|
||||
$qgen->create_question('shortanswer', null, array('category' => $qcat->id)),
|
||||
);
|
||||
$this->expectOutputRegex('/'.get_string('unusedcategorydeleted', 'question').'/');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Run delete..
|
||||
course_delete_module($assign->cmid);
|
||||
course_delete_module($module->cmid);
|
||||
|
||||
// Verify the context has been removed.
|
||||
$this->assertFalse(context_module::instance($assign->cmid, IGNORE_MISSING));
|
||||
$this->assertFalse(context_module::instance($module->cmid, IGNORE_MISSING));
|
||||
|
||||
// Verify the course_module record has been deleted.
|
||||
$cmcount = $DB->count_records('course_modules', array('id' => $assign->cmid));
|
||||
$cmcount = $DB->count_records('course_modules', array('id' => $module->cmid));
|
||||
$this->assertEmpty($cmcount);
|
||||
|
||||
// Verify event assignment events have been removed.
|
||||
$eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign'));
|
||||
$this->assertEmpty($eventcount);
|
||||
// Test clean up of module specific messes.
|
||||
switch ($type) {
|
||||
case 'assign':
|
||||
// Verify event assignment events have been removed.
|
||||
$eventcount = $DB->count_records('event', array('instance' => $module->id, 'modulename' => $type));
|
||||
$this->assertEmpty($eventcount);
|
||||
|
||||
// Verify the tag instances were deleted.
|
||||
$this->assertEquals(0, $DB->count_records('tag_instance', array('component' => 'mod_assign', 'contextid' =>
|
||||
$modcontext->id)));
|
||||
// Verify the tag instances were deleted.
|
||||
$criteria = array('component' => 'mod_assign', 'contextid' => $modcontext->id);
|
||||
$this->assertEquals(0, $DB->count_records('tag_instance', $criteria));
|
||||
break;
|
||||
case 'quiz':
|
||||
// Verify category deleted.
|
||||
$criteria = array('contextid' => $modcontext->id);
|
||||
$this->assertEquals(0, $DB->count_records('question_categories', $criteria));
|
||||
|
||||
// Verify questions deleted.
|
||||
$criteria = array('category' => $qcat->id);
|
||||
$this->assertEquals(0, $DB->count_records('question', $criteria));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,5 +50,8 @@ function xmldb_enrol_database_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,5 +51,8 @@ function xmldb_enrol_flatfile_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ function xmldb_enrol_guest_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,5 +53,8 @@ function xmldb_enrol_imsenterprise_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
|
||||
|
||||
if ($imsdeleteusers) { // If we're allowed to delete user records.
|
||||
// Do not dare to hack the user.deleted field directly in database!!!
|
||||
$params = array('username' => $person->username, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted ' => 0);
|
||||
$params = array('username' => $person->username, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted' => 0);
|
||||
if ($user = $DB->get_record('user', $params)) {
|
||||
if (delete_user($user)) {
|
||||
$this->log_line("Deleted user '$person->username' (ID number $person->idnumber).");
|
||||
|
||||
@@ -63,6 +63,9 @@ function xmldb_enrol_manual_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,5 +52,8 @@ function xmldb_enrol_mnet_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -67,5 +67,8 @@ function xmldb_enrol_paypal_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ function xmldb_enrol_self_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -187,9 +187,14 @@ $allusernames = get_all_user_name_fields(false, null, null, null, true);
|
||||
$usernameheader = null;
|
||||
// Get the alternative full name format for users with the viewfullnames capability.
|
||||
$fullusernames = $CFG->alternativefullnameformat;
|
||||
// If fullusernames is empty or accidentally set to language then fall back on the $allusernames set up.
|
||||
// If fullusernames is empty or accidentally set to language then fall back to default of just first and last name.
|
||||
if ($fullusernames == 'language' || empty($fullusernames)) {
|
||||
$usernameheader = $allusernames;
|
||||
// Set $a variables to return 'firstname' and 'lastname'.
|
||||
$a = new stdClass();
|
||||
$a->firstname = 'firstname';
|
||||
$a->lastname = 'lastname';
|
||||
// Getting the fullname display will ensure that the order in the language file is maintained.
|
||||
$usernameheader = explode(' ', get_string('fullnamedisplay', null, $a));
|
||||
} else {
|
||||
// If everything is as expected then put them in the order specified by the alternative full name format setting.
|
||||
$usernameheader = order_in_string($allusernames, $fullusernames);
|
||||
|
||||
+33
-5
@@ -19,6 +19,7 @@ AUTOLINKER = function() {
|
||||
};
|
||||
Y.extend(AUTOLINKER, Y.Base, {
|
||||
overlay : null,
|
||||
alertpanels: {},
|
||||
initializer : function() {
|
||||
var self = this;
|
||||
Y.delegate('click', function(e){
|
||||
@@ -64,7 +65,10 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
var data,
|
||||
key,
|
||||
alertpanel,
|
||||
definition;
|
||||
alertpanelid,
|
||||
definition,
|
||||
position;
|
||||
var self = this;
|
||||
try {
|
||||
data = Y.JSON.parse(content);
|
||||
if (data.success){
|
||||
@@ -72,12 +76,22 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
|
||||
for (key in data.entries) {
|
||||
definition = data.entries[key].definition + data.entries[key].attachments;
|
||||
alertpanel = new M.core.alert({title:data.entries[key].concept,
|
||||
alertpanel = new M.core.alert({title:data.entries[key].concept, draggable: true,
|
||||
message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
|
||||
alertpanel.show();
|
||||
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))});
|
||||
|
||||
Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
|
||||
|
||||
// Register alertpanel for stacking.
|
||||
alertpanelid = '#moodle-dialogue-' + alertpanel.get('COUNT');
|
||||
alertpanel.on('complete', this._deletealertpanel(self.alertpanels, alertpanelid));
|
||||
|
||||
// We already have some windows opened, so set the right position...
|
||||
if (!Y.Object.isEmpty(this.alertpanels)){
|
||||
position = this._getLatestWindowPosition();
|
||||
Y.Node.one(alertpanelid).setXY([position[0] + 10, position[1] + 10]);
|
||||
}
|
||||
|
||||
this.alertpanels[alertpanelid] = Y.Node.one(alertpanelid).getXY();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -88,6 +102,18 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
new M.core.exception(e);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
_getLatestWindowPosition : function() {
|
||||
var lastPosition = [0, 0];
|
||||
Y.Object.each(this.alertpanels, function(position) {
|
||||
if (position[0] > lastPosition[0]){
|
||||
lastPosition = position;
|
||||
}
|
||||
});
|
||||
return lastPosition;
|
||||
},
|
||||
_deletealertpanel : function(alertpanels, alertpanelid) {
|
||||
delete alertpanels[alertpanelid];
|
||||
}
|
||||
}, {
|
||||
NAME : AUTOLINKERNAME,
|
||||
@@ -147,6 +173,8 @@ M.filter_glossary.init_filter_autolinking = function(config) {
|
||||
"event-delegate",
|
||||
"overlay",
|
||||
"moodle-core-event",
|
||||
"moodle-core-notification-alert"
|
||||
"moodle-core-notification-alert",
|
||||
"moodle-core-notification-exception",
|
||||
"moodle-core-notification-ajaxexception"
|
||||
]
|
||||
});
|
||||
|
||||
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js
Vendored
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-filter_glossary-autolinker",function(e,t){var n="Glossary filter autolinker",r="width",i="height",s="menubar",o="location",u="scrollbars",a="resizable",f="toolbar",l="status",c="directories",h="fullscreen",p="dependent",d;d=function(){d.superclass.constructor.apply(this,arguments)},e.extend(d,e.Base,{overlay:null,initializer:function(){var t=this;e.delegate("click",function(n){n.preventDefault();var r="",i=e.Node.create('<div id="glossaryfilteroverlayprogress"><img src="'+M.cfg.loadingicon+'" class="spinner" />'+"</div>"),s=new e.Overlay({headerContent:r,bodyContent:i}),o,u;t.overlay=s,s.render(e.one(document.body)),o=this.getAttribute("href").replace("showentry.php","showentry_ajax.php"),u={method:"get",context:t,on:{success:function(e,t){this.display_callback(t.responseText)},failure:function(e,t){var n=t.statusText;M.cfg.developerdebug&&(t.statusText+=" ("+o+")"),this.display_callback("bodyContent",n)}}},e.io(o,u)},e.one(document.body),"a.glossary.autolink.concept")},display_callback:function(t){var n,r,i,s;try{n=e.JSON.parse(t);if(n.success){this.overlay.hide();for(r in n.entries)s=n.entries[r].definition+n.entries[r].attachments,i=new M.core.alert({title:n.entries[r].concept,message:s,modal:!1,yesLabel:M.util.get_string("ok","moodle")}),i.show(),e.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:new e.NodeList(i.get("boundingBox"))}),e.Node.one("#id_yuialertconfirm-"+i.get("COUNT")).focus();return!0}n.error&&new M.core.ajaxException(n)}catch(o){new M.core.exception(o)}return!1}},{NAME:n,ATTRS:{url:{validator:e.Lang.isString,value:M.cfg.wwwroot+"/mod/glossary/showentry.php"},name:{validator:e.Lang.isString,value:"glossaryconcept"},options:{getter:function(){return{width:this.get(r),height:this.get(i),menubar:this.get(s),location:this.get(o),scrollbars:this.get(u),resizable:this.get(a),toolbar:this.get(f),status:this.get(l),directories:this.get(c),fullscreen:this.get(h),dependent:this.get(p)}},readOnly:!0},width:{value:600},height:{value:450},menubar:{value:!1},location:{value:!1},scrollbars:{value:!0},resizable:{value:!0},toolbar:{value:!0},status:{value:!0},directories:{value:!1},fullscreen:{value:!1},dependent:{value:!0}}}),M.filter_glossary=M.filter_glossary||{},M.filter_glossary.init_filter_autolinking=function(e){return new d(e)}},"@VERSION@",{requires:["base","node","io-base","json-parse","event-delegate","overlay","moodle-core-event","moodle-core-notification-alert"]});
|
||||
YUI.add("moodle-filter_glossary-autolinker",function(e,t){var n="Glossary filter autolinker",r="width",i="height",s="menubar",o="location",u="scrollbars",a="resizable",f="toolbar",l="status",c="directories",h="fullscreen",p="dependent",d;d=function(){d.superclass.constructor.apply(this,arguments)},e.extend(d,e.Base,{overlay:null,alertpanels:{},initializer:function(){var t=this;e.delegate("click",function(n){n.preventDefault();var r="",i=e.Node.create('<div id="glossaryfilteroverlayprogress"><img src="'+M.cfg.loadingicon+'" class="spinner" />'+"</div>"),s=new e.Overlay({headerContent:r,bodyContent:i}),o,u;t.overlay=s,s.render(e.one(document.body)),o=this.getAttribute("href").replace("showentry.php","showentry_ajax.php"),u={method:"get",context:t,on:{success:function(e,t){this.display_callback(t.responseText)},failure:function(e,t){var n=t.statusText;M.cfg.developerdebug&&(t.statusText+=" ("+o+")"),this.display_callback("bodyContent",n)}}},e.io(o,u)},e.one(document.body),"a.glossary.autolink.concept")},display_callback:function(t){var n,r,i,s,o,u,a=this;try{n=e.JSON.parse(t);if(n.success){this.overlay.hide();for(r in n.entries)o=n.entries[r].definition+n.entries[r].attachments,i=new M.core.alert({title:n.entries[r].concept,draggable:!0,message:o,modal:!1,yesLabel:M.util.get_string("ok","moodle")}),e.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:new e.NodeList(i.get("boundingBox"))}),e.Node.one("#id_yuialertconfirm-"+i.get("COUNT")).focus(),s="#moodle-dialogue-"+i.get("COUNT"),i.on("complete",this._deletealertpanel(a.alertpanels,s)),e.Object.isEmpty(this.alertpanels)||(u=this._getLatestWindowPosition(),e.Node.one(s).setXY([u[0]+10,u[1]+10])),this.alertpanels[s]=e.Node.one(s).getXY();return!0}n.error&&new M.core.ajaxException(n)}catch(f){new M.core.exception(f)}return!1},_getLatestWindowPosition:function(){var t=[0,0];return e.Object.each(this.alertpanels,function(e){e[0]>t[0]&&(t=e)}),t},_deletealertpanel:function(e,t){delete e[t]}},{NAME:n,ATTRS:{url:{validator:e.Lang.isString,value:M.cfg.wwwroot+"/mod/glossary/showentry.php"},name:{validator:e.Lang.isString,value:"glossaryconcept"},options:{getter:function(){return{width:this.get(r),height:this.get(i),menubar:this.get(s),location:this.get(o),scrollbars:this.get(u),resizable:this.get(a),toolbar:this.get(f),status:this.get(l),directories:this.get(c),fullscreen:this.get(h),dependent:this.get(p)}},readOnly:!0},width:{value:600},height:{value:450},menubar:{value:!1},location:{value:!1},scrollbars:{value:!0},resizable:{value:!0},toolbar:{value:!0},status:{value:!0},directories:{value:!1},fullscreen:{value:!1},dependent:{value:!0}}}),M.filter_glossary=M.filter_glossary||{},M.filter_glossary.init_filter_autolinking=function(e){return new d(e)}},"@VERSION@",{requires:["base","node","io-base","json-parse","event-delegate","overlay","moodle-core-event","moodle-core-notification-alert","moodle-core-notification-exception","moodle-core-notification-ajaxexception"]});
|
||||
|
||||
Vendored
+33
-5
@@ -19,6 +19,7 @@ AUTOLINKER = function() {
|
||||
};
|
||||
Y.extend(AUTOLINKER, Y.Base, {
|
||||
overlay : null,
|
||||
alertpanels: {},
|
||||
initializer : function() {
|
||||
var self = this;
|
||||
Y.delegate('click', function(e){
|
||||
@@ -64,7 +65,10 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
var data,
|
||||
key,
|
||||
alertpanel,
|
||||
definition;
|
||||
alertpanelid,
|
||||
definition,
|
||||
position;
|
||||
var self = this;
|
||||
try {
|
||||
data = Y.JSON.parse(content);
|
||||
if (data.success){
|
||||
@@ -72,12 +76,22 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
|
||||
for (key in data.entries) {
|
||||
definition = data.entries[key].definition + data.entries[key].attachments;
|
||||
alertpanel = new M.core.alert({title:data.entries[key].concept,
|
||||
alertpanel = new M.core.alert({title:data.entries[key].concept, draggable: true,
|
||||
message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
|
||||
alertpanel.show();
|
||||
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))});
|
||||
|
||||
Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
|
||||
|
||||
// Register alertpanel for stacking.
|
||||
alertpanelid = '#moodle-dialogue-' + alertpanel.get('COUNT');
|
||||
alertpanel.on('complete', this._deletealertpanel(self.alertpanels, alertpanelid));
|
||||
|
||||
// We already have some windows opened, so set the right position...
|
||||
if (!Y.Object.isEmpty(this.alertpanels)){
|
||||
position = this._getLatestWindowPosition();
|
||||
Y.Node.one(alertpanelid).setXY([position[0] + 10, position[1] + 10]);
|
||||
}
|
||||
|
||||
this.alertpanels[alertpanelid] = Y.Node.one(alertpanelid).getXY();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -88,6 +102,18 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
new M.core.exception(e);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
_getLatestWindowPosition : function() {
|
||||
var lastPosition = [0, 0];
|
||||
Y.Object.each(this.alertpanels, function(position) {
|
||||
if (position[0] > lastPosition[0]){
|
||||
lastPosition = position;
|
||||
}
|
||||
});
|
||||
return lastPosition;
|
||||
},
|
||||
_deletealertpanel : function(alertpanels, alertpanelid) {
|
||||
delete alertpanels[alertpanelid];
|
||||
}
|
||||
}, {
|
||||
NAME : AUTOLINKERNAME,
|
||||
@@ -147,6 +173,8 @@ M.filter_glossary.init_filter_autolinking = function(config) {
|
||||
"event-delegate",
|
||||
"overlay",
|
||||
"moodle-core-event",
|
||||
"moodle-core-notification-alert"
|
||||
"moodle-core-notification-alert",
|
||||
"moodle-core-notification-exception",
|
||||
"moodle-core-notification-ajaxexception"
|
||||
]
|
||||
});
|
||||
|
||||
+30
-4
@@ -17,6 +17,7 @@ AUTOLINKER = function() {
|
||||
};
|
||||
Y.extend(AUTOLINKER, Y.Base, {
|
||||
overlay : null,
|
||||
alertpanels: {},
|
||||
initializer : function() {
|
||||
var self = this;
|
||||
Y.delegate('click', function(e){
|
||||
@@ -62,7 +63,10 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
var data,
|
||||
key,
|
||||
alertpanel,
|
||||
definition;
|
||||
alertpanelid,
|
||||
definition,
|
||||
position;
|
||||
var self = this;
|
||||
try {
|
||||
data = Y.JSON.parse(content);
|
||||
if (data.success){
|
||||
@@ -70,12 +74,22 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
|
||||
for (key in data.entries) {
|
||||
definition = data.entries[key].definition + data.entries[key].attachments;
|
||||
alertpanel = new M.core.alert({title:data.entries[key].concept,
|
||||
alertpanel = new M.core.alert({title:data.entries[key].concept, draggable: true,
|
||||
message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
|
||||
alertpanel.show();
|
||||
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))});
|
||||
|
||||
Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
|
||||
|
||||
// Register alertpanel for stacking.
|
||||
alertpanelid = '#moodle-dialogue-' + alertpanel.get('COUNT');
|
||||
alertpanel.on('complete', this._deletealertpanel(self.alertpanels, alertpanelid));
|
||||
|
||||
// We already have some windows opened, so set the right position...
|
||||
if (!Y.Object.isEmpty(this.alertpanels)){
|
||||
position = this._getLatestWindowPosition();
|
||||
Y.Node.one(alertpanelid).setXY([position[0] + 10, position[1] + 10]);
|
||||
}
|
||||
|
||||
this.alertpanels[alertpanelid] = Y.Node.one(alertpanelid).getXY();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -86,6 +100,18 @@ Y.extend(AUTOLINKER, Y.Base, {
|
||||
new M.core.exception(e);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
_getLatestWindowPosition : function() {
|
||||
var lastPosition = [0, 0];
|
||||
Y.Object.each(this.alertpanels, function(position) {
|
||||
if (position[0] > lastPosition[0]){
|
||||
lastPosition = position;
|
||||
}
|
||||
});
|
||||
return lastPosition;
|
||||
},
|
||||
_deletealertpanel : function(alertpanels, alertpanelid) {
|
||||
delete alertpanels[alertpanelid];
|
||||
}
|
||||
}, {
|
||||
NAME : AUTOLINKERNAME,
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
"event-delegate",
|
||||
"overlay",
|
||||
"moodle-core-event",
|
||||
"moodle-core-notification-alert"
|
||||
"moodle-core-notification-alert",
|
||||
"moodle-core-notification-exception",
|
||||
"moodle-core-notification-ajaxexception"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,5 +106,8 @@ MathJax.Hub.Config({
|
||||
upgrade_plugin_savepoint(true, 2015021700, 'filter', 'mathjaxloader');
|
||||
}
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -75,5 +75,8 @@ function xmldb_filter_mediaplugin_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -71,5 +71,8 @@ function xmldb_filter_tex_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,22 @@ class course_settings_form extends moodleform {
|
||||
$mform->addElement('select', 'aggregationposition', get_string('aggregationposition', 'grades'), $options);
|
||||
$mform->addHelpButton('aggregationposition', 'aggregationposition', 'grades');
|
||||
|
||||
if ($CFG->grade_minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_ITEM) {
|
||||
$default = get_string('gradeitemminmax', 'grades');
|
||||
} else if ($CFG->grade_minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_GRADE) {
|
||||
$default = get_string('gradegrademinmax', 'grades');
|
||||
} else {
|
||||
throw new coding_exception('Invalid $CFG->grade_minmaxtouse value.');
|
||||
}
|
||||
|
||||
$options = array(
|
||||
-1 => get_string('defaultprev', 'grades', $default),
|
||||
GRADE_MIN_MAX_FROM_GRADE_ITEM => get_string('gradeitemminmax', 'grades'),
|
||||
GRADE_MIN_MAX_FROM_GRADE_GRADE => get_string('gradegrademinmax', 'grades')
|
||||
);
|
||||
$mform->addElement('select', 'minmaxtouse', get_string('minmaxtouse', 'grades'), $options);
|
||||
$mform->addHelpButton('minmaxtouse', 'minmaxtouse', 'grades');
|
||||
|
||||
// Grade item settings
|
||||
$mform->addElement('header', 'grade_item_settings', get_string('gradeitemsettings', 'grades'));
|
||||
$mform->setExpanded('grade_item_settings');
|
||||
|
||||
@@ -58,7 +58,7 @@ if ($mform->is_cancelled()) {
|
||||
|
||||
} else if ($data = $mform->get_data()) {
|
||||
$data = (array)$data;
|
||||
$general = array('displaytype', 'decimalpoints', 'aggregationposition');
|
||||
$general = array('displaytype', 'decimalpoints', 'aggregationposition', 'minmaxtouse');
|
||||
foreach ($data as $key=>$value) {
|
||||
if (!in_array($key, $general) and strpos($key, 'report_') !== 0
|
||||
and strpos($key, 'import_') !== 0
|
||||
@@ -69,6 +69,12 @@ if ($mform->is_cancelled()) {
|
||||
$value = null;
|
||||
}
|
||||
grade_set_setting($course->id, $key, $value);
|
||||
|
||||
$previousvalue = isset($settings->{$key}) ? $settings->{$key} : null;
|
||||
if ($key == 'minmaxtouse' && $previousvalue != $value) {
|
||||
// The min max has changed, we need to regrade the grades.
|
||||
grade_force_full_regrading($courseid);
|
||||
}
|
||||
}
|
||||
|
||||
redirect($returnurl);
|
||||
@@ -76,6 +82,10 @@ if ($mform->is_cancelled()) {
|
||||
|
||||
print_grade_page_head($courseid, 'settings', 'coursesettings', get_string('coursegradesettings', 'grades'));
|
||||
|
||||
// The settings could have been changed due to a notice shown in print_grade_page_head, we need to refresh them.
|
||||
$settings = grade_get_settings($course->id);
|
||||
$mform->set_data($settings);
|
||||
|
||||
echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthnormal centerpara');
|
||||
echo get_string('coursesettingsexplanation', 'grades');
|
||||
echo $OUTPUT->box_end();
|
||||
|
||||
@@ -86,15 +86,31 @@ if ($id) {
|
||||
} else {
|
||||
$category->grade_item_aggregationcoef = format_float($category->grade_item_aggregationcoef, 4);
|
||||
}
|
||||
|
||||
if ($category->aggregation == GRADE_AGGREGATE_SUM) {
|
||||
// Input fields for grademin and grademax are disabled for the "Natural" category,
|
||||
// this means they will be ignored if user does not change aggregation method.
|
||||
// But if user does change aggregation method the default values should be used.
|
||||
$category->grademax = 100;
|
||||
$category->grade_item_grademax = 100;
|
||||
$category->grademin = 0;
|
||||
$category->grade_item_grademin = 0;
|
||||
// Check to see if the gradebook is frozen. This allows grades to not be altered at all until a user verifies that they
|
||||
// wish to update the grades.
|
||||
$gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $courseid);
|
||||
// Stick with the original code if the grade book is frozen.
|
||||
if ($gradebookcalculationsfreeze && (int)$gradebookcalculationsfreeze <= 20150627) {
|
||||
if ($category->aggregation == GRADE_AGGREGATE_SUM) {
|
||||
// Input fields for grademin and grademax are disabled for the "Natural" category,
|
||||
// this means they will be ignored if user does not change aggregation method.
|
||||
// But if user does change aggregation method the default values should be used.
|
||||
$category->grademax = 100;
|
||||
$category->grade_item_grademax = 100;
|
||||
$category->grademin = 0;
|
||||
$category->grade_item_grademin = 0;
|
||||
}
|
||||
} else {
|
||||
if ($category->aggregation == GRADE_AGGREGATE_SUM && !$grade_item->is_calculated()) {
|
||||
// Input fields for grademin and grademax are disabled for the "Natural" category,
|
||||
// this means they will be ignored if user does not change aggregation method.
|
||||
// But if user does change aggregation method the default values should be used.
|
||||
// This does not apply to calculated category totals.
|
||||
$category->grademax = 100;
|
||||
$category->grade_item_grademax = 100;
|
||||
$category->grademin = 0;
|
||||
$category->grade_item_grademin = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
+18
-1
@@ -237,7 +237,24 @@ abstract class grade_export {
|
||||
if (is_array($this->displaytype) && !is_null($gradedisplayconst)) {
|
||||
$displaytype = $gradedisplayconst;
|
||||
}
|
||||
return grade_format_gradevalue($grade->finalgrade, $this->grade_items[$grade->itemid], false, $displaytype, $this->decimalpoints);
|
||||
|
||||
$gradeitem = $this->grade_items[$grade->itemid];
|
||||
|
||||
// We are going to store the min and max so that we can "reset" the grade_item for later.
|
||||
$grademax = $gradeitem->grademax;
|
||||
$grademin = $gradeitem->grademin;
|
||||
|
||||
// Updating grade_item with this grade_grades min and max.
|
||||
$gradeitem->grademax = $grade->get_grade_max();
|
||||
$gradeitem->grademin = $grade->get_grade_min();
|
||||
|
||||
$formattedgrade = grade_format_gradevalue($grade->finalgrade, $gradeitem, false, $displaytype, $this->decimalpoints);
|
||||
|
||||
// Resetting the grade item in case it is reused.
|
||||
$gradeitem->grademax = $grademax;
|
||||
$gradeitem->grademin = $grademin;
|
||||
|
||||
return $formattedgrade;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ Feature: I need to export grades as text
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled |
|
||||
| assign | C1 | a1 | Test assignment name | Submit your online text | 1 |
|
||||
| assign | C1 | a2 | Test assignment name 2 | Submit your online text | 1 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
@@ -59,6 +60,8 @@ Feature: I need to export grades as text
|
||||
Then I should see "Student,1"
|
||||
And I should see "80.00 %"
|
||||
And I should see "B-"
|
||||
And I should not see "40.00 %"
|
||||
And I should not see ",F,"
|
||||
|
||||
@javascript
|
||||
Scenario: Export grades as text using real, percentages and letters
|
||||
@@ -71,4 +74,6 @@ Feature: I need to export grades as text
|
||||
Then I should see "Student,1"
|
||||
And I should see "80.00"
|
||||
And I should see "80.00 %"
|
||||
And I should see "B-"
|
||||
And I should see "B-"
|
||||
And I should not see "40.00 %"
|
||||
And I should not see ",F,"
|
||||
@@ -59,5 +59,8 @@ function xmldb_gradingform_rubric_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+162
-7
@@ -467,6 +467,45 @@ function hide_natural_aggregation_upgrade_notice($courseid) {
|
||||
unset_config('show_sumofgrades_upgrade_' . $courseid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide warning about changed grades during upgrade from 2.8.0-2.8.6 and 2.9.0.
|
||||
*
|
||||
* @param int $courseid The current course id.
|
||||
*/
|
||||
function grade_hide_min_max_grade_upgrade_notice($courseid) {
|
||||
unset_config('show_min_max_grades_changed_' . $courseid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the grade min and max from the grade_grade.
|
||||
*
|
||||
* This is reserved for core use after an upgrade.
|
||||
*
|
||||
* @param int $courseid The current course id.
|
||||
*/
|
||||
function grade_upgrade_use_min_max_from_grade_grade($courseid) {
|
||||
grade_set_setting($courseid, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
|
||||
|
||||
grade_force_full_regrading($courseid);
|
||||
// Do this now, because it probably happened to late in the page load to be happen automatically.
|
||||
grade_regrade_final_grades($courseid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the grade min and max from the grade_item.
|
||||
*
|
||||
* This is reserved for core use after an upgrade.
|
||||
*
|
||||
* @param int $courseid The current course id.
|
||||
*/
|
||||
function grade_upgrade_use_min_max_from_grade_item($courseid) {
|
||||
grade_set_setting($courseid, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
|
||||
|
||||
grade_force_full_regrading($courseid);
|
||||
// Do this now, because it probably happened to late in the page load to be happen automatically.
|
||||
grade_regrade_final_grades($courseid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide warning about changed grades during upgrade to 2.8.
|
||||
*
|
||||
@@ -476,6 +515,15 @@ function hide_aggregatesubcats_upgrade_notice($courseid) {
|
||||
unset_config('show_aggregatesubcats_upgrade_' . $courseid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide warning about changed grades due to bug fixes
|
||||
*
|
||||
* @param int $courseid The current course id.
|
||||
*/
|
||||
function hide_gradebook_calculations_freeze_notice($courseid) {
|
||||
unset_config('gradebook_calculations_freeze_' . $courseid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print warning about changed grades during upgrade to 2.8.
|
||||
*
|
||||
@@ -487,20 +535,29 @@ function hide_aggregatesubcats_upgrade_notice($courseid) {
|
||||
* @return nothing or string if $return true
|
||||
*/
|
||||
function print_natural_aggregation_upgrade_notice($courseid, $context, $thispage, $return=false) {
|
||||
global $OUTPUT;
|
||||
global $CFG, $OUTPUT;
|
||||
$html = '';
|
||||
|
||||
// Do not do anything if they cannot manage the grades of this course.
|
||||
if (!has_capability('moodle/grade:manage', $context)) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$hidesubcatswarning = optional_param('seenaggregatesubcatsupgradedgrades', false, PARAM_BOOL) && confirm_sesskey();
|
||||
$showsubcatswarning = get_config('core', 'show_aggregatesubcats_upgrade_' . $courseid);
|
||||
$hidenaturalwarning = optional_param('seensumofgradesupgradedgrades', false, PARAM_BOOL) && confirm_sesskey();
|
||||
$shownaturalwarning = get_config('core', 'show_sumofgrades_upgrade_' . $courseid);
|
||||
|
||||
// Do not do anything if they are not a teacher.
|
||||
if ($hidesubcatswarning || $showsubcatswarning || $hidenaturalwarning || $shownaturalwarning) {
|
||||
if (!has_capability('moodle/grade:manage', $context)) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
$hideminmaxwarning = optional_param('seenminmaxupgradedgrades', false, PARAM_BOOL) && confirm_sesskey();
|
||||
$showminmaxwarning = get_config('core', 'show_min_max_grades_changed_' . $courseid);
|
||||
|
||||
$useminmaxfromgradeitem = optional_param('useminmaxfromgradeitem', false, PARAM_BOOL) && confirm_sesskey();
|
||||
$useminmaxfromgradegrade = optional_param('useminmaxfromgradegrade', false, PARAM_BOOL) && confirm_sesskey();
|
||||
|
||||
$minmaxtouse = grade_get_setting($courseid, 'minmaxtouse', $CFG->grade_minmaxtouse);
|
||||
|
||||
$gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $courseid);
|
||||
$acceptgradebookchanges = optional_param('acceptgradebookchanges', false, PARAM_BOOL) && confirm_sesskey();
|
||||
|
||||
// Hide the warning if the user told it to go away.
|
||||
if ($hidenaturalwarning) {
|
||||
@@ -511,6 +568,26 @@ function print_natural_aggregation_upgrade_notice($courseid, $context, $thispage
|
||||
hide_aggregatesubcats_upgrade_notice($courseid);
|
||||
}
|
||||
|
||||
// Hide the min/max warning if the user told it to go away.
|
||||
if ($hideminmaxwarning) {
|
||||
grade_hide_min_max_grade_upgrade_notice($courseid);
|
||||
$showminmaxwarning = false;
|
||||
}
|
||||
|
||||
if ($useminmaxfromgradegrade) {
|
||||
// Revert to the new behaviour, we now use the grade_grade for min/max.
|
||||
grade_upgrade_use_min_max_from_grade_grade($courseid);
|
||||
grade_hide_min_max_grade_upgrade_notice($courseid);
|
||||
$showminmaxwarning = false;
|
||||
|
||||
} else if ($useminmaxfromgradeitem) {
|
||||
// Apply the new logic, we now use the grade_item for min/max.
|
||||
grade_upgrade_use_min_max_from_grade_item($courseid);
|
||||
grade_hide_min_max_grade_upgrade_notice($courseid);
|
||||
$showminmaxwarning = false;
|
||||
}
|
||||
|
||||
|
||||
if (!$hidenaturalwarning && $shownaturalwarning) {
|
||||
$message = get_string('sumofgradesupgradedgrades', 'grades');
|
||||
$hidemessage = get_string('upgradedgradeshidemessage', 'grades');
|
||||
@@ -535,6 +612,84 @@ function print_natural_aggregation_upgrade_notice($courseid, $context, $thispage
|
||||
$html .= $goawaybutton;
|
||||
}
|
||||
|
||||
if ($showminmaxwarning) {
|
||||
$hidemessage = get_string('upgradedgradeshidemessage', 'grades');
|
||||
$urlparams = array( 'id' => $courseid,
|
||||
'seenminmaxupgradedgrades' => true,
|
||||
'sesskey' => sesskey());
|
||||
|
||||
$goawayurl = new moodle_url($thispage, $urlparams);
|
||||
$hideminmaxbutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get');
|
||||
$moreinfo = html_writer::link(get_docs_url(get_string('minmaxtouse_link', 'grades')), get_string('moreinfo'),
|
||||
array('target' => '_blank'));
|
||||
|
||||
if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_ITEM) {
|
||||
// Show the message that there were min/max issues that have been resolved.
|
||||
$message = get_string('minmaxupgradedgrades', 'grades') . ' ' . $moreinfo;
|
||||
|
||||
$revertmessage = get_string('upgradedminmaxrevertmessage', 'grades');
|
||||
$urlparams = array('id' => $courseid,
|
||||
'useminmaxfromgradegrade' => true,
|
||||
'sesskey' => sesskey());
|
||||
$reverturl = new moodle_url($thispage, $urlparams);
|
||||
$revertbutton = $OUTPUT->single_button($reverturl, $revertmessage, 'get');
|
||||
|
||||
$html .= $OUTPUT->notification($message);
|
||||
$html .= $revertbutton . $hideminmaxbutton;
|
||||
|
||||
} else if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_GRADE) {
|
||||
// Show the warning that there are min/max issues that have not be resolved.
|
||||
$message = get_string('minmaxupgradewarning', 'grades') . ' ' . $moreinfo;
|
||||
|
||||
$fixmessage = get_string('minmaxupgradefixbutton', 'grades');
|
||||
$urlparams = array('id' => $courseid,
|
||||
'useminmaxfromgradeitem' => true,
|
||||
'sesskey' => sesskey());
|
||||
$fixurl = new moodle_url($thispage, $urlparams);
|
||||
$fixbutton = $OUTPUT->single_button($fixurl, $fixmessage, 'get');
|
||||
|
||||
$html .= $OUTPUT->notification($message);
|
||||
$html .= $fixbutton . $hideminmaxbutton;
|
||||
}
|
||||
}
|
||||
|
||||
if ($gradebookcalculationsfreeze) {
|
||||
if ($acceptgradebookchanges) {
|
||||
// Accept potential changes in grades caused by extra credit bug MDL-49257.
|
||||
hide_gradebook_calculations_freeze_notice($courseid);
|
||||
$courseitem = grade_item::fetch_course_item($courseid);
|
||||
$courseitem->force_regrading();
|
||||
grade_regrade_final_grades($courseid);
|
||||
|
||||
$html .= $OUTPUT->notification(get_string('gradebookcalculationsuptodate', 'grades'), 'notifysuccess');
|
||||
} else {
|
||||
// Show the warning that there may be extra credit weights problems.
|
||||
$a = new stdClass();
|
||||
$a->gradebookversion = $gradebookcalculationsfreeze;
|
||||
if (preg_match('/(\d{8,})/', $CFG->release, $matches)) {
|
||||
$a->currentversion = $matches[1];
|
||||
} else {
|
||||
$a->currentversion = $CFG->release;
|
||||
}
|
||||
$a->url = get_docs_url('Gradebook_calculation_changes');
|
||||
$message = get_string('gradebookcalculationswarning', 'grades', $a);
|
||||
|
||||
$fixmessage = get_string('gradebookcalculationsfixbutton', 'grades');
|
||||
$urlparams = array('id' => $courseid,
|
||||
'acceptgradebookchanges' => true,
|
||||
'sesskey' => sesskey());
|
||||
$fixurl = new moodle_url($thispage, $urlparams);
|
||||
$fixbutton = $OUTPUT->single_button($fixurl, $fixmessage, 'get');
|
||||
|
||||
$html .= $OUTPUT->notification($message);
|
||||
$html .= $fixbutton;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($html)) {
|
||||
$html = html_writer::tag('div', $html, array('class' => 'core_grades_notices'));
|
||||
}
|
||||
|
||||
if ($return) {
|
||||
return $html;
|
||||
} else {
|
||||
|
||||
+10
-11
@@ -589,6 +589,9 @@ class grade_report_grader extends grade_report {
|
||||
$rows = array();
|
||||
|
||||
$showuserimage = $this->get_pref('showuserimage');
|
||||
$canseeuserreport = has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context);
|
||||
$canseesingleview = has_capability('gradereport/singleview:view', $this->context);
|
||||
$hasuserreportcell = $canseeuserreport || $canseesingleview;
|
||||
|
||||
$strfeedback = $this->get_lang_string("feedback");
|
||||
$strgrade = $this->get_lang_string('grade');
|
||||
@@ -597,11 +600,7 @@ class grade_report_grader extends grade_report {
|
||||
|
||||
$arrows = $this->get_sort_arrows($extrafields);
|
||||
|
||||
$colspan = 1;
|
||||
if (has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context)) {
|
||||
$colspan++;
|
||||
}
|
||||
$colspan += count($extrafields);
|
||||
$colspan = 1 + $hasuserreportcell + count($extrafields);
|
||||
|
||||
$levels = count($this->gtree->levels) - 1;
|
||||
|
||||
@@ -628,7 +627,7 @@ class grade_report_grader extends grade_report {
|
||||
$studentheader->scope = 'col';
|
||||
$studentheader->header = true;
|
||||
$studentheader->id = 'studentheader';
|
||||
if (has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context)) {
|
||||
if ($hasuserreportcell) {
|
||||
$studentheader->colspan = 2;
|
||||
}
|
||||
$studentheader->text = $arrows['studentname'];
|
||||
@@ -685,7 +684,7 @@ class grade_report_grader extends grade_report {
|
||||
$userreportcell = new html_table_cell();
|
||||
$userreportcell->attributes['class'] = 'userreport';
|
||||
$userreportcell->header = false;
|
||||
if (has_capability('gradereport/'.$CFG->grade_profilereport.':view', $this->context)) {
|
||||
if ($canseeuserreport) {
|
||||
$a = new stdClass();
|
||||
$a->user = $fullname;
|
||||
$strgradesforuser = get_string('gradesforuser', 'grades', $a);
|
||||
@@ -693,7 +692,7 @@ class grade_report_grader extends grade_report {
|
||||
$userreportcell->text .= $OUTPUT->action_icon($url, new pix_icon('t/grades', $strgradesforuser));
|
||||
}
|
||||
|
||||
if (has_capability('gradereport/singleview:view', $this->context)) {
|
||||
if ($canseesingleview) {
|
||||
$url = new moodle_url('/grade/report/singleview/index.php', array('id' => $this->course->id, 'itemid' => $user->id, 'item' => 'user'));
|
||||
$singleview = $OUTPUT->action_icon($url, new pix_icon('t/editstring', get_string('singleview', 'grades', $fullname)));
|
||||
$userreportcell->text .= $singleview;
|
||||
@@ -844,7 +843,7 @@ class grade_report_grader extends grade_report {
|
||||
'itemid' => $element['object']->id));
|
||||
$singleview = $OUTPUT->action_icon(
|
||||
$url,
|
||||
new pix_icon('t/editstring', get_string('singleview', 'grades', $element['object']->itemname))
|
||||
new pix_icon('t/editstring', get_string('singleview', 'grades', $element['object']->get_name()))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1086,8 +1085,8 @@ class grade_report_grader extends grade_report {
|
||||
} else {
|
||||
// The max and min for an aggregation may be different to the grade_item.
|
||||
if (!is_null($gradeval)) {
|
||||
$item->grademax = $grade->rawgrademax;
|
||||
$item->grademin = $grade->rawgrademin;
|
||||
$item->grademax = $grade->get_grade_max();
|
||||
$item->grademin = $grade->get_grade_min();
|
||||
}
|
||||
|
||||
$itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>" .
|
||||
|
||||
+13
-1
@@ -620,13 +620,25 @@ FloatingHeaders.prototype = {
|
||||
|
||||
// Generate the new fields.
|
||||
userColumn.each(function(node) {
|
||||
var height = node.getComputedStyle(HEIGHT);
|
||||
// Nasty hack to account for Internet Explorer
|
||||
if(Y.UA.ie !== 0) {
|
||||
var allHeight = node.get('offsetHeight');
|
||||
var marginHeight = parseInt(node.getComputedStyle('marginTop'),10) +
|
||||
parseInt(node.getComputedStyle('marginBottom'),10);
|
||||
var paddingHeight = parseInt(node.getComputedStyle('paddingTop'),10) +
|
||||
parseInt(node.getComputedStyle('paddingBottom'),10);
|
||||
var borderHeight = parseInt(node.getComputedStyle('borderTopWidth'),10) +
|
||||
parseInt(node.getComputedStyle('borderBottomWidth'),10);
|
||||
height = allHeight - marginHeight - paddingHeight - borderHeight;
|
||||
}
|
||||
// Create and configure the new container.
|
||||
var containerNode = Y.Node.create('<div></div>');
|
||||
containerNode.set('innerHTML', node.get('innerHTML'))
|
||||
.setAttribute('class', node.getAttribute('class'))
|
||||
.setAttribute('data-uid', node.ancestor('tr').getData('uid'))
|
||||
.setStyles({
|
||||
height: node.getComputedStyle(HEIGHT),
|
||||
height: height,
|
||||
width: node.getComputedStyle(WIDTH)
|
||||
});
|
||||
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
+13
-1
@@ -620,13 +620,25 @@ FloatingHeaders.prototype = {
|
||||
|
||||
// Generate the new fields.
|
||||
userColumn.each(function(node) {
|
||||
var height = node.getComputedStyle(HEIGHT);
|
||||
// Nasty hack to account for Internet Explorer
|
||||
if(Y.UA.ie !== 0) {
|
||||
var allHeight = node.get('offsetHeight');
|
||||
var marginHeight = parseInt(node.getComputedStyle('marginTop'),10) +
|
||||
parseInt(node.getComputedStyle('marginBottom'),10);
|
||||
var paddingHeight = parseInt(node.getComputedStyle('paddingTop'),10) +
|
||||
parseInt(node.getComputedStyle('paddingBottom'),10);
|
||||
var borderHeight = parseInt(node.getComputedStyle('borderTopWidth'),10) +
|
||||
parseInt(node.getComputedStyle('borderBottomWidth'),10);
|
||||
height = allHeight - marginHeight - paddingHeight - borderHeight;
|
||||
}
|
||||
// Create and configure the new container.
|
||||
var containerNode = Y.Node.create('<div></div>');
|
||||
containerNode.set('innerHTML', node.get('innerHTML'))
|
||||
.setAttribute('class', node.getAttribute('class'))
|
||||
.setAttribute('data-uid', node.ancestor('tr').getData('uid'))
|
||||
.setStyles({
|
||||
height: node.getComputedStyle(HEIGHT),
|
||||
height: height,
|
||||
width: node.getComputedStyle(WIDTH)
|
||||
});
|
||||
|
||||
|
||||
@@ -477,13 +477,25 @@ FloatingHeaders.prototype = {
|
||||
|
||||
// Generate the new fields.
|
||||
userColumn.each(function(node) {
|
||||
var height = node.getComputedStyle(HEIGHT);
|
||||
// Nasty hack to account for Internet Explorer
|
||||
if(Y.UA.ie !== 0) {
|
||||
var allHeight = node.get('offsetHeight');
|
||||
var marginHeight = parseInt(node.getComputedStyle('marginTop'),10) +
|
||||
parseInt(node.getComputedStyle('marginBottom'),10);
|
||||
var paddingHeight = parseInt(node.getComputedStyle('paddingTop'),10) +
|
||||
parseInt(node.getComputedStyle('paddingBottom'),10);
|
||||
var borderHeight = parseInt(node.getComputedStyle('borderTopWidth'),10) +
|
||||
parseInt(node.getComputedStyle('borderBottomWidth'),10);
|
||||
height = allHeight - marginHeight - paddingHeight - borderHeight;
|
||||
}
|
||||
// Create and configure the new container.
|
||||
var containerNode = Y.Node.create('<div></div>');
|
||||
containerNode.set('innerHTML', node.get('innerHTML'))
|
||||
.setAttribute('class', node.getAttribute('class'))
|
||||
.setAttribute('data-uid', node.ancestor('tr').getData('uid'))
|
||||
.setStyles({
|
||||
height: node.getComputedStyle(HEIGHT),
|
||||
height: height,
|
||||
width: node.getComputedStyle(WIDTH)
|
||||
});
|
||||
|
||||
|
||||
@@ -413,7 +413,7 @@ class tablelog extends \table_sql implements \renderable {
|
||||
|
||||
$sql = "SELECT $select
|
||||
FROM {grade_grades_history} ggh
|
||||
LEFT JOIN {grade_items} gi ON gi.id = ggh.itemid
|
||||
JOIN {grade_items} gi ON gi.id = ggh.itemid
|
||||
JOIN {user} u ON u.id = ggh.userid
|
||||
LEFT JOIN {user} ug ON ug.id = ggh.usermodified
|
||||
WHERE $where";
|
||||
|
||||
@@ -55,7 +55,7 @@ abstract class grade_report {
|
||||
|
||||
/**
|
||||
* The grade_tree object.
|
||||
* @var object $gtree
|
||||
* @var grade_tree $gtree
|
||||
*/
|
||||
public $gtree;
|
||||
|
||||
@@ -437,8 +437,8 @@ abstract class grade_report {
|
||||
$grademin = $course_item->grademin;
|
||||
$grademax = $course_item->grademax;
|
||||
if ($coursegradegrade) {
|
||||
$grademin = $coursegradegrade->rawgrademin;
|
||||
$grademax = $coursegradegrade->rawgrademax;
|
||||
$grademin = $coursegradegrade->get_grade_min();
|
||||
$grademax = $coursegradegrade->get_grade_max();
|
||||
} else {
|
||||
$coursegradegrade = new grade_grade(array('userid'=>$this->user->id, 'itemid'=>$course_item->id), false);
|
||||
}
|
||||
|
||||
@@ -238,11 +238,11 @@ class grade_report_overview extends grade_report {
|
||||
$course_item->grademin = $adjustedgrade['grademin'];
|
||||
}
|
||||
} else {
|
||||
// We must use the rawgrademin / rawgrademax because it can be different for
|
||||
// We must use the specific max/min because it can be different for
|
||||
// each grade_grade when items are excluded from sum of grades.
|
||||
if (!is_null($finalgrade)) {
|
||||
$course_item->grademin = $course_grade->rawgrademin;
|
||||
$course_item->grademax = $course_grade->rawgrademax;
|
||||
$course_item->grademin = $course_grade->get_grade_min();
|
||||
$course_item->grademax = $course_grade->get_grade_max();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,12 +113,6 @@ class user extends tablelike implements selectable_items {
|
||||
$params = array('courseid' => $this->courseid);
|
||||
|
||||
$seq = new grade_seq($this->courseid, true);
|
||||
foreach ($seq->items as $key => $item) {
|
||||
if (isset($item->itemmodule)) {
|
||||
list($courseid, $cmid) = get_course_and_cm_from_instance($item->iteminstance, $item->itemmodule);
|
||||
$seq->items[$key]->cmid = $cmid->id;
|
||||
}
|
||||
}
|
||||
|
||||
$this->items = array();
|
||||
foreach ($seq->items as $itemid => $item) {
|
||||
@@ -179,11 +173,6 @@ class user extends tablelike implements selectable_items {
|
||||
$lockicon = $OUTPUT->pix_icon('t/locked', 'grade is locked');
|
||||
}
|
||||
|
||||
$realmodid = '';
|
||||
if (isset($item->cmid)) {
|
||||
$realmodid = $item->cmid;
|
||||
}
|
||||
|
||||
$iconstring = get_string('filtergrades', 'gradereport_singleview', $item->get_name());
|
||||
|
||||
// Create a fake gradetreeitem so we can call get_element_header().
|
||||
@@ -200,12 +189,6 @@ class user extends tablelike implements selectable_items {
|
||||
$itemlabel = $this->structure->get_element_header($gradetreeitem, true, false, false, false, true);
|
||||
$grade->label = $item->get_name();
|
||||
|
||||
$itemlabel = $item->get_name();
|
||||
if (!empty($realmodid)) {
|
||||
$url = new moodle_url('/mod/' . $item->itemmodule . '/view.php', array('id' => $realmodid));
|
||||
$itemlabel = html_writer::link($url, $item->get_name());
|
||||
}
|
||||
|
||||
$line = array(
|
||||
$OUTPUT->action_icon($this->format_link('grade', $item->id), new pix_icon('t/editstring', $iconstring)),
|
||||
$this->format_icon($item) . $lockicon . $itemlabel,
|
||||
|
||||
@@ -39,5 +39,8 @@ function xmldb_gradereport_user_upgrade($oldversion) {
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -466,8 +466,8 @@ class grade_report_user extends grade_report {
|
||||
} else {
|
||||
// The max and min for an aggregation may be different to the grade_item.
|
||||
if (!is_null($gradeval)) {
|
||||
$grade_grade->grade_item->grademax = $grade_grade->rawgrademax;
|
||||
$grade_grade->grade_item->grademin = $grade_grade->rawgrademin;
|
||||
$grade_grade->grade_item->grademax = $grade_grade->get_grade_max();
|
||||
$grade_grade->grade_item->grademin = $grade_grade->get_grade_min();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,7 +859,7 @@ class grade_report_user extends grade_report {
|
||||
* Builds the grade item averages.
|
||||
*/
|
||||
function calculate_averages() {
|
||||
global $USER, $DB;
|
||||
global $USER, $DB, $CFG;
|
||||
|
||||
if ($this->showaverage) {
|
||||
// This settings are actually grader report settings (not user report)
|
||||
@@ -882,7 +882,11 @@ class grade_report_user extends grade_report {
|
||||
list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
|
||||
|
||||
// Limit to users with an active enrolment.
|
||||
list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context);
|
||||
$coursecontext = $this->context->get_course_context(true);
|
||||
$defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
|
||||
$showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
|
||||
$showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext);
|
||||
list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context, '', 0, $showonlyactiveenrol);
|
||||
|
||||
$params = array_merge($this->groupwheresql_params, $gradebookrolesparams, $enrolledparams, $relatedctxparams);
|
||||
$params['courseid'] = $this->courseid;
|
||||
|
||||
@@ -79,6 +79,122 @@ class behat_grade extends behat_base {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a calculated manual grade item. Needs a table with item name - idnumber relation. The step requires you to be in categories and items page.
|
||||
*
|
||||
* @Given /^I set "(?P<calculation_string>(?:[^"]|\\")*)" calculation for grade item "(?P<grade_item_string>(?:[^"]|\\")*)" with idnumbers:$/
|
||||
* @param string $calculation The calculation.
|
||||
* @param string $gradeitem The grade item name.
|
||||
* @param TableNode $TableNode The grade item name - idnumbers relation.
|
||||
* @return Given[]
|
||||
*/
|
||||
public function i_set_calculation_for_grade_item_with_idnumbers($calculation, $gradeitem, TableNode $data) {
|
||||
|
||||
$steps = array();
|
||||
$gradeitem = $this->getSession()->getSelectorsHandler()->xpathLiteral($gradeitem);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]//a[contains(@class,'toggle-display')]";
|
||||
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$steps[] = new Given('I click on "' . $this->escape($xpath) . '" "xpath_element"');
|
||||
}
|
||||
}
|
||||
|
||||
// Going to edit calculation.
|
||||
$savechanges = get_string('savechanges', 'grades');
|
||||
$edit = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('editcalculation', 'grades'));
|
||||
$linkxpath = "//a[./img[starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$steps[] = new Given('I click on "' . $this->escape($linkxpath) . '" "xpath_element"');
|
||||
|
||||
// After adding id numbers we should wait until the page is reloaded.
|
||||
if ($this->running_javascript()) {
|
||||
$steps[] = new Given('I wait until the page is ready');
|
||||
}
|
||||
|
||||
// Mapping names to idnumbers.
|
||||
$datahash = $data->getRowsHash();
|
||||
foreach ($datahash as $gradeitem => $idnumber) {
|
||||
// This xpath looks for course, categories and items with the provided name.
|
||||
// Grrr, we can't equal in categoryitem and courseitem because there is a line jump...
|
||||
$inputxpath ="//input[@class='idnumber'][" .
|
||||
"parent::li[@class='item'][text()='" . $gradeitem . "']" .
|
||||
" or " .
|
||||
"parent::li[@class='categoryitem' or @class='courseitem']/parent::ul/parent::li[starts-with(text(),'" . $gradeitem . "')]" .
|
||||
"]";
|
||||
$steps[] = new Given('I set the field with xpath "' . $inputxpath . '" to "' . $idnumber . '"');
|
||||
}
|
||||
|
||||
$steps[] = new Given('I press "' . get_string('addidnumbers', 'grades') . '"');
|
||||
|
||||
// After adding id numbers we should wait until the page is reloaded.
|
||||
if ($this->running_javascript()) {
|
||||
$steps[] = new Given('I wait until the page is ready');
|
||||
}
|
||||
|
||||
$steps[] = new Given('I set the field "' . get_string('calculation', 'grades') . '" to "' . $calculation . '"');
|
||||
$steps[] = new Given('I press "' . $savechanges . '"');
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a calculated manual grade category total. Needs a table with item name - idnumber relation.
|
||||
* The step requires you to be in categories and items page.
|
||||
*
|
||||
* @Given /^I set "(?P<calculation_string>(?:[^"]|\\")*)" calculation for grade category "(?P<grade_item_string>(?:[^"]|\\")*)" with idnumbers:$/
|
||||
* @param string $calculation The calculation.
|
||||
* @param string $gradeitem The grade item name.
|
||||
* @param TableNode $data The grade item name - idnumbers relation.
|
||||
* @return Given[]
|
||||
*/
|
||||
public function i_set_calculation_for_grade_category_with_idnumbers($calculation, $gradeitem, TableNode $data) {
|
||||
|
||||
$steps = array();
|
||||
$gradecategorytotal = $this->getSession()->getSelectorsHandler()->xpathLiteral($gradeitem . ' total');
|
||||
$gradeitem = $this->getSession()->getSelectorsHandler()->xpathLiteral($gradeitem);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//tr[contains(.,$gradecategorytotal)]//*[contains(@class,'moodle-actionmenu')]" .
|
||||
"//a[contains(@class,'toggle-display')]";
|
||||
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
|
||||
$steps[] = new Given('I click on "' . $this->escape($xpath) . '" "xpath_element"');
|
||||
}
|
||||
}
|
||||
|
||||
// Going to edit calculation.
|
||||
$savechanges = get_string('savechanges', 'grades');
|
||||
$edit = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('editcalculation', 'grades'));
|
||||
$linkxpath = "//a[./img[starts-with(@title,$edit) and contains(@title,$gradeitem)]]";
|
||||
$steps[] = new Given('I click on "' . $this->escape($linkxpath) . '" "xpath_element"');
|
||||
|
||||
// After adding id numbers we should wait until the page is reloaded.
|
||||
$steps[] = new Given('I wait until the page is ready');
|
||||
|
||||
// Mapping names to idnumbers.
|
||||
$datahash = $data->getRowsHash();
|
||||
foreach ($datahash as $gradeitem => $idnumber) {
|
||||
// This xpath looks for course, categories and items with the provided name.
|
||||
// Grrr, we can't equal in categoryitem and courseitem because there is a line jump...
|
||||
$inputxpath = "//input[@class='idnumber'][" .
|
||||
"parent::li[@class='item'][text()='" . $gradeitem . "']" .
|
||||
" | " .
|
||||
"parent::li[@class='categoryitem' | @class='courseitem']" .
|
||||
"/parent::ul/parent::li[starts-with(text(),'" . $gradeitem . "')]" .
|
||||
"]";
|
||||
$steps[] = new Given('I set the field with xpath "' . $inputxpath . '" to "' . $idnumber . '"');
|
||||
}
|
||||
|
||||
$steps[] = new Given('I press "' . get_string('addidnumbers', 'grades') . '"');
|
||||
|
||||
// After adding id numbers we should wait until the page is reloaded.
|
||||
$steps[] = new Given('I wait until the page is ready');
|
||||
|
||||
$steps[] = new Given('I set the field "' . get_string('calculation', 'grades') . '" to "' . $calculation . '"');
|
||||
$steps[] = new Given('I press "' . $savechanges . '"');
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the weights for the grade category
|
||||
*
|
||||
@@ -104,4 +220,18 @@ class behat_grade extends behat_base {
|
||||
$steps[] = new Given('I click on "' . $this->escape($linktext) . '" "link"');
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step allowing to test before-the-fix behaviour of the gradebook
|
||||
*
|
||||
* @Given /^gradebook calculations for the course "(?P<coursename_string>(?:[^"]|\\")*)" are frozen at version "(?P<version_string>(?:[^"]|\\")*)"$/
|
||||
* @param string $coursename
|
||||
* @param string $version
|
||||
* @return Given
|
||||
*/
|
||||
public function gradebook_calculations_for_the_course_are_frozen_at_version($coursename, $version) {
|
||||
global $DB;
|
||||
$courseid = $DB->get_field('course', 'id', array('shortname' => $coursename), MUST_EXIST);
|
||||
set_config('gradebook_calculations_freeze_' . $courseid, $version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
@core @core_grades
|
||||
Feature: Average grades are displayed in the gradebook
|
||||
In order to check the expected results are displayed
|
||||
As an admin
|
||||
I need to assign grades and check that they display correctly in the gradebook.
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
| student3 | Student | 3 | student3@example.com |
|
||||
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 "admin"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
# Enable averages
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Course grade settings" node in "Grade administration > Setup"
|
||||
And I set the following fields to these values:
|
||||
| Show average | Show |
|
||||
And I press "Save changes"
|
||||
# Add a manual grade item
|
||||
And I navigate to "Categories and items" node in "Grade administration > Setup"
|
||||
And I press "Add grade item"
|
||||
And I set the following fields to these values:
|
||||
| Item name | Manual item 1 |
|
||||
And I press "Save changes"
|
||||
# Give all student the same grade for the manual grade item
|
||||
And I navigate to "Grader report" node in "Grade administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "50.00" to the user "Student 1" for the grade item "Manual item 1"
|
||||
And I give the grade "50.00" to the user "Student 2" for the grade item "Manual item 1"
|
||||
And I give the grade "50.00" to the user "Student 3" for the grade item "Manual item 1"
|
||||
And I press "Save changes"
|
||||
And I turn editing mode off
|
||||
# Suspend a user
|
||||
And I navigate to "Enrolled users" node in "Course administration > Users"
|
||||
And I click on "Edit" "link" in the "Student 2" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Status | Suspended |
|
||||
And I press "Save changes"
|
||||
|
||||
Scenario: Grade a grade item and ensure the results display correctly in the gradebook
|
||||
# Check the admin grade table
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
Then I should see "50.00" in the ".avg.r0.lastrow .c1" "css_element"
|
||||
Then I should see "50.00" in the ".avg.r0.lastrow .c2" "css_element"
|
||||
And I log out
|
||||
|
||||
# Check the user grade table
|
||||
And I log in as "student1"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
Then I should see "50.00" in the ".level2.column-grade" "css_element"
|
||||
Then I should see "50.00" in the ".level2.column-average" "css_element"
|
||||
And I log out
|
||||
@@ -0,0 +1,164 @@
|
||||
@core @core_grades
|
||||
Feature: Calculated grade items can be used in the gradebook
|
||||
In order to use calculated grade items in the gradebook
|
||||
As a teacher
|
||||
I need setup calculated grade items in the categories and items page.
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
|
||||
| student1 | Student | 1 | student1@example.com | s1 |
|
||||
| student2 | Student | 2 | student2@example.com | s2 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Categories and items" node in "Grade administration > Setup"
|
||||
|
||||
@javascript
|
||||
Scenario: The max grade for a category item, with a calculation using Natural aggregation, can be changed
|
||||
Given I press "Add category"
|
||||
And I set the following fields to these values:
|
||||
| Category name | Calc cat |
|
||||
And I press "Save changes"
|
||||
And I press "Add grade item"
|
||||
And I set the following fields to these values:
|
||||
| Item name | grade item 1 |
|
||||
| Grade category | Calc cat |
|
||||
And I press "Save changes"
|
||||
And I set "=[[gi1]]/2" calculation for grade category "Calc cat" with idnumbers:
|
||||
| grade item 1 | gi1 |
|
||||
And I set the following settings for grade item "Calc cat":
|
||||
| Maximum grade | 50 |
|
||||
And I follow "Grader report"
|
||||
And I turn editing mode on
|
||||
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
And I select "Student 1" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | - | 75.00 | 0–100 | 75.00 % | - |
|
||||
| Calc cat totalInclude empty grades. | 100.00 % | 37.50 | 0–50 | 75.00 % | - |
|
||||
| Course total | - | 37.50 | 0–50 | 75.00 % | - |
|
||||
|
||||
@javascript
|
||||
Scenario: Changing max grade for a category item with a calculation that has existing grades will display the same points with the new max grade values immediately.
|
||||
Given I press "Add category"
|
||||
And I set the following fields to these values:
|
||||
| Category name | Calc cat |
|
||||
And I press "Save changes"
|
||||
And I press "Add grade item"
|
||||
And I set the following fields to these values:
|
||||
| Item name | grade item 1 |
|
||||
| Grade category | Calc cat |
|
||||
And I press "Save changes"
|
||||
And I set "=[[gi1]]/2" calculation for grade category "Calc cat" with idnumbers:
|
||||
| grade item 1 | gi1 |
|
||||
And I set the following settings for grade item "Calc cat":
|
||||
| Maximum grade | 50 |
|
||||
And I follow "Grader report"
|
||||
And I turn editing mode on
|
||||
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
And I select "Student 1" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | - | 75.00 | 0–100 | 75.00 % | - |
|
||||
| Calc cat totalInclude empty grades. | 100.00 % | 37.50 | 0–50 | 75.00 % | - |
|
||||
| Course total | - | 37.50 | 0–50 | 75.00 % | - |
|
||||
And I navigate to "Categories and items" node in "Grade administration > Setup"
|
||||
And I set the following settings for grade item "Calc cat":
|
||||
| Maximum grade | 40 |
|
||||
And I follow "Grader report"
|
||||
And I give the grade "65.00" to the user "Student 2" for the grade item "grade item 1"
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
When I select "Student 1" from the "Select all or one user" singleselect
|
||||
Then the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | - | 75.00 | 0–100 | 75.00 % | - |
|
||||
| Calc cat totalInclude empty grades. | 100.00 % | 37.50 | 0–40 | 93.75 % | - |
|
||||
| Course total | - | 37.50 | 0–40 | 93.75 % | - |
|
||||
And I select "Student 2" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | - | 65.00 | 0–100 | 65.00 % | - |
|
||||
| Calc cat totalInclude empty grades. | 100.00 % | 32.50 | 0–40 | 81.25 % | - |
|
||||
| Course total | - | 32.50 | 0–40 | 81.25 % | - |
|
||||
And I navigate to "Course grade settings" node in "Grade administration > Setup"
|
||||
And I set the following fields to these values:
|
||||
| Min and max grades used in calculation | Initial min and max grades |
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
And I select "Student 1" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | - | 75.00 | 0–100 | 75.00 % | - |
|
||||
| Calc cat totalInclude empty grades. | 100.00 % | 37.50 | 0–40 | 93.75 % | - |
|
||||
| Course total | - | 37.50 | 0–40 | 93.75 % | - |
|
||||
And I select "Student 2" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | - | 65.00 | 0–100 | 65.00 % | - |
|
||||
| Calc cat totalInclude empty grades. | 100.00 % | 32.50 | 0–40 | 81.25 % | - |
|
||||
| Course total | - | 32.50 | 0–40 | 81.25 % | - |
|
||||
|
||||
@javascript
|
||||
Scenario: Values in calculated grade items are not always out of one hundred
|
||||
Given I press "Add grade item"
|
||||
And I set the following fields to these values:
|
||||
| Item name | grade item 1 |
|
||||
And I press "Save changes"
|
||||
And I press "Add grade item"
|
||||
And I set the following fields to these values:
|
||||
| Item name | calc item |
|
||||
And I press "Save changes"
|
||||
And I set "=[[gi1]]/2" calculation for grade item "calc item" with idnumbers:
|
||||
| grade item 1 | gi1 |
|
||||
And I set the following settings for grade item "calc item":
|
||||
| Maximum grade | 50 |
|
||||
And I navigate to "Course grade settings" node in "Grade administration > Setup"
|
||||
And I set the following fields to these values:
|
||||
| Min and max grades used in calculation | Initial min and max grades |
|
||||
And I press "Save changes"
|
||||
And I follow "Grader report"
|
||||
And I turn editing mode on
|
||||
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
When I select "Student 1" from the "Select all or one user" singleselect
|
||||
Then the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | 66.67 % | 75.00 | 0–100 | 75.00 % | 50.00 % |
|
||||
| calc item | 33.33 % | 37.50 | 0–50 | 75.00 % | 25.00 % |
|
||||
| Course total | - | 112.50 | 0–150 | 75.00 % | - |
|
||||
And I navigate to "Categories and items" node in "Grade administration > Setup"
|
||||
And I set the following settings for grade item "calc item":
|
||||
| Maximum grade | 40 |
|
||||
And I follow "Grader report"
|
||||
And I give the grade "65.00" to the user "Student 2" for the grade item "grade item 1"
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
And I select "Student 1" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | 71.43 % | 75.00 | 0–100 | 75.00 % | 53.57 % |
|
||||
| calc item | 28.57 % | 37.50 | 0–40 | 93.75 % | 26.79 % |
|
||||
| Course total | - | 112.50 | 0–140 | 80.36 % | - |
|
||||
And I select "Student 2" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
|
||||
| grade item 1 | 71.43 % | 65.00 | 0–100 | 65.00 % | 46.43 % |
|
||||
| calc item | 28.57 % | 32.50 | 0–40 | 81.25 % | 23.21 % |
|
||||
| Course total | - | 97.50 | 0–140 | 69.64 % | - |
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user