Compare commits
497 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b3d19c2f5 | |||
| b4d0a4479c | |||
| 3e07b8a2f3 | |||
| 383776876b | |||
| 91c8d4da71 | |||
| 1721c8eb85 | |||
| c5f351435e | |||
| 03b06dedbc | |||
| da80885cc6 | |||
| 94ac7a87fa | |||
| 10b02d6d41 | |||
| ebb6f3e80b | |||
| 7f4db6f4d9 | |||
| 4fc5861cba | |||
| 40b205197c | |||
| cb914a71aa | |||
| 85f376892d | |||
| e0708141f8 | |||
| 76b012d611 | |||
| 53ca351f7a | |||
| ea9f3057da | |||
| f1406d3b39 | |||
| 91251e4889 | |||
| 8994593332 | |||
| 67b3704318 | |||
| 37e7d91b8c | |||
| 3fe64cbd7d | |||
| 22051a4e34 | |||
| e7cd680765 | |||
| 84d2c6f761 | |||
| f97581eda7 | |||
| 2c0b608cda | |||
| eb1381de1d | |||
| 4eacb77012 | |||
| 93835758f3 | |||
| a238e7ed72 | |||
| 98ac33bcb0 | |||
| 0caa8c60d2 | |||
| 2dbdaedc3e | |||
| 30a264540b | |||
| 6d05bee940 | |||
| 2535dfaf64 | |||
| 35186e3725 | |||
| bfe4417cb7 | |||
| 6b6affec1f | |||
| 9e13649c89 | |||
| f549deed15 | |||
| ab59b7db71 | |||
| 200a2b7fad | |||
| 9945bcec41 | |||
| b4ac5653ed | |||
| 0207466e77 | |||
| 2ca9e09dab | |||
| 6eaf5ec8e3 | |||
| 1d110af2d6 | |||
| 2d121036cc | |||
| 61961447c2 | |||
| 867f40990b | |||
| 78ba7d9e6b | |||
| 63010978b4 | |||
| c5e9bc48f0 | |||
| cd90445d4a | |||
| 0052796dbb | |||
| b522356839 | |||
| 1d45b926f3 | |||
| 0ba5f02b15 | |||
| a31fdfb145 | |||
| d019ffd21f | |||
| a93f8344ae | |||
| 2d7617aa18 | |||
| 84acc68175 | |||
| 38d8b7b703 | |||
| 69ddeb42e2 | |||
| 2bd9cd1077 | |||
| 35588aa876 | |||
| fc415ee908 | |||
| 10b4bda916 | |||
| 3708e1bb7c | |||
| e7e79055e1 | |||
| 3d4cf404df | |||
| 31c0efeac7 | |||
| 3571cd46d2 | |||
| fa6db7b8c1 | |||
| 947a90339a | |||
| dc30afaafc | |||
| 03a5278a38 | |||
| d683942c6a | |||
| 24c0432bbc | |||
| c16de45a14 | |||
| 9d19781014 | |||
| ab6ae906cd | |||
| f45b59d427 | |||
| 3add7d878f | |||
| c9bd902bd3 | |||
| 366124d222 | |||
| 89203e11a7 | |||
| dd83fbfbbc | |||
| 1fb374121a | |||
| f3163a2002 | |||
| 65764352dd | |||
| 2c7b800f2f | |||
| ed7d676329 | |||
| b23bc0a148 | |||
| df9a669791 | |||
| b1ab535efa | |||
| 1e9dce0df4 | |||
| 8dd0756226 | |||
| 8458e3d2c2 | |||
| 951a64f6ef | |||
| b336cf98b4 | |||
| b6ac868d71 | |||
| 57ce05c631 | |||
| f0538cee92 | |||
| f4f4965a1c | |||
| 93a593daab | |||
| c8c1a2cb10 | |||
| 793ab11d95 | |||
| 47221d5fdd | |||
| 1affa3ea22 | |||
| 70971d43eb | |||
| 99e0bb23bf | |||
| d95453d903 | |||
| 53fb01aef0 | |||
| cfd5ba4101 | |||
| 5eb386fd09 | |||
| 594848bb15 | |||
| 64fea720ce | |||
| 83d08fcc21 | |||
| 01e7204646 | |||
| 3152864fd5 | |||
| 2997bd6dce | |||
| 083d5a6f0c | |||
| c1ee80fef5 | |||
| 0a9815d14e | |||
| 3ac5a3544c | |||
| 6f5ca6613f | |||
| a16755314a | |||
| a4919abf4f | |||
| 022a58af8d | |||
| 6480ec0c48 | |||
| 1e4e4a05d7 | |||
| 9dc9608795 | |||
| e08d290469 | |||
| 80bb90c3ca | |||
| a3ddcab336 | |||
| a839769c23 | |||
| 1eb503b379 | |||
| cc5f8bd53f | |||
| bb512f7c1f | |||
| 5b5a73019d | |||
| ce0b9bb7ca | |||
| 38063e7d1b | |||
| ee5b9e137d | |||
| 55103810f0 | |||
| e5b111f26b | |||
| 7c2e2133cc | |||
| 3352ffcfa2 | |||
| 8e74bfa8e8 | |||
| 9f630b6cc4 | |||
| c2779c9f29 | |||
| 7fecbba80b | |||
| 80b81e5094 | |||
| 6e977fcdd6 | |||
| 9c8c5f2d01 | |||
| 9134f3f0df | |||
| b093752289 | |||
| bd87c3e225 | |||
| 7bea1ea240 | |||
| afd6e7d542 | |||
| e29eef4bde | |||
| 63dd180030 | |||
| 8eacbd5a32 | |||
| 680ff52414 | |||
| 884e310a3b | |||
| 7eac026a02 | |||
| deaddfb6b8 | |||
| 85b40b18d5 | |||
| 3b6987cea3 | |||
| 14ff3d59b3 | |||
| dd02a787d8 | |||
| cefe7c7f59 | |||
| d9fc73dc7a | |||
| 3bc1e345ca | |||
| 5d3fe21ab2 | |||
| 17db3e8af1 | |||
| a0da864ac2 | |||
| 0978aab839 | |||
| 7d947ad66c | |||
| 5e63c8e57e | |||
| 34bcea8159 | |||
| 2a56e3c8b9 | |||
| 1fb1c6d456 | |||
| 469e7dd82d | |||
| 1461f9d664 | |||
| 8791525d88 | |||
| a0f39f2b57 | |||
| 6fc2264a8a | |||
| 8893b111c2 | |||
| 3362673173 | |||
| 49703ecf1d | |||
| d56f3531b4 | |||
| 902a36137a | |||
| 19e4d5ada8 | |||
| d81917322f | |||
| b657f6db05 | |||
| abd980d36d | |||
| 7b27045680 | |||
| e4a56bd9dd | |||
| 5807b224d9 | |||
| 8b1596c257 | |||
| 2649eefe1c | |||
| b3bb3a4422 | |||
| 6e10f195c5 | |||
| ab7c329acf | |||
| 95d39aabc7 | |||
| 6e515be94f | |||
| b3b4f9a4a4 | |||
| c71d8267ed | |||
| 1742e76777 | |||
| 2797fcc75e | |||
| 2538e2dab1 | |||
| 6bf5eeed56 | |||
| c14d87daaa | |||
| cb201e866b | |||
| cc6a8bc792 | |||
| fa71841e9d | |||
| be7809f5fd | |||
| 655cdde2dc | |||
| 7f75f1507e | |||
| 3fbf089303 | |||
| 8a453265d2 | |||
| 807d45073a | |||
| 253bbbb668 | |||
| 8fbc1919df | |||
| c41ace2f7a | |||
| 3be351cabc | |||
| 53bd21e7d8 | |||
| 217530dfca | |||
| 30271d87aa | |||
| f271df32ec | |||
| 77ae35faba | |||
| 32d746479b | |||
| b18fd23232 | |||
| bbd644ea34 | |||
| c4bfba91c2 | |||
| 6e7a7aecf3 | |||
| 635493f6dd | |||
| 0f583e0c91 | |||
| 1a7ded8989 | |||
| 159e18c977 | |||
| 801dea3298 | |||
| d468b949f1 | |||
| a0881872c7 | |||
| a9e9cd31e1 | |||
| 0085d95576 | |||
| e4226ddc26 | |||
| 4c7169437b | |||
| b2cdd35a46 | |||
| aa0fad65e3 | |||
| 4c06cef684 | |||
| 6871df272d | |||
| 40a4427420 | |||
| f76b5133a5 | |||
| d5a7b7873e | |||
| ffa71ca45e | |||
| 5248eb8831 | |||
| 5468d02e60 | |||
| 251fd097bb | |||
| 3ac721e5a3 | |||
| ecd99dc88a | |||
| 3097fca71c | |||
| bc1c896692 | |||
| 6a927661f2 | |||
| 601d32ae66 | |||
| 2dde0b96da | |||
| d420bf952f | |||
| a02d7831b6 | |||
| 604db7d557 | |||
| 41ab96e7ff | |||
| 9dfb59fa28 | |||
| ad94e63238 | |||
| 82c0485aab | |||
| 4524454ff2 | |||
| 658bba713a | |||
| 238c388016 | |||
| 5e10e88673 | |||
| 7b6bad24ee | |||
| 11be1e8b2b | |||
| 42126ff6a5 | |||
| f12f99241c | |||
| 8fde6e8ef9 | |||
| 36bd6f3319 | |||
| 0f52f263ca | |||
| b9e1842e02 | |||
| 99261fdf05 | |||
| 07388eaded | |||
| d983601e46 | |||
| fd85f4eeb9 | |||
| c11ac48868 | |||
| 0d5c68bfd8 | |||
| a6b91c8407 | |||
| f6cac05e9c | |||
| 9a2938c57c | |||
| f4d6bab1b4 | |||
| ebfbd63b3c | |||
| 9ec7228b03 | |||
| 0a1f0c4b1f | |||
| 7180fb19c1 | |||
| ac2015f2ce | |||
| 6fc8187375 | |||
| 81e433d505 | |||
| 9fbdee633a | |||
| f1dee5ce23 | |||
| 1ffce0c735 | |||
| 3e307259ac | |||
| 8455124070 | |||
| a1d932bd82 | |||
| d9ef98fc80 | |||
| 4affd3c42e | |||
| 8771f49c0a | |||
| b018b44b49 | |||
| 3d4f5c6bf8 | |||
| 6bbdb16bb1 | |||
| 07783f9c20 | |||
| b19370bd35 | |||
| 9d18c714b8 | |||
| 474dd3da66 | |||
| 5095725a00 | |||
| 02da49597c | |||
| 5f86aa9d14 | |||
| ae916b5d6a | |||
| ea66859873 | |||
| 23f43bb4c4 | |||
| 108d281f6b | |||
| 4a0e272c5b | |||
| 647a688de3 | |||
| 3f9ea21ae3 | |||
| 34a46904c2 | |||
| d73b1f3e71 | |||
| 2c356d8ecd | |||
| 62c7d543f6 | |||
| 008cfb2a1f | |||
| 243f766222 | |||
| 2b9259ed7f | |||
| c5d9d36e79 | |||
| 296029fadf | |||
| 7e78f9c4a5 | |||
| 83bc3ccfdf | |||
| 6a001a3223 | |||
| 1974f5ade7 | |||
| 837e3741fd | |||
| 4bdb702918 | |||
| e588f20b6c | |||
| ad7d8edf0c | |||
| 9f4a69a8cd | |||
| fd4c7d7b69 | |||
| e77b4ac0de | |||
| 4fe4fbba9d | |||
| 331298218b | |||
| db52d4058d | |||
| b5d1353575 | |||
| fb3663ae5c | |||
| 6825f882e2 | |||
| 04b949a8f5 | |||
| 86976c5bd9 | |||
| 33238bb24b | |||
| 2b548c27ee | |||
| e0cd7e44db | |||
| 184cdf0d52 | |||
| 472896acdd | |||
| 1ff977a5e5 | |||
| 68a1c2a8d9 | |||
| db77228155 | |||
| 8a0dcb91cc | |||
| 11b5d9b763 | |||
| dc195425ee | |||
| 72cf8ec5eb | |||
| 1130c181f9 | |||
| 443d4dae06 | |||
| a2720952c2 | |||
| 89262fa9f1 | |||
| bc3c2a8eed | |||
| fb7e5c42cd | |||
| 2e2a229f58 | |||
| d12b20d022 | |||
| 5ce5bc6bdd | |||
| 54c9048405 | |||
| 7b04f1fa49 | |||
| eebd7f8964 | |||
| 871af2ebc5 | |||
| 0d4b11ff88 | |||
| e342149a37 | |||
| 9054cd2a25 | |||
| 7d5e56cffd | |||
| 137c0261ee | |||
| 1c500e2157 | |||
| 46021b98b2 | |||
| 55739cdfb6 | |||
| 63e5416f5b | |||
| 689a8f383c | |||
| 10f981a794 | |||
| 556a760d0c | |||
| 2ba0565d7d | |||
| 16d5729223 | |||
| 38ef7ab379 | |||
| 740cb942ce | |||
| 3725adf852 | |||
| b9c49aefb2 | |||
| 60f8e19ce1 | |||
| d0f43772fb | |||
| 106be68e82 | |||
| f12ad8521f | |||
| 9efa210e32 | |||
| 79b146cb5c | |||
| 8711ce1f4a | |||
| 417fa07162 | |||
| 1910d01a86 | |||
| c9c530fd6e | |||
| dadeff80c9 | |||
| cc41096ad5 | |||
| db9987c267 | |||
| 8d8a5e8035 | |||
| b60373f3e4 | |||
| 1d8bebfeaf | |||
| 41d178f9da | |||
| d144e53188 | |||
| 49b50ef5ab | |||
| 4fac06549a | |||
| 7141921ad4 | |||
| 70e78a4315 | |||
| 520592c43d | |||
| 553b1e6f6d | |||
| bb5652829f | |||
| 288a79ccd4 | |||
| 8f6d8a5653 | |||
| c64368bb1d | |||
| 177beaf23a | |||
| 147d7af758 | |||
| 20bd24b70d | |||
| 7c75924319 | |||
| d90846033b | |||
| da02a3c472 | |||
| 61609ec274 | |||
| 228fc821e0 | |||
| d44071ee09 | |||
| 91fae7e9b4 | |||
| 3e7b9158f4 | |||
| 95f9c8f716 | |||
| 170392d4a0 | |||
| 3724b3aa8d | |||
| 9af90f03bb | |||
| 64a2dfba1f | |||
| 043cf8bab7 | |||
| 832393cfc9 | |||
| d8e7fa9196 | |||
| 075e999c1a | |||
| 8efb66741f | |||
| fa348b5d46 | |||
| ac2eafee91 | |||
| e6c69d835d | |||
| 1468444f42 | |||
| 3a34659252 | |||
| bfa6c5080e | |||
| 0f0729b157 | |||
| f75d82450a | |||
| 9389ff572b | |||
| 3dd33e3862 | |||
| e3b98ac6b6 | |||
| 3951213860 | |||
| 24b81e0566 | |||
| 0ab271dcfd | |||
| b9cb39eaf6 | |||
| c83407f033 | |||
| da75ffce68 | |||
| ee9f6db7a2 | |||
| d46979ec3a | |||
| d48b1de9f7 | |||
| da6b4b9bf9 | |||
| 38d1c9a886 | |||
| 1c48d7e188 | |||
| 11b39253d2 | |||
| 56e84a7985 | |||
| 133f83d557 | |||
| 1d20cf37cb | |||
| 17e57aa07d | |||
| 710b364b44 | |||
| d277c441da | |||
| b993411de1 | |||
| 81d72831b8 | |||
| 3cfabf7190 | |||
| 0e5791a6cd | |||
| da3e5e0c5c | |||
| ae3b9e1e1f | |||
| 3485ecf225 | |||
| 83e8f495f2 | |||
| ba4e81d249 | |||
| c3af87ac64 |
+19
-20
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* This file is used to display a categories sub categories, external pages, and settings.
|
||||
*
|
||||
* @since 2.3
|
||||
* @since Moodle 2.3
|
||||
* @package admin
|
||||
* @copyright 2011 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -97,27 +97,26 @@ foreach ($settingspage->children as $childpage) {
|
||||
$outputhtml .= $OUTPUT->heading(html_writer::link($childpage->url, $childpage->visiblename), 3);
|
||||
} else if ($childpage instanceof admin_settingpage) {
|
||||
$outputhtml .= $OUTPUT->heading(html_writer::link(new moodle_url('/'.$CFG->admin.'/settings.php', array('section' => $childpage->name)), $childpage->visiblename), 3);
|
||||
// If its a settings page and has settings lets display them.
|
||||
if (!empty($childpage->settings)) {
|
||||
$outputhtml .= html_writer::start_tag('fieldset', array('class' => 'adminsettings'));
|
||||
foreach ($childpage->settings as $setting) {
|
||||
if (empty($setting->nosave)) {
|
||||
$savebutton = true;
|
||||
}
|
||||
$fullname = $setting->get_full_name();
|
||||
if (array_key_exists($fullname, $adminroot->errors)) {
|
||||
$data = $adminroot->errors[$fullname]->data;
|
||||
} else {
|
||||
$data = $setting->get_setting();
|
||||
}
|
||||
$outputhtml .= html_writer::tag('div', '<!-- -->', array('class' => 'clearer'));
|
||||
$outputhtml .= $setting->output_html($data);
|
||||
}
|
||||
$outputhtml .= html_writer::end_tag('fieldset');
|
||||
}
|
||||
} else if ($childpage instanceof admin_category) {
|
||||
$outputhtml .= $OUTPUT->heading(html_writer::link(new moodle_url('/'.$CFG->admin.'/category.php', array('category' => $childpage->name)), get_string('admincategory', 'admin', $childpage->visiblename)), 3);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (!empty($childpage->settings)) {
|
||||
$outputhtml .= html_writer::start_tag('fieldset', array('class' => 'adminsettings'));
|
||||
foreach ($childpage->settings as $setting) {
|
||||
if (empty($setting->nosave)) {
|
||||
$savebutton = true;
|
||||
}
|
||||
$fullname = $setting->get_full_name();
|
||||
if (array_key_exists($fullname, $adminroot->errors)) {
|
||||
$data = $adminroot->errors[$fullname]->data;
|
||||
} else {
|
||||
$data = $setting->get_setting();
|
||||
}
|
||||
$outputhtml .= html_writer::tag('div', '<!-- -->', array('class' => 'clearer'));
|
||||
$outputhtml .= $setting->output_html($data);
|
||||
}
|
||||
$outputhtml .= html_writer::end_tag('fieldset');
|
||||
}
|
||||
}
|
||||
if ($savebutton) {
|
||||
|
||||
@@ -201,17 +201,9 @@ if (defined('COMPONENT_CLASSLOADER')) {
|
||||
require($CFG->dirroot.'/version.php');
|
||||
$CFG->target_release = $release;
|
||||
|
||||
$_SESSION = array();
|
||||
$_SESSION['SESSION'] = new stdClass();
|
||||
$_SESSION['SESSION']->lang = $CFG->lang;
|
||||
$_SESSION['USER'] = new stdClass();
|
||||
$_SESSION['USER']->id = 0;
|
||||
$_SESSION['USER']->mnethostid = 1;
|
||||
|
||||
\core\session\manager::init_empty_session();
|
||||
global $SESSION;
|
||||
global $USER;
|
||||
$SESSION = &$_SESSION['SESSION'];
|
||||
$USER = &$_SESSION['USER'];
|
||||
|
||||
global $COURSE;
|
||||
$COURSE = new stdClass();
|
||||
|
||||
+5
-3
@@ -378,9 +378,6 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (!$confirmplugins) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
@@ -398,6 +395,9 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$deployer = \core\update\deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$deployer->initialize($PAGE->url, $PAGE->url);
|
||||
@@ -421,6 +421,8 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$reloadurl = new moodle_url('/admin/index.php', array('cache' => 0));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
die();
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
/**
|
||||
* This file contains functions used by the admin pages
|
||||
*
|
||||
* @since 2.1
|
||||
* @since Moodle 2.1
|
||||
* @package admin
|
||||
* @copyright 2011 Andrew Davis
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
+1
-1
@@ -1384,7 +1384,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
get_string('report'),
|
||||
get_string('status'),
|
||||
);
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign status', 'leftalign report', 'centeralign info');
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'centeralign status');
|
||||
$servertable->attributes['class'] = 'admintable environmenttable generaltable';
|
||||
$servertable->id = 'serverstatus';
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ if ($roleid) {
|
||||
// Show UI for assigning a particular role to users.
|
||||
// Print a warning if we are assigning system roles.
|
||||
if ($context->contextlevel == CONTEXT_SYSTEM) {
|
||||
echo $OUTPUT->box(get_string('globalroleswarning', 'core_role'));
|
||||
echo $OUTPUT->notification(get_string('globalroleswarning', 'core_role'));
|
||||
}
|
||||
|
||||
// Print the form.
|
||||
@@ -251,7 +251,7 @@ if ($roleid) {
|
||||
|
||||
// Print a warning if we are assigning system roles.
|
||||
if ($context->contextlevel == CONTEXT_SYSTEM) {
|
||||
echo $OUTPUT->box(get_string('globalroleswarning', 'core_role'));
|
||||
echo $OUTPUT->notification(get_string('globalroleswarning', 'core_role'));
|
||||
}
|
||||
|
||||
// Print instruction.
|
||||
|
||||
@@ -74,8 +74,16 @@ abstract class core_role_capability_table_base {
|
||||
public function display() {
|
||||
if (count($this->capabilities) > self::NUM_CAPS_FOR_SEARCH) {
|
||||
global $PAGE;
|
||||
$PAGE->requires->strings_for_js(array('filter', 'clear'), 'moodle');
|
||||
$PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, $this->context->id));
|
||||
$jsmodule = array(
|
||||
'name' => 'rolescapfilter',
|
||||
'fullpath' => '/admin/roles/module.js',
|
||||
'strings' => array(
|
||||
array('filter', 'moodle'),
|
||||
array('clear', 'moodle'), ),
|
||||
'requires' => array('node', 'cookie', 'escape')
|
||||
);
|
||||
$PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, $this->context->id), false,
|
||||
$jsmodule);
|
||||
}
|
||||
echo '<table class="' . implode(' ', $this->classes) . '" id="' . $this->id . '">' . "\n<thead>\n";
|
||||
echo '<tr><th class="name" align="left" scope="col">' . get_string('capability', 'core_role') . '</th>';
|
||||
|
||||
@@ -75,7 +75,8 @@ switch ($action) {
|
||||
$a->id = $roleid;
|
||||
$a->name = $roles[$roleid]->name;
|
||||
$a->shortname = $roles[$roleid]->shortname;
|
||||
$a->count = $DB->count_records('role_assignments', array('roleid'=>$roleid));
|
||||
$a->count = $DB->count_records_select('role_assignments',
|
||||
'roleid = ?', array($roleid), 'COUNT(DISTINCT userid)');
|
||||
|
||||
$formcontinue = new single_button(new moodle_url($baseurl, $optionsyes), get_string('yes'));
|
||||
$formcancel = new single_button(new moodle_url($baseurl), get_string('no'), 'get');
|
||||
|
||||
@@ -51,7 +51,7 @@ M.core_role.init_cap_table_filter = function(Y, tableid, contextid) {
|
||||
marginRight : 'auto'
|
||||
});
|
||||
// Create the capability search input.
|
||||
this.input = Y.Node.create('<input type="text" id="'+this.table.get('id')+'capabilitysearch" value="'+filtervalue+'" />');
|
||||
this.input = Y.Node.create('<input type="text" id="'+this.table.get('id')+'capabilitysearch" value="'+Y.Escape.html(filtervalue)+'" />');
|
||||
// Create a label for the search input.
|
||||
this.label = Y.Node.create('<label for="'+this.input.get('id')+'">'+M.str.moodle.filter+' </label>');
|
||||
// Create a clear button to clear the input.
|
||||
|
||||
@@ -139,7 +139,6 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
array(
|
||||
'context' => $context,
|
||||
'objectid' => $roleid,
|
||||
'courseid' => $courseid
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -80,7 +80,8 @@ class behat_admin extends behat_base {
|
||||
// Single element settings.
|
||||
try {
|
||||
$fieldxpath = "//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" .
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for]";
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for or " .
|
||||
"@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
|
||||
|
||||
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
|
||||
@@ -89,7 +90,7 @@ class behat_admin extends behat_base {
|
||||
} catch (ElementNotFoundException $e) {
|
||||
|
||||
// Multi element settings, interacting only the first one.
|
||||
$fieldxpath = "//descendant::label[.= $label]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
$fieldxpath = "//*[label[.= $label]|span[.= $label]]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
"/descendant::div[@class='form-group']/descendant::*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath);
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
@core @core_admin
|
||||
Feature: Set admin settings value
|
||||
In order to set admin settings value
|
||||
As an admin
|
||||
I need to set admin setting value and verify it is applied
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course fullname | C_shortname | 0 |
|
||||
And I log in as "admin"
|
||||
And I should see "Course fullname"
|
||||
And I should not see "C_shortname Course fullname"
|
||||
|
||||
Scenario: set admin value with full name
|
||||
Given I set the following administration settings values:
|
||||
| Display extended course names | 1 |
|
||||
When I press "Save changes"
|
||||
And I am on homepage
|
||||
Then I should see "C_shortname Course fullname"
|
||||
|
||||
Scenario: set admin value with short name
|
||||
Given I set the following administration settings values:
|
||||
| courselistshortnames | 1 |
|
||||
When I press "Save changes"
|
||||
And I am on homepage
|
||||
Then I should see "C_shortname Course fullname"
|
||||
@@ -27,6 +27,11 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php');
|
||||
require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
|
||||
|
||||
// This page usually takes an exceedingly long time to load, so we need to
|
||||
// increase the time limit. At present it takes about a minute on some
|
||||
// systems, but let's allow room for expansion.
|
||||
core_php_time_limit::raise(300);
|
||||
|
||||
$filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
|
||||
$type = optional_param('type', false, PARAM_ALPHAEXT);
|
||||
$component = optional_param('component', '', PARAM_ALPHAEXT);
|
||||
|
||||
@@ -45,5 +45,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,20 +28,20 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['acknowledgement'] = 'Acknowledgement';
|
||||
$string['acknowledgementmust'] = 'You must acknowledge this';
|
||||
$string['acknowledgementtext'] = 'I understand that it is my responsibility to have full backups of this site prior to installing add-ons. I accept and understand that add-ons (especially but not only those originating in unofficial sources) may contain security holes, can make the site unavailable, or cause private data leaks or loss.';
|
||||
$string['featuredisabled'] = 'The add-on installer is disabled on this site.';
|
||||
$string['installaddon'] = 'Install add-on!';
|
||||
$string['installaddons'] = 'Install add-ons';
|
||||
$string['installexception'] = 'Oops... An error occurred while trying to install the add-on. Turn debugging mode on to see details of the error.';
|
||||
$string['installfromrepo'] = 'Install add-ons from the Moodle plugins directory';
|
||||
$string['installfromrepo_help'] = 'You will be redirected to the Moodle plugins directory to search for and install an add-on. Note that your site full name, URL and Moodle version will be sent as well, to make the installation process easier for you.';
|
||||
$string['installfromzip'] = 'Install add-on from ZIP file';
|
||||
$string['installfromzip_help'] = 'An alternative to installing an add-on directly from the Moodle plugins directory is to upload a ZIP package of the add-on. The ZIP package should have the same structure as a package downloaded from the Moodle plugins directory.';
|
||||
$string['acknowledgementtext'] = 'I understand that it is my responsibility to have full backups of this site prior to installing additional plugins. I accept and understand that plugins (especially but not only those originating in unofficial sources) may contain security holes, can make the site unavailable, or cause private data leaks or loss.';
|
||||
$string['featuredisabled'] = 'The plugin installer is disabled on this site.';
|
||||
$string['installaddon'] = 'Install plugin!';
|
||||
$string['installaddons'] = 'Install plugins';
|
||||
$string['installexception'] = 'Oops... An error occurred while trying to install the plugin. Turn debugging mode on to see details of the error.';
|
||||
$string['installfromrepo'] = 'Install plugins from the Moodle plugins directory';
|
||||
$string['installfromrepo_help'] = 'You will be redirected to the Moodle plugins directory to search for and install a plugin. Note that your site full name, URL and Moodle version will be sent as well, to make the installation process easier for you.';
|
||||
$string['installfromzip'] = 'Install plugin from ZIP file';
|
||||
$string['installfromzip_help'] = 'An alternative to installing a plugin directly from the Moodle plugins directory is to upload a ZIP package of the plugin. The ZIP package should have the same structure as a package downloaded from the Moodle plugins directory.';
|
||||
$string['installfromzipfile'] = 'ZIP package';
|
||||
$string['installfromzipfile_help'] = 'The plugin ZIP package must contain just one directory, named to match the plugin. The ZIP will be extracted into an appropriate location for the plugin type. If the package has been downloaded from the Moodle plugins directory then it will have this structure.';
|
||||
$string['installfromziprootdir'] = 'Rename the root directory';
|
||||
$string['installfromziprootdir_help'] = 'Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. If so, the correct name may be entered here.';
|
||||
$string['installfromzipsubmit'] = 'Install add-on from the ZIP file';
|
||||
$string['installfromzipsubmit'] = 'Install plugin from the ZIP file';
|
||||
$string['installfromziptype'] = 'Plugin type';
|
||||
$string['installfromziptype_help'] = 'Choose the correct type of plugin you are about to install. Warning: The installation procedure can fail badly if an incorrect plugin type is specified.';
|
||||
$string['permcheck'] = 'Make sure the plugin type root location is writable by the web server process.';
|
||||
@@ -49,54 +49,54 @@ $string['permcheckerror'] = 'Error while checking for write permission';
|
||||
$string['permcheckprogress'] = 'Checking for write permission ...';
|
||||
$string['permcheckresultno'] = 'Plugin type location <em>{$a->path}</em> is not writable';
|
||||
$string['permcheckresultyes'] = 'Plugin type location <em>{$a->path}</em> is writable';
|
||||
$string['pluginname'] = 'Add-on installer';
|
||||
$string['remoterequestalreadyinstalled'] = 'There is a request to install add-on {$a->name} ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. However, this plugin is <strong>already installed</strong> on the site.';
|
||||
$string['remoterequestconfirm'] = 'There is a request to install add-on <strong>{$a->name}</strong> ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. If you continue, the add-on ZIP package will be downloaded for validation. Nothing will be installed yet.';
|
||||
$string['remoterequestinvalid'] = 'There is a request to install an add-on from the Moodle plugins directory on this site. Unfortunately the request is not valid and so the add-on cannot be installed.';
|
||||
$string['remoterequestpermcheck'] = 'There is a request to install add-on {$a->name} ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. However, the plugin type location <strong>{$a->typepath}</strong> is <strong>not writable</strong>. You need to give write access for the web server user to the plugin type location, then press the continue button to repeat the check.';
|
||||
$string['remoterequestpluginfoexception'] = 'Oops... An error occurred while trying to obtain information about the add-on {$a->name} ({$a->component}) version {$a->version}. The add-on cannot be installed. Turn debugging mode on to see details of the error.';
|
||||
$string['validation'] = 'Add-on package validation';
|
||||
$string['pluginname'] = 'Plugin installer';
|
||||
$string['remoterequestalreadyinstalled'] = 'There is a request to install plugin {$a->name} ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. However, this plugin is <strong>already installed</strong> on the site.';
|
||||
$string['remoterequestconfirm'] = 'There is a request to install plugin <strong>{$a->name}</strong> ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. If you continue, the plugin ZIP package will be downloaded for validation. Nothing will be installed yet.';
|
||||
$string['remoterequestinvalid'] = 'There is a request to install a plugin from the Moodle plugins directory on this site. Unfortunately the request is not valid and so the plugin cannot be installed.';
|
||||
$string['remoterequestpermcheck'] = 'There is a request to install plugin {$a->name} ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. However, the location <strong>{$a->typepath}</strong> is <strong>not writable</strong>. You need to give write access for the web server user to the location, then press the continue button to repeat the check.';
|
||||
$string['remoterequestpluginfoexception'] = 'Oops... An error occurred while trying to obtain information about the plugin {$a->name} ({$a->component}) version {$a->version}. The plugin cannot be installed. Turn debugging mode on to see details of the error.';
|
||||
$string['validation'] = 'Plugin package validation';
|
||||
$string['validationmsg_componentmatch'] = 'Full component name';
|
||||
$string['validationmsg_componentmismatchname'] = 'Add-on name mismatch';
|
||||
$string['validationmsg_componentmismatchname_help'] = 'Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. You need to fix the name of the root directory to match the declared add-on name.';
|
||||
$string['validationmsg_componentmismatchname_info'] = 'The add-on declares its name is \'{$a}\' but that does not match the name of the root directory.';
|
||||
$string['validationmsg_componentmismatchtype'] = 'Add-on type mismatch';
|
||||
$string['validationmsg_componentmismatchtype_info'] = 'You have selected the type \'{$a->expected}\' but the add-on declares its type is \'{$a->found}\'.';
|
||||
$string['validationmsg_componentmismatchname'] = 'Plugin name mismatch';
|
||||
$string['validationmsg_componentmismatchname_help'] = 'Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. You need to fix the name of the root directory to match the declared plugin name.';
|
||||
$string['validationmsg_componentmismatchname_info'] = 'The plugin declares its name is \'{$a}\' but that does not match the name of the root directory.';
|
||||
$string['validationmsg_componentmismatchtype'] = 'Plugin type mismatch';
|
||||
$string['validationmsg_componentmismatchtype_info'] = 'You have selected the type \'{$a->expected}\' but the plugin declares its type is \'{$a->found}\'.';
|
||||
$string['validationmsg_filenotexists'] = 'Extracted file not found';
|
||||
$string['validationmsg_filesnumber'] = 'Not enough files found in the package';
|
||||
$string['validationmsg_filestatus'] = 'Unable to extract all files';
|
||||
$string['validationmsg_filestatus_info'] = 'Attempting to extract file {$a->file} resulted in error \'{$a->status}\'.';
|
||||
$string['validationmsg_maturity'] = 'Declared maturity level';
|
||||
$string['validationmsg_maturity_help'] = 'The add-on can declare its maturity level. If the maintainer considers the add-on stable, the declared maturity level will read MATURITY_STABLE. All other maturity levels (such as alpha or beta) should be considered unstable and a warning is raised.';
|
||||
$string['validationmsg_maturity_help'] = 'The plugin can declare its maturity level. If the maintainer considers the plugin stable, the declared maturity level will read MATURITY_STABLE. All other maturity levels (such as alpha or beta) should be considered unstable and a warning is raised.';
|
||||
$string['validationmsg_missingexpectedlangenfile'] = 'English language file name mismatch';
|
||||
$string['validationmsg_missingexpectedlangenfile_info'] = 'The given add-on type is missing the expected English language file {$a}.';
|
||||
$string['validationmsg_missingexpectedlangenfile_info'] = 'The given plugin type is missing the expected English language file {$a}.';
|
||||
$string['validationmsg_missinglangenfile'] = 'No English language file found';
|
||||
$string['validationmsg_missinglangenfolder'] = 'Missing English language folder';
|
||||
$string['validationmsg_missingversion'] = 'Add-on does not declare its version';
|
||||
$string['validationmsg_missingversion'] = 'Plugin does not declare its version';
|
||||
$string['validationmsg_missingversionphp'] = 'File version.php not found';
|
||||
$string['validationmsg_multiplelangenfiles'] = 'Multiple English language files found';
|
||||
$string['validationmsg_onedir'] = 'Invalid structure of the ZIP package.';
|
||||
$string['validationmsg_onedir_help'] = 'The ZIP package must contain just one root directory that holds the add-on code. The name of that root directory must match the name of the plugin.';
|
||||
$string['validationmsg_onedir_help'] = 'The ZIP package must contain just one root directory that holds the plugin code. The name of that root directory must match the name of the plugin.';
|
||||
$string['validationmsg_pathwritable'] = 'Write access check';
|
||||
$string['validationmsg_pluginversion'] = 'Add-on version';
|
||||
$string['validationmsg_release'] = 'Add-on release';
|
||||
$string['validationmsg_pluginversion'] = 'Plugin version';
|
||||
$string['validationmsg_release'] = 'Plugin release';
|
||||
$string['validationmsg_requiresmoodle'] = 'Required Moodle version';
|
||||
$string['validationmsg_rootdir'] = 'Name of the add-on to be installed';
|
||||
$string['validationmsg_rootdir_help'] = 'The name of the root directory in the ZIP package forms the name of the add-on to be installed. If the name is not correct, you may wish to rename the root directory in the ZIP prior to installing the add-on.';
|
||||
$string['validationmsg_rootdirinvalid'] = 'Invalid add-on name';
|
||||
$string['validationmsg_rootdirinvalid_help'] = 'The name of the root directory in the ZIP package violates formal syntax requirements. Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. You need to fix the name of the root directory to match the add-on name.';
|
||||
$string['validationmsg_rootdir'] = 'Name of the plugin to be installed';
|
||||
$string['validationmsg_rootdir_help'] = 'The name of the root directory in the ZIP package forms the name of the plugin to be installed. If the name is not correct, you may wish to rename the root directory in the ZIP prior to installing the plugin.';
|
||||
$string['validationmsg_rootdirinvalid'] = 'Invalid plugin name';
|
||||
$string['validationmsg_rootdirinvalid_help'] = 'The name of the root directory in the ZIP package violates formal syntax requirements. Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. You need to fix the name of the root directory to match the plugin name.';
|
||||
$string['validationmsg_targetexists'] = 'Target location already exists';
|
||||
$string['validationmsg_targetexists_help'] = 'The directory that the add-on is to be installed to, must not exist yet.';
|
||||
$string['validationmsg_targetexists_help'] = 'The directory that the plugin is to be installed to must not yet exist.';
|
||||
$string['validationmsg_unknowntype'] = 'Unknown plugin type';
|
||||
$string['validationmsglevel_debug'] = 'Debug';
|
||||
$string['validationmsglevel_error'] = 'Error';
|
||||
$string['validationmsglevel_info'] = 'OK';
|
||||
$string['validationmsglevel_warning'] = 'Warning';
|
||||
$string['validationresult0'] = 'Validation failed!';
|
||||
$string['validationresult0_help'] = 'A serious problem was detected and so it is not safe to install the add-on. See the validation log messages for details.';
|
||||
$string['validationresult0_help'] = 'A serious problem was detected and so it is not safe to install the plugin. See the validation log messages for details.';
|
||||
$string['validationresult1'] = 'Validation passed!';
|
||||
$string['validationresult1_help'] = 'No serious problems were detected. You can continue with the add-on installation. See the validation log messages for more details and eventual warnings.';
|
||||
$string['validationresult1_help'] = 'The add-on package has been validated and no serious problems were detected.';
|
||||
$string['validationresult2_help'] = 'No serious problems were detected. You can continue with the plugin installation. See the validation log messages for more details and eventual warnings.';
|
||||
$string['validationresult1_help'] = 'The plugin package has been validated and no serious problems were detected.';
|
||||
$string['validationresultinfo'] = 'Info';
|
||||
$string['validationresultmsg'] = 'Message';
|
||||
$string['validationresultstatus'] = 'Status';
|
||||
|
||||
@@ -72,7 +72,7 @@ trait buffered_writer {
|
||||
$entry['other'] = serialize($entry['other']);
|
||||
$entry['origin'] = $PAGE->requestorigin;
|
||||
$entry['ip'] = $PAGE->requestip;
|
||||
$entry['realuserid'] = \core\session\manager::is_loggedinas() ? $_SESSION['USER']->realuser : null;
|
||||
$entry['realuserid'] = \core\session\manager::is_loggedinas() ? $GLOBALS['USER']->realuser : null;
|
||||
|
||||
$this->buffer[] = $entry;
|
||||
$this->count++;
|
||||
|
||||
@@ -43,5 +43,8 @@ function xmldb_tool_log_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2014040600, 'tool', 'log');
|
||||
}
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
$string['actlogshdr'] = 'Available log stores';
|
||||
$string['configlogplugins'] = 'Please enable all required plugins and arrange then in appropriate order.';
|
||||
$string['configlogplugins'] = 'Please enable all required plugins and arrange them in appropriate order.';
|
||||
$string['logging'] = 'Logging';
|
||||
$string['managelogging'] = 'Manage log stores';
|
||||
$string['reportssupported'] = 'Reports supported';
|
||||
|
||||
@@ -33,5 +33,8 @@ function xmldb_logstore_database_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2014041700, 'logstore', 'database');
|
||||
}
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -130,8 +130,7 @@ class logstore_database_store_testcase extends advanced_testcase {
|
||||
array('context' => context_module::instance($module2->cmid), 'other' => array('sample' => 6, 'xx' => 9)));
|
||||
$event2->trigger();
|
||||
|
||||
$_SESSION['SESSION'] = new \stdClass();
|
||||
$this->setUser(0);
|
||||
\core\session\manager::init_empty_session();
|
||||
$this->assertFalse(\core\session\manager::is_loggedinas());
|
||||
|
||||
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
|
||||
|
||||
@@ -185,6 +185,11 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
|
||||
// database so that it doesn't cause a DB error. Log a warning so that
|
||||
// developers can avoid doing things which are likely to cause this on a
|
||||
// routine basis.
|
||||
if (\core_text::strlen($action) > 40) {
|
||||
$action = \core_text::substr($action, 0, 37) . '...';
|
||||
debugging('Warning: logged very long action', DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
if (!empty($info) && \core_text::strlen($info) > 255) {
|
||||
$info = \core_text::substr($info, 0, 252) . '...';
|
||||
debugging('Warning: logged very long info', DEBUG_DEVELOPER);
|
||||
|
||||
@@ -111,5 +111,8 @@ function xmldb_logstore_standard_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2014041500, 'logstore', 'standard');
|
||||
}
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -95,8 +95,7 @@ class logstore_standard_store_testcase extends advanced_testcase {
|
||||
$event2->trigger();
|
||||
logstore_standard_restore::hack_executing(0);
|
||||
|
||||
$_SESSION['SESSION'] = new \stdClass();
|
||||
$this->setUser(0);
|
||||
\core\session\manager::init_empty_session();
|
||||
$this->assertFalse(\core\session\manager::is_loggedinas());
|
||||
|
||||
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
|
||||
|
||||
@@ -104,11 +104,11 @@ if ($mform && ($mform->is_cancelled() || !empty($CFG->preventscheduledtaskchange
|
||||
|
||||
} else {
|
||||
echo $OUTPUT->header();
|
||||
$error = optional_param('error', '', PARAM_RAW);
|
||||
$error = optional_param('error', '', PARAM_NOTAGS);
|
||||
if ($error) {
|
||||
echo $OUTPUT->notification($error, 'notifyerror');
|
||||
}
|
||||
$success = optional_param('success', '', PARAM_RAW);
|
||||
$success = optional_param('success', '', PARAM_NOTAGS);
|
||||
if ($success) {
|
||||
echo $OUTPUT->notification($success, 'notifysuccess');
|
||||
}
|
||||
|
||||
@@ -875,7 +875,6 @@ class tool_uploadcourse_course {
|
||||
$resetdata = new stdClass();
|
||||
$resetdata->id = $course->id;
|
||||
$resetdata->reset_start_date = time();
|
||||
$resetdata->reset_logs = true;
|
||||
$resetdata->reset_events = true;
|
||||
$resetdata->reset_notes = true;
|
||||
$resetdata->delete_blog_associations = true;
|
||||
|
||||
@@ -669,7 +669,7 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
|
||||
if ($doupdate or $existinguser->password !== $oldpw) {
|
||||
// We want only users that were really updated.
|
||||
user_update_user($existinguser, false);
|
||||
user_update_user($existinguser, false, false);
|
||||
|
||||
$upt->track('status', $struserupdated);
|
||||
$usersupdated++;
|
||||
@@ -687,6 +687,9 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger event.
|
||||
\core\event\user_updated::create_from_userid($existinguser->id)->trigger();
|
||||
|
||||
} else {
|
||||
// no user information changed
|
||||
$upt->track('status', $struseruptodate);
|
||||
@@ -800,7 +803,7 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
$upt->track('password', '-', 'normal', false);
|
||||
}
|
||||
|
||||
$user->id = user_create_user($user, false);
|
||||
$user->id = user_create_user($user, false, false);
|
||||
$upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$user->id)), s($user->username)), 'normal', false);
|
||||
|
||||
// pre-process custom profile menu fields data from csv file
|
||||
@@ -815,6 +818,9 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
set_user_preference('create_password', 1, $user);
|
||||
}
|
||||
|
||||
// Trigger event.
|
||||
\core\event\user_created::create_from_userid($user->id)->trigger();
|
||||
|
||||
$upt->track('status', $struseradded);
|
||||
$upt->track('id', $user->id, 'normal', false);
|
||||
$usersnew++;
|
||||
|
||||
+18
-3
@@ -167,12 +167,27 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
*
|
||||
*/
|
||||
function prelogout_hook() {
|
||||
global $CFG;
|
||||
global $CFG, $USER, $DB;
|
||||
|
||||
if (!empty($this->config->logoutcas)) {
|
||||
if (!empty($this->config->logoutcas) && $USER->auth == $this->authtype) {
|
||||
$backurl = $CFG->wwwroot;
|
||||
$this->connectCAS();
|
||||
phpCAS::logoutWithURL($backurl);
|
||||
// Note: Hack to stable versions to trigger the event before it redirect to CAS logout.
|
||||
$sid = session_id();
|
||||
$event = \core\event\user_loggedout::create(
|
||||
array(
|
||||
'userid' => $USER->id,
|
||||
'objectid' => $USER->id,
|
||||
'other' => array('sessionid' => $sid),
|
||||
)
|
||||
);
|
||||
if ($session = $DB->get_record('sessions', array('sid' => $sid))) {
|
||||
$event->add_record_snapshot('sessions', $session);
|
||||
}
|
||||
\core\session\manager::terminate_current();
|
||||
$event->trigger();
|
||||
|
||||
phpCAS::logoutWithRedirectService($backurl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,5 +52,8 @@ function xmldb_auth_cas_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -384,6 +384,10 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
if ($old_user = $DB->get_record('user', array('username'=>$username, 'deleted'=>0, 'suspended'=>1, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype))) {
|
||||
$DB->set_field('user', 'suspended', 0, array('id'=>$old_user->id));
|
||||
$trace->output(get_string('auth_dbreviveduser', 'auth_db', array('name'=>$username, 'id'=>$old_user->id)), 1);
|
||||
|
||||
// Trigger user_updated event.
|
||||
\core\event\user_updated::create_from_userid($old_user->id)->trigger();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -410,6 +414,10 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
}
|
||||
try {
|
||||
$id = $DB->insert_record ('user', $user); // it is truly a new user
|
||||
|
||||
// Trigger user_created event.
|
||||
\core\event\user_created::create_from_userid($id)->trigger();
|
||||
|
||||
$trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)), 1);
|
||||
} catch (moodle_exception $e) {
|
||||
$trace->output(get_string('auth_dbinsertusererror', 'auth_db', $user->username), 1);
|
||||
@@ -547,6 +555,9 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
}
|
||||
if ($updated) {
|
||||
$DB->set_field('user', 'timemodified', time(), array('id'=>$userid));
|
||||
|
||||
// Trigger user_updated event.
|
||||
\core\event\user_updated::create_from_userid($userid)->trigger();
|
||||
}
|
||||
return $DB->get_record('user', array('id'=>$userid, 'deleted'=>0));
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class auth_db_testcase extends advanced_testcase {
|
||||
/** @var string Original error log */
|
||||
protected $oldlog;
|
||||
|
||||
protected function init_auth_database() {
|
||||
public function init_auth_database() {
|
||||
global $DB, $CFG;
|
||||
require_once("$CFG->dirroot/auth/db/auth.php");
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Events tests.
|
||||
*
|
||||
* @package auth_db
|
||||
* @category test
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/auth/db/tests/db_test.php');
|
||||
|
||||
class auth_db_events_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the locations in the auth_db API that create a user trigger the user_created event.
|
||||
*/
|
||||
public function test_user_created() {
|
||||
global $DB;
|
||||
|
||||
$this->preventResetByRollback();
|
||||
|
||||
// Initialise the database.
|
||||
$authdbtestcase = new auth_db_testcase();
|
||||
$authdbtestcase->init_auth_database();
|
||||
|
||||
$auth = get_auth_plugin('db');
|
||||
$auth->db_init();
|
||||
|
||||
// Add a user to the auth_db_users table - we will then call sync_users to
|
||||
// deal with the record here. In this case it will create the user.
|
||||
$user = new stdClass();
|
||||
$user->name = 'mark';
|
||||
$user->pass = 'password123';
|
||||
$user->email = 'what@legend.com';
|
||||
$user->id = $DB->insert_record('auth_db_users', $user);
|
||||
|
||||
// Run sync_users and capture the user_created event.
|
||||
$sink = $this->redirectEvents();
|
||||
$trace = new null_progress_trace();
|
||||
$auth->sync_users($trace, false);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Check that there is only one event.
|
||||
$this->assertEquals(1, count($events));
|
||||
|
||||
// Get the event.
|
||||
$event = array_pop($events);
|
||||
|
||||
// Test that the user created event was triggered - no need to test the other
|
||||
// details of the event as that is done extensively in other unit tests.
|
||||
$this->assertInstanceOf('\core\event\user_created', $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the locations in the auth_db API that update a user trigger the user_updated event.
|
||||
*/
|
||||
public function test_user_updated() {
|
||||
global $CFG, $DB;
|
||||
|
||||
$this->preventResetByRollback();
|
||||
|
||||
// Initialise the database.
|
||||
$authdbtestcase = new auth_db_testcase();
|
||||
$authdbtestcase->init_auth_database();
|
||||
|
||||
$auth = get_auth_plugin('db');
|
||||
$auth->db_init();
|
||||
|
||||
// Add a suspended user.
|
||||
$user = array();
|
||||
$user['username'] = 'mark';
|
||||
$user['suspended'] = '1';
|
||||
$user['mnethostid'] = $CFG->mnet_localhost_id;
|
||||
$user['auth'] = 'db';
|
||||
$this->getDataGenerator()->create_user($user);
|
||||
|
||||
// Add a user to the auth_db_users table - we will then call sync_users to
|
||||
// deal with the record here. In this case it will un-suspend the user.
|
||||
$user = new stdClass();
|
||||
$user->name = 'mark';
|
||||
$user->pass = 'password123';
|
||||
$user->email = 'what@legend.com';
|
||||
$user->id = $DB->insert_record('auth_db_users', $user);
|
||||
|
||||
// Set the config to remove the suspension on the user.
|
||||
set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/db');
|
||||
$auth->config->removeuser = AUTH_REMOVEUSER_SUSPEND;
|
||||
|
||||
// Run sync_users and capture the user_updated event.
|
||||
$sink = $this->redirectEvents();
|
||||
$trace = new null_progress_trace();
|
||||
$auth->sync_users($trace, false);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Check that there is only one event.
|
||||
$this->assertEquals(1, count($events));
|
||||
|
||||
// Get the event.
|
||||
$event = array_pop($events);
|
||||
|
||||
// Test that the user updated event was triggered - no need to test the other
|
||||
// details of the event as that is done extensively in other unit tests.
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
|
||||
// Run sync_users and capture the user_updated event.
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->update_user_record('mark');
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Check that there is only one event.
|
||||
$this->assertEquals(1, count($events));
|
||||
|
||||
// Get the event.
|
||||
$event = array_pop($events);
|
||||
|
||||
// Test that the user updated event was triggered - no need to test the other
|
||||
// details of the event as that is done extensively in other unit tests.
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -94,11 +94,14 @@ class auth_plugin_email extends auth_plugin_base {
|
||||
$user->calendartype = $CFG->calendartype;
|
||||
}
|
||||
|
||||
$user->id = user_create_user($user, false);
|
||||
$user->id = user_create_user($user, false, false);
|
||||
|
||||
// Save any custom profile field information.
|
||||
profile_save_data($user);
|
||||
|
||||
// Trigger event.
|
||||
\core\event\user_created::create_from_userid($user->id)->trigger();
|
||||
|
||||
if (! send_confirmation_email($user)) {
|
||||
print_error('auth_emailnoemail','auth_email');
|
||||
}
|
||||
|
||||
+4
-2
@@ -551,7 +551,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
print_error('auth_ldap_create_error', 'auth_ldap');
|
||||
}
|
||||
|
||||
$user->id = user_create_user($user, false);
|
||||
$user->id = user_create_user($user, false, false);
|
||||
|
||||
// Save any custom profile field information
|
||||
profile_save_data($user);
|
||||
@@ -564,6 +564,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
$user = $DB->get_record('user', array('id'=>$user->id));
|
||||
|
||||
\core\event\user_created::create_from_userid($user->id)->trigger();
|
||||
|
||||
if (! send_confirmation_email($user)) {
|
||||
print_error('noemail', 'auth_ldap');
|
||||
}
|
||||
@@ -1027,7 +1029,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
}
|
||||
}
|
||||
user_update_user($newuser, false);
|
||||
user_update_user($newuser, false, false);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_auth_ldap_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -279,6 +279,143 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$this->assertEventLegacyLogData($expectedlog, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test logging in via LDAP calls a user_loggedin event.
|
||||
*/
|
||||
public function test_ldap_user_signup() {
|
||||
global $CFG, $DB;
|
||||
|
||||
// User to create.
|
||||
$user = array(
|
||||
'username' => 'usersignuptest1',
|
||||
'password' => 'Moodle2014!',
|
||||
'idnumber' => 'idsignuptest1',
|
||||
'firstname' => 'First Name User Test 1',
|
||||
'lastname' => 'Last Name User Test 1',
|
||||
'middlename' => 'Middle Name User Test 1',
|
||||
'lastnamephonetic' => '最後のお名前のテスト一号',
|
||||
'firstnamephonetic' => 'お名前のテスト一号',
|
||||
'alternatename' => 'Alternate Name User Test 1',
|
||||
'email' => 'usersignuptest1@email.com',
|
||||
'description' => 'This is a description for user 1',
|
||||
'city' => 'Perth',
|
||||
'country' => 'au',
|
||||
'mnethostid' => $CFG->mnet_localhost_id,
|
||||
'auth' => 'ldap'
|
||||
);
|
||||
|
||||
if (!extension_loaded('ldap')) {
|
||||
$this->markTestSkipped('LDAP extension is not loaded.');
|
||||
}
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
require_once($CFG->dirroot.'/auth/ldap/auth.php');
|
||||
require_once($CFG->libdir.'/ldaplib.php');
|
||||
|
||||
if (!defined('TEST_AUTH_LDAP_HOST_URL') or !defined('TEST_AUTH_LDAP_BIND_DN') or !defined('TEST_AUTH_LDAP_BIND_PW') or !defined('TEST_AUTH_LDAP_DOMAIN')) {
|
||||
$this->markTestSkipped('External LDAP test server not configured.');
|
||||
}
|
||||
|
||||
// Make sure we can connect the server.
|
||||
$debuginfo = '';
|
||||
if (!$connection = ldap_connect_moodle(TEST_AUTH_LDAP_HOST_URL, 3, 'rfc2307', TEST_AUTH_LDAP_BIND_DN, TEST_AUTH_LDAP_BIND_PW, LDAP_DEREF_NEVER, $debuginfo, false)) {
|
||||
$this->markTestSkipped('Can not connect to LDAP test server: '.$debuginfo);
|
||||
}
|
||||
|
||||
$this->enable_plugin();
|
||||
|
||||
// Create new empty test container.
|
||||
$topdn = 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN;
|
||||
|
||||
$this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
|
||||
|
||||
$o = array();
|
||||
$o['objectClass'] = array('dcObject', 'organizationalUnit');
|
||||
$o['dc'] = 'moodletest';
|
||||
$o['ou'] = 'MOODLETEST';
|
||||
if (!ldap_add($connection, 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN, $o)) {
|
||||
$this->markTestSkipped('Can not create test LDAP container.');
|
||||
}
|
||||
|
||||
// Create a few users.
|
||||
$o = array();
|
||||
$o['objectClass'] = array('organizationalUnit');
|
||||
$o['ou'] = 'users';
|
||||
ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
|
||||
|
||||
// Configure the plugin a bit.
|
||||
set_config('host_url', TEST_AUTH_LDAP_HOST_URL, 'auth/ldap');
|
||||
set_config('start_tls', 0, 'auth/ldap');
|
||||
set_config('ldap_version', 3, 'auth/ldap');
|
||||
set_config('ldapencoding', 'utf-8', 'auth/ldap');
|
||||
set_config('pagesize', '2', 'auth/ldap');
|
||||
set_config('bind_dn', TEST_AUTH_LDAP_BIND_DN, 'auth/ldap');
|
||||
set_config('bind_pw', TEST_AUTH_LDAP_BIND_PW, 'auth/ldap');
|
||||
set_config('user_type', 'rfc2307', 'auth/ldap');
|
||||
set_config('contexts', 'ou=users,'.$topdn, 'auth/ldap');
|
||||
set_config('search_sub', 0, 'auth/ldap');
|
||||
set_config('opt_deref', LDAP_DEREF_NEVER, 'auth/ldap');
|
||||
set_config('user_attribute', 'cn', 'auth/ldap');
|
||||
set_config('memberattribute', 'memberuid', 'auth/ldap');
|
||||
set_config('memberattribute_isdn', 0, 'auth/ldap');
|
||||
set_config('creators', 'cn=creators,'.$topdn, 'auth/ldap');
|
||||
set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth/ldap');
|
||||
|
||||
set_config('field_map_email', 'mail', 'auth/ldap');
|
||||
set_config('field_updatelocal_email', 'oncreate', 'auth/ldap');
|
||||
set_config('field_updateremote_email', '0', 'auth/ldap');
|
||||
set_config('field_lock_email', 'unlocked', 'auth/ldap');
|
||||
|
||||
set_config('field_map_firstname', 'givenName', 'auth/ldap');
|
||||
set_config('field_updatelocal_firstname', 'oncreate', 'auth/ldap');
|
||||
set_config('field_updateremote_firstname', '0', 'auth/ldap');
|
||||
set_config('field_lock_firstname', 'unlocked', 'auth/ldap');
|
||||
|
||||
set_config('field_map_lastname', 'sn', 'auth/ldap');
|
||||
set_config('field_updatelocal_lastname', 'oncreate', 'auth/ldap');
|
||||
set_config('field_updateremote_lastname', '0', 'auth/ldap');
|
||||
set_config('field_lock_lastname', 'unlocked', 'auth/ldap');
|
||||
set_config('passtype', 'md5', 'auth/ldap');
|
||||
set_config('create_context', 'ou=users,'.$topdn, 'auth/ldap');
|
||||
|
||||
$this->assertEquals(2, $DB->count_records('user'));
|
||||
$this->assertEquals(0, $DB->count_records('role_assignments'));
|
||||
|
||||
/** @var auth_plugin_ldap $auth */
|
||||
$auth = get_auth_plugin('ldap');
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->user_signup((object)$user, false);
|
||||
$this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting');
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Verify 2 events get generated.
|
||||
$this->assertCount(2, $events);
|
||||
|
||||
// Get record from db.
|
||||
$dbuser = $DB->get_record('user', array('username' => $user['username']));
|
||||
$user['id'] = $dbuser->id;
|
||||
|
||||
// Last event is user_created.
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\user_created', $event);
|
||||
$this->assertEquals($user['id'], $event->objectid);
|
||||
$this->assertEquals('user_created', $event->get_legacy_eventname());
|
||||
$this->assertEquals(context_user::instance($user['id']), $event->get_context());
|
||||
$expectedlogdata = array(SITEID, 'user', 'add', '/view.php?id='.$event->objectid, fullname($dbuser));
|
||||
$this->assertEventLegacyLogData($expectedlogdata, $event);
|
||||
|
||||
// First event is user_password_updated.
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\user_password_updated', $event);
|
||||
$this->assertEventContextNotUsed($event);
|
||||
|
||||
// Delete user which we just created.
|
||||
ldap_delete($connection, 'cn='.$user['username'].',ou=users,'.$topdn);
|
||||
}
|
||||
|
||||
protected function create_ldap_user($connection, $topdn, $i) {
|
||||
$o = array();
|
||||
$o['objectClass'] = array('inetOrgPerson', 'organizationalPerson', 'person', 'posixAccount');
|
||||
|
||||
@@ -47,5 +47,8 @@ function xmldb_auth_manual_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* This file contains the mnet services for the mnet authentication plugin
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package auth_mnet
|
||||
* @copyright 2010 Penny Leach
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -47,5 +47,8 @@ function xmldb_auth_mnet_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -40,9 +40,13 @@
|
||||
if (!empty($_SERVER[$pluginconfig->user_attribute])) { // Shibboleth auto-login
|
||||
$frm = new stdClass();
|
||||
$frm->username = strtolower($_SERVER[$pluginconfig->user_attribute]);
|
||||
$frm->password = substr(base64_encode($_SERVER[$pluginconfig->user_attribute]),0,8);
|
||||
// The random password consists of the first 8 letters of the base 64 encoded user ID
|
||||
// This password is never used unless the user account is converted to manual
|
||||
// The password is never actually used, but needs to be passed to the functions 'user_login' and
|
||||
// 'authenticate_user_login'. Shibboleth returns true for the function 'prevent_local_password', which is
|
||||
// used when setting the password in 'update_internal_user_password'. When 'prevent_local_password'
|
||||
// returns true, the password is set to 'not cached' (AUTH_PASSWORD_NOT_CACHED) in the Moodle DB. However,
|
||||
// rather than setting the password to a hard-coded value, we will generate one each time, in case there are
|
||||
// changes to the Shibboleth plugin and it is actually used.
|
||||
$frm->password = generate_password(8);
|
||||
|
||||
/// Check if the user has actually submitted login data to us
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ abstract class condition extends tree_node {
|
||||
*
|
||||
* Default implementation returns false.
|
||||
*
|
||||
* @param stdClass $course Moodle course object
|
||||
* @param \stdClass $course Moodle course object
|
||||
* @param int $cmid ID of activity whose completion value is considered
|
||||
* @return boolean True if the availability of something else may rely on it
|
||||
*/
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract class frontend {
|
||||
*
|
||||
* Default returns true.
|
||||
*
|
||||
* @param stdClass $course Course object
|
||||
* @param \stdClass $course Course object
|
||||
* @param \cm_info $cm Course-module currently being edited (null if none)
|
||||
* @param \section_info $section Section currently being edited (null if none)
|
||||
*/
|
||||
@@ -73,7 +73,7 @@ abstract class frontend {
|
||||
*
|
||||
* Default returns no parameters.
|
||||
*
|
||||
* @param stdClass $course Course object
|
||||
* @param \stdClass $course Course object
|
||||
* @param \cm_info $cm Course-module currently being edited (null if none)
|
||||
* @param \section_info $section Section currently being edited (null if none)
|
||||
* @return array Array of parameters for the JavaScript function
|
||||
@@ -95,7 +95,7 @@ abstract class frontend {
|
||||
/**
|
||||
* Includes JavaScript for the main system and all plugins.
|
||||
*
|
||||
* @param stdClass $course Course object
|
||||
* @param \stdClass $course Course object
|
||||
* @param \cm_info $cm Course-module currently being edited (null if none)
|
||||
* @param \section_info $section Section currently being edited (null if none)
|
||||
*/
|
||||
|
||||
@@ -34,7 +34,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class info {
|
||||
/** @var stdClass Course */
|
||||
/** @var \stdClass Course */
|
||||
protected $course;
|
||||
|
||||
/** @var \course_modinfo Modinfo (available only during some functions) */
|
||||
@@ -52,10 +52,10 @@ abstract class info {
|
||||
/**
|
||||
* Constructs with item details.
|
||||
*
|
||||
* @param stdClass $course Course object
|
||||
* @param \stdClass $course Course object
|
||||
* @param int $visible Value of visible flag (eye icon)
|
||||
* @param string $availability Availability definition (JSON format) or null
|
||||
* @throws coding_exception If data is not valid JSON format
|
||||
* @throws \coding_exception If data is not valid JSON format
|
||||
*/
|
||||
public function __construct($course, $visible, $availability) {
|
||||
// Set basic values.
|
||||
@@ -67,7 +67,7 @@ abstract class info {
|
||||
/**
|
||||
* Obtains the course associated with this availability information.
|
||||
*
|
||||
* @return stdClass Moodle course object
|
||||
* @return \stdClass Moodle course object
|
||||
*/
|
||||
public function get_course() {
|
||||
return $this->course;
|
||||
@@ -128,7 +128,7 @@ abstract class info {
|
||||
* @param string $availability Availability string in JSON format
|
||||
* @param boolean $lax If true, throw exceptions only for invalid structure
|
||||
* @return tree Availability tree
|
||||
* @throws coding_exception If data is not valid JSON format
|
||||
* @throws \coding_exception If data is not valid JSON format
|
||||
*/
|
||||
protected function decode_availability($availability, $lax) {
|
||||
// Decode JSON data.
|
||||
@@ -306,7 +306,7 @@ abstract class info {
|
||||
*
|
||||
* @param string $restoreid Restore identifier
|
||||
* @param int $courseid Target course id
|
||||
* @param base_logger $logger Logger for any warnings
|
||||
* @param \base_logger $logger Logger for any warnings
|
||||
*/
|
||||
public function update_after_restore($restoreid, $courseid, \base_logger $logger) {
|
||||
$tree = $this->get_availability_tree();
|
||||
@@ -342,7 +342,7 @@ abstract class info {
|
||||
* function does that for the conditional availability data for all
|
||||
* modules and sections on the course.
|
||||
*
|
||||
* @param int|stdClass $courseorid Course id or object
|
||||
* @param int|\stdClass $courseorid Course id or object
|
||||
* @param string $table Table name e.g. 'course_modules'
|
||||
* @param int $oldid Previous ID
|
||||
* @param int $newid New ID
|
||||
@@ -407,7 +407,7 @@ abstract class info {
|
||||
* groupmembersonly field for modules. This is off by default because
|
||||
* we are not yet moving the groupmembersonly option into this new API.
|
||||
*
|
||||
* @param stdClass $rec Object possibly containing legacy fields
|
||||
* @param \stdClass $rec Object possibly containing legacy fields
|
||||
* @param bool $section True if this is a section
|
||||
* @param bool $modgroupmembersonly True if groupmembersonly is converted for mods
|
||||
* @return string|null New availability value or null if none
|
||||
@@ -468,7 +468,7 @@ abstract class info {
|
||||
* that it has an AND tree with one or more conditions.
|
||||
*
|
||||
* @param string|null $availability Current availability conditions
|
||||
* @param stdClass $rec Object containing information from old table
|
||||
* @param \stdClass $rec Object containing information from old table
|
||||
* @param bool $show True if 'show' option should be enabled
|
||||
* @return string New availability conditions
|
||||
*/
|
||||
@@ -501,7 +501,7 @@ abstract class info {
|
||||
* that it has an AND tree with one or more conditions.
|
||||
*
|
||||
* @param string|null $availability Current availability conditions
|
||||
* @param stdClass $rec Object containing information from old table
|
||||
* @param \stdClass $rec Object containing information from old table
|
||||
* @param bool $show True if 'show' option should be enabled
|
||||
* @return string New availability conditions
|
||||
*/
|
||||
@@ -598,8 +598,8 @@ abstract class info {
|
||||
* object.
|
||||
*
|
||||
* @param string $info Info string
|
||||
* @param int|stdClass $courseorid
|
||||
* @return Correctly formatted info string
|
||||
* @param int|\stdClass $courseorid
|
||||
* @return string Correctly formatted info string
|
||||
*/
|
||||
public static function format_info($info, $courseorid) {
|
||||
// Don't waste time if there are no special tags.
|
||||
@@ -624,7 +624,7 @@ abstract class info {
|
||||
* JS (using the non-JS version instead, which causes a page reload) if a
|
||||
* completion tickbox value may affect a conditional activity.
|
||||
*
|
||||
* @param stdClass $course Moodle course object
|
||||
* @param \stdClass $course Moodle course object
|
||||
* @param int $cmid Course-module id
|
||||
* @return bool True if this is used in a condition, false otherwise
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,7 @@ class info_module extends info {
|
||||
/**
|
||||
* Gets the course-module object. Intended for use by conditions.
|
||||
*
|
||||
* @return cm_info Course module
|
||||
* @return \cm_info Course module
|
||||
*/
|
||||
public function get_course_module() {
|
||||
return $this->cm;
|
||||
@@ -130,11 +130,11 @@ class info_module extends info {
|
||||
* disabled, and you supply a $cm object with necessary fields, and you
|
||||
* don't check course access.
|
||||
*
|
||||
* @param int|stdClass|cm_info $cmorid Object or id representing activity
|
||||
* @param int|\stdClass|\cm_info $cmorid Object or id representing activity
|
||||
* @param int $userid User id (0 = current user)
|
||||
* @param bool $checkcourse If true, checks whether the user has course access
|
||||
* @return bool True if the activity is visible to the specified user
|
||||
* @throws moodle_exception If the cmid doesn't exist
|
||||
* @throws \moodle_exception If the cmid doesn't exist
|
||||
*/
|
||||
public static function is_user_visible($cmorid, $userid = 0, $checkcourse = true) {
|
||||
global $USER, $DB, $CFG;
|
||||
|
||||
@@ -65,7 +65,7 @@ class info_section extends info {
|
||||
/**
|
||||
* Gets the section object. Intended for use by conditions.
|
||||
*
|
||||
* @return section_info Section
|
||||
* @return \section_info Section
|
||||
*/
|
||||
public function get_section() {
|
||||
return $this->section;
|
||||
|
||||
@@ -128,11 +128,11 @@ class tree extends tree_node {
|
||||
* coding_exception (if $lax is false).
|
||||
*
|
||||
* @see decode_availability
|
||||
* @param stdClass $structure Structure (decoded from JSON)
|
||||
* @param \stdClass $structure Structure (decoded from JSON)
|
||||
* @param boolean $lax If true, throw exceptions only for invalid structure
|
||||
* @param boolean $root If true, this is the root tree
|
||||
* @return tree Availability tree
|
||||
* @throws coding_exception If data is not valid structure
|
||||
* @throws \coding_exception If data is not valid structure
|
||||
*/
|
||||
public function __construct($structure, $lax = false, $root = true) {
|
||||
$this->root = $root;
|
||||
@@ -389,12 +389,12 @@ class tree extends tree_node {
|
||||
* for display to staff.
|
||||
*
|
||||
* @param info $info Information about location of condition tree
|
||||
* @throws coding_exception If you call on a non-root tree
|
||||
* @throws \coding_exception If you call on a non-root tree
|
||||
* @return string HTML data (empty string if none)
|
||||
*/
|
||||
public function get_full_information(info $info) {
|
||||
if (!$this->root) {
|
||||
throw new coding_exception('Only supported on root item');
|
||||
throw new \coding_exception('Only supported on root item');
|
||||
}
|
||||
return $this->get_full_information_recursive(false, $info, null, true);
|
||||
}
|
||||
@@ -406,12 +406,12 @@ class tree extends tree_node {
|
||||
*
|
||||
* @param info $info Information about location of condition tree
|
||||
* @param result $result Result object
|
||||
* @throws coding_exception If you call on a non-root tree
|
||||
* @throws \coding_exception If you call on a non-root tree
|
||||
* @return string HTML data (empty string if none)
|
||||
*/
|
||||
public function get_result_information(info $info, result $result) {
|
||||
if (!$this->root) {
|
||||
throw new coding_exception('Only supported on root item');
|
||||
throw new \coding_exception('Only supported on root item');
|
||||
}
|
||||
return $this->get_full_information_recursive(false, $info, $result, true);
|
||||
}
|
||||
@@ -530,7 +530,7 @@ class tree extends tree_node {
|
||||
$negative = true;
|
||||
break;
|
||||
default:
|
||||
throw new coding_exception('Unknown operator');
|
||||
throw new \coding_exception('Unknown operator');
|
||||
}
|
||||
switch($this->op) {
|
||||
case self::OP_AND:
|
||||
@@ -542,7 +542,7 @@ class tree extends tree_node {
|
||||
$andoperator = false;
|
||||
break;
|
||||
default:
|
||||
throw new coding_exception('Unknown operator');
|
||||
throw new \coding_exception('Unknown operator');
|
||||
}
|
||||
|
||||
// Select NOT (or not) for children. It flips if this is a 'not' group.
|
||||
|
||||
@@ -78,7 +78,7 @@ abstract class tree_node {
|
||||
/**
|
||||
* Saves tree data back to a structure object.
|
||||
*
|
||||
* @return stdClass Structure object (ready to be made into JSON format)
|
||||
* @return \stdClass Structure object (ready to be made into JSON format)
|
||||
*/
|
||||
public abstract function save();
|
||||
|
||||
@@ -152,11 +152,11 @@ abstract class tree_node {
|
||||
* @param \core_availability\info $info Item we're checking
|
||||
* @param capability_checker $checker
|
||||
* @return array Filtered version of input array
|
||||
* @throws coding_exception If called on a condition that doesn't apply to user lists
|
||||
* @throws \coding_exception If called on a condition that doesn't apply to user lists
|
||||
*/
|
||||
public function filter_user_list(array $users, $not,
|
||||
\core_availability\info $info, capability_checker $checker) {
|
||||
throw new coding_exception('Not implemented (do not call unless '.
|
||||
throw new \coding_exception('Not implemented (do not call unless '.
|
||||
'is_applied_to_user_lists is true)');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ class condition extends \core_availability\condition {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $structure Data structure from JSON decode
|
||||
* @throws coding_exception If invalid data structure.
|
||||
* @param \stdClass $structure Data structure from JSON decode
|
||||
* @throws \coding_exception If invalid data structure.
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get cmid.
|
||||
@@ -212,7 +212,7 @@ class condition extends \core_availability\condition {
|
||||
* Used in course/lib.php because we need to disable the completion JS if
|
||||
* a completion value affects a conditional activity.
|
||||
*
|
||||
* @param stdClass $course Moodle course object
|
||||
* @param \stdClass $course Moodle course object
|
||||
* @param int $cmid Course-module id
|
||||
* @return bool True if this is used in a condition, false otherwise
|
||||
*/
|
||||
|
||||
@@ -52,8 +52,8 @@ class condition extends \core_availability\condition {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $structure Data structure from JSON decode
|
||||
* @throws coding_exception If invalid data structure.
|
||||
* @param \stdClass $structure Data structure from JSON decode
|
||||
* @throws \coding_exception If invalid data structure.
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get direction.
|
||||
|
||||
@@ -74,7 +74,7 @@ class frontend extends \core_availability\frontend {
|
||||
* Given a timestamp, obtains corresponding field values.
|
||||
*
|
||||
* @param int $time Timestamp
|
||||
* @return stdClass Object with fields for year, month, day, hour, minute
|
||||
* @return \stdClass Object with fields for year, month, day, hour, minute
|
||||
*/
|
||||
public static function get_fields_from_time($time) {
|
||||
$calendartype = \core_calendar\type_factory::get_calendar_instance();
|
||||
|
||||
@@ -46,8 +46,8 @@ class condition extends \core_availability\condition {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $structure Data structure from JSON decode
|
||||
* @throws coding_exception If invalid data structure.
|
||||
* @param \stdClass $structure Data structure from JSON decode
|
||||
* @throws \coding_exception If invalid data structure.
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get grade item id.
|
||||
|
||||
@@ -43,8 +43,8 @@ class condition extends \core_availability\condition {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $structure Data structure from JSON decode
|
||||
* @throws coding_exception If invalid data structure.
|
||||
* @param \stdClass $structure Data structure from JSON decode
|
||||
* @throws \coding_exception If invalid data structure.
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get group id.
|
||||
|
||||
@@ -46,8 +46,8 @@ class condition extends \core_availability\condition {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $structure Data structure from JSON decode
|
||||
* @throws coding_exception If invalid data structure.
|
||||
* @param \stdClass $structure Data structure from JSON decode
|
||||
* @throws \coding_exception If invalid data structure.
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get grouping id.
|
||||
|
||||
@@ -73,8 +73,8 @@ class condition extends \core_availability\condition {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $structure Data structure from JSON decode
|
||||
* @throws coding_exception If invalid data structure.
|
||||
* @param \stdClass $structure Data structure from JSON decode
|
||||
* @throws \coding_exception If invalid data structure.
|
||||
*/
|
||||
public function __construct($structure) {
|
||||
// Get operator.
|
||||
@@ -292,14 +292,23 @@ class condition extends \core_availability\condition {
|
||||
* Gets data about custom profile fields. Cached statically in current
|
||||
* request.
|
||||
*
|
||||
* This only includes fields which can be tested by the system (those whose
|
||||
* data is cached in $USER object) - basically doesn't include textarea type
|
||||
* fields.
|
||||
*
|
||||
* @return array Array of records indexed by shortname
|
||||
*/
|
||||
public static function get_custom_profile_fields() {
|
||||
global $DB;
|
||||
global $DB, $CFG;
|
||||
|
||||
if (self::$customprofilefields === null) {
|
||||
self::$customprofilefields = $DB->get_records('user_info_field', null,
|
||||
'id ASC', 'shortname, id, name, defaultdata');
|
||||
// Get fields and store them indexed by shortname.
|
||||
require_once($CFG->dirroot . '/user/profile/lib.php');
|
||||
$fields = profile_get_custom_fields(true);
|
||||
self::$customprofilefields = array();
|
||||
foreach ($fields as $field) {
|
||||
self::$customprofilefields[$field->shortname] = $field;
|
||||
}
|
||||
}
|
||||
return self::$customprofilefields;
|
||||
}
|
||||
|
||||
@@ -64,3 +64,52 @@ Feature: availability_profile
|
||||
# I see P1 but not P2.
|
||||
Then I should see "P1" in the "region-main" "region"
|
||||
And I should not see "P2" in the "region-main" "region"
|
||||
|
||||
@javascript
|
||||
Scenario: Test with custom user profile field
|
||||
# Add custom field.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "User profile fields" node in "Site administration > Users > Accounts"
|
||||
And I set the field "datatype" to "Text input"
|
||||
And I set the following fields to these values:
|
||||
| Short name | superfield |
|
||||
| Name | Super field |
|
||||
And I click on "Save changes" "button"
|
||||
|
||||
# Set field value for user.
|
||||
And I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
|
||||
And I click on "a[title=Edit]" "css_element" in the "s@example.org" "table_row"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Super field" to "Bananaman"
|
||||
And I click on "Update profile" "button"
|
||||
|
||||
# Set Page activity which has requirement on this field.
|
||||
And I am on homepage
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Page" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | P1 |
|
||||
| Description | x |
|
||||
| Page content | x |
|
||||
And I expand all fieldsets
|
||||
And I click on "Add restriction..." "button"
|
||||
And I click on "User profile" "button"
|
||||
And I set the following fields to these values:
|
||||
| User profile field | Super field |
|
||||
| Value to compare against | Bananaman |
|
||||
And I click on ".availability-item .availability-eye img" "css_element"
|
||||
And I click on "Save and return to course" "button"
|
||||
|
||||
# Edit it again and check the setting still works.
|
||||
When I follow "P1"
|
||||
And I navigate to "Edit settings" node in "Page module administration"
|
||||
And I expand all fieldsets
|
||||
Then the field "User profile field" matches value "Super field"
|
||||
And the field "Value to compare against" matches value "Bananaman"
|
||||
|
||||
# Log out and back in as student. Should be able to see activity.
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "P1" in the "region-main" "region"
|
||||
|
||||
@@ -317,6 +317,29 @@ class availability_profile_condition_testcase extends advanced_testcase {
|
||||
$this->assertTrue($cond->is_available(false, $info, true, $user->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests what happens with custom fields that are text areas. These should
|
||||
* not be offered in the menu because their data is not included in user
|
||||
* object
|
||||
*/
|
||||
public function test_custom_textarea_field() {
|
||||
global $USER, $SITE, $DB;
|
||||
$this->setAdminUser();
|
||||
$info = new \core_availability\mock_info();
|
||||
|
||||
// Add custom textarea type.
|
||||
$DB->insert_record('user_info_field', array(
|
||||
'shortname' => 'longtext', 'name' => 'Long text', 'categoryid' => 1,
|
||||
'datatype' => 'textarea'));
|
||||
$customfield = $DB->get_record('user_info_field',
|
||||
array('shortname' => 'longtext'));
|
||||
|
||||
// The list of fields should include the text field added in setUp(),
|
||||
// but should not include the textarea field added just now.
|
||||
$fields = condition::get_custom_profile_fields();
|
||||
$this->assertEquals(array('frogtype'), array_keys($fields));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom profile field used for testing.
|
||||
*
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ M.availability_profile.form.getNode = function(json) {
|
||||
node.one('select[name=field] > option[value=sf_' + json.sf + ']')) {
|
||||
node.one('select[name=field]').set('value', 'sf_' + json.sf);
|
||||
} else if (json.cf !== undefined &&
|
||||
node.one('select[name=field] > option[value=cf_' + json.sf + ']')) {
|
||||
node.one('select[name=field] > option[value=cf_' + json.cf + ']')) {
|
||||
node.one('select[name=field]').set('value', 'cf_' + json.cf);
|
||||
}
|
||||
if (json.op !== undefined &&
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-availability_profile-form",function(e,t){M.availability_profile=M.availability_profile||{},M.availability_profile.form=e.Object(M.core_availability.plugin),M.availability_profile.form.profiles=null,M.availability_profile.form.initInner=function(e,t){this.standardFields=e,this.customFields=t},M.availability_profile.form.getNode=function(t){var n=M.str.availability_profile,r='<span class="availability-group"><label>'+n.conditiontitle+" "+'<select name="field">'+'<option value="choose">'+M.str.moodle.choosedots+"</option>",i;for(var s=0;s<this.standardFields.length;s++)i=this.standardFields[s],r+='<option value="sf_'+i.field+'">'+i.display+"</option>";for(s=0;s<this.customFields.length;s++)i=this.customFields[s],r+='<option value="cf_'+i.field+'">'+i.display+"</option>";r+='</select></label> <label><span class="accesshide">'+n.label_operator+' </span><select name="op" title="'+n.label_operator+'">';var o=["isequalto","contains","doesnotcontain","startswith","endswith","isempty","isnotempty"];for(s=0;s<o.length;s++)r+='<option value="'+o[s]+'">'+n["op_"+o[s]]+"</option>";r+='</select></label> <label><span class="accesshide">'+n.label_value+'</span><input name="value" type="text" style="width: 10em" title="'+n.label_value+'"/></label></span>';var u=e.Node.create("<span>"+r+"</span>");t.sf!==undefined&&u.one("select[name=field] > option[value=sf_"+t.sf+"]")?u.one("select[name=field]").set("value","sf_"+t.sf):t.cf!==undefined&&u.one("select[name=field] > option[value=cf_"+t.sf+"]")&&u.one("select[name=field]").set("value","cf_"+t.cf),t.op!==undefined&&u.one("select[name=op] > option[value="+t.op+"]")&&u.one("select[name=op]").set("value",t.op),t.v!==undefined&&u.one("input").set("value",t.v);if(!M.availability_profile.form.addedEvents){M.availability_profile.form.addedEvents=!0;var a=function(e){var t=e.ancestor("span.availability_profile"),n=t.one("select[name=op]"),r=n.get("value")==="isempty"||n.get("value")==="isnotempty";t.one("input[name=value]").set("disabled",r),M.core_availability.form.update()},f=e.one("#fitem_id_availabilityconditionsjson");f.delegate("change",function(){a(this)},".availability_profile select"),f.delegate("change",function(){a(this)},".availability_profile input[name=value]")}return u},M.availability_profile.form.fillValue=function(e,t){var n=t.one("select[name=field]").get("value");n.substr(0,3)==="sf_"?e.sf=n.substr(3):n.substr(0,3)==="cf_"&&(e.cf=n.substr(3)),e.op=t.one("select[name=op]").get("value");var r=t.one("input[name=value]");r.get("disabled")||(e.v=r.get("value"))},M.availability_profile.form.fillErrors=function(e,t){var n={};this.fillValue(n,t),n.sf===undefined&&n.cf===undefined&&e.push("availability_profile:error_selectfield"),n.v!==undefined&&/^\s*$/.test(n.v)&&e.push("availability_profile:error_setvalue")}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]});
|
||||
YUI.add("moodle-availability_profile-form",function(e,t){M.availability_profile=M.availability_profile||{},M.availability_profile.form=e.Object(M.core_availability.plugin),M.availability_profile.form.profiles=null,M.availability_profile.form.initInner=function(e,t){this.standardFields=e,this.customFields=t},M.availability_profile.form.getNode=function(t){var n=M.str.availability_profile,r='<span class="availability-group"><label>'+n.conditiontitle+" "+'<select name="field">'+'<option value="choose">'+M.str.moodle.choosedots+"</option>",i;for(var s=0;s<this.standardFields.length;s++)i=this.standardFields[s],r+='<option value="sf_'+i.field+'">'+i.display+"</option>";for(s=0;s<this.customFields.length;s++)i=this.customFields[s],r+='<option value="cf_'+i.field+'">'+i.display+"</option>";r+='</select></label> <label><span class="accesshide">'+n.label_operator+' </span><select name="op" title="'+n.label_operator+'">';var o=["isequalto","contains","doesnotcontain","startswith","endswith","isempty","isnotempty"];for(s=0;s<o.length;s++)r+='<option value="'+o[s]+'">'+n["op_"+o[s]]+"</option>";r+='</select></label> <label><span class="accesshide">'+n.label_value+'</span><input name="value" type="text" style="width: 10em" title="'+n.label_value+'"/></label></span>';var u=e.Node.create("<span>"+r+"</span>");t.sf!==undefined&&u.one("select[name=field] > option[value=sf_"+t.sf+"]")?u.one("select[name=field]").set("value","sf_"+t.sf):t.cf!==undefined&&u.one("select[name=field] > option[value=cf_"+t.cf+"]")&&u.one("select[name=field]").set("value","cf_"+t.cf),t.op!==undefined&&u.one("select[name=op] > option[value="+t.op+"]")&&u.one("select[name=op]").set("value",t.op),t.v!==undefined&&u.one("input").set("value",t.v);if(!M.availability_profile.form.addedEvents){M.availability_profile.form.addedEvents=!0;var a=function(e){var t=e.ancestor("span.availability_profile"),n=t.one("select[name=op]"),r=n.get("value")==="isempty"||n.get("value")==="isnotempty";t.one("input[name=value]").set("disabled",r),M.core_availability.form.update()},f=e.one("#fitem_id_availabilityconditionsjson");f.delegate("change",function(){a(this)},".availability_profile select"),f.delegate("change",function(){a(this)},".availability_profile input[name=value]")}return u},M.availability_profile.form.fillValue=function(e,t){var n=t.one("select[name=field]").get("value");n.substr(0,3)==="sf_"?e.sf=n.substr(3):n.substr(0,3)==="cf_"&&(e.cf=n.substr(3)),e.op=t.one("select[name=op]").get("value");var r=t.one("input[name=value]");r.get("disabled")||(e.v=r.get("value"))},M.availability_profile.form.fillErrors=function(e,t){var n={};this.fillValue(n,t),n.sf===undefined&&n.cf===undefined&&e.push("availability_profile:error_selectfield"),n.v!==undefined&&/^\s*$/.test(n.v)&&e.push("availability_profile:error_setvalue")}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]});
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ M.availability_profile.form.getNode = function(json) {
|
||||
node.one('select[name=field] > option[value=sf_' + json.sf + ']')) {
|
||||
node.one('select[name=field]').set('value', 'sf_' + json.sf);
|
||||
} else if (json.cf !== undefined &&
|
||||
node.one('select[name=field] > option[value=cf_' + json.sf + ']')) {
|
||||
node.one('select[name=field] > option[value=cf_' + json.cf + ']')) {
|
||||
node.one('select[name=field]').set('value', 'cf_' + json.cf);
|
||||
}
|
||||
if (json.op !== undefined &&
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ M.availability_profile.form.getNode = function(json) {
|
||||
node.one('select[name=field] > option[value=sf_' + json.sf + ']')) {
|
||||
node.one('select[name=field]').set('value', 'sf_' + json.sf);
|
||||
} else if (json.cf !== undefined &&
|
||||
node.one('select[name=field] > option[value=cf_' + json.sf + ']')) {
|
||||
node.one('select[name=field] > option[value=cf_' + json.cf + ']')) {
|
||||
node.one('select[name=field]').set('value', 'cf_' + json.cf);
|
||||
}
|
||||
if (json.op !== undefined &&
|
||||
|
||||
@@ -77,6 +77,7 @@ Feature: display_availability
|
||||
And I click on "User profile" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "User profile field" to "Email address"
|
||||
And I set the field "Value to compare against" to "email@example.org"
|
||||
And I set the field "Method of comparison" to "is equal to"
|
||||
And I press "Save and return to course"
|
||||
|
||||
# Add another Page with no restrictions.
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* create the temp dir where backup/restore will happen,
|
||||
* delete old directories and create temp ids table
|
||||
* Create the temp dir where backup/restore will happen and create temp ids table.
|
||||
*/
|
||||
class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
|
||||
@@ -38,7 +37,6 @@ class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
$progress->start_progress('Deleting backup directories');
|
||||
backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir
|
||||
backup_helper::clear_backup_dir($this->get_backupid(), $progress); // Empty temp dir, just in case
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60), $progress); // Delete > 4 hours temp dirs
|
||||
backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table
|
||||
backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table
|
||||
$progress->end_progress();
|
||||
@@ -46,11 +44,11 @@ class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the temp dir used by backup/restore (conditionally),
|
||||
* delete old directories and drop tem ids table. Note we delete
|
||||
* Delete the temp dir used by backup/restore (conditionally),
|
||||
* delete old directories and drop temp ids table. Note we delete
|
||||
* the directory but not the corresponding log file that will be
|
||||
* there for, at least, 4 hours - only delete_old_backup_dirs()
|
||||
* deletes log files (for easier access to them)
|
||||
* there for, at least, 1 week - only delete_old_backup_dirs() or cron
|
||||
* deletes log files (for easier access to them).
|
||||
*/
|
||||
class drop_and_clean_temp_stuff extends backup_execution_step {
|
||||
|
||||
@@ -60,7 +58,7 @@ class drop_and_clean_temp_stuff extends backup_execution_step {
|
||||
global $CFG;
|
||||
|
||||
backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
|
||||
backup_helper::delete_old_backup_dirs(strtotime('-1 week')); // Delete > 1 week old temp dirs.
|
||||
// Delete temp dir conditionally:
|
||||
// 1) If $CFG->keeptempdirectoriesonbackup is not enabled
|
||||
// 2) If backup temp dir deletion has been marked to be avoided
|
||||
|
||||
@@ -67,7 +67,7 @@ class restore_drop_and_clean_temp_stuff extends restore_execution_step {
|
||||
restore_controller_dbops::drop_restore_temp_tables($this->get_restoreid()); // Drop ids temp table
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress('Deleting backup dir');
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60), $progress); // Delete > 4 hours temp dirs
|
||||
backup_helper::delete_old_backup_dirs(strtotime('-1 week'), $progress); // Delete > 1 week old temp dirs.
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) { // Conditionally
|
||||
backup_helper::delete_backup_dir($this->task->get_tempdir(), $progress); // Empty restore dir
|
||||
}
|
||||
@@ -3676,13 +3676,16 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
* Execution step that will create all the question/answers/qtype-specific files for the restored
|
||||
* questions. It must be executed after {@link restore_move_module_questions_categories}
|
||||
* because only then each question is in its final category and only then the
|
||||
* context can be determined
|
||||
*
|
||||
* TODO: Improve this. Instead of looping over each question, it can be reduced to
|
||||
* be done by contexts (this will save a huge ammount of queries)
|
||||
* contexts can be determined.
|
||||
*/
|
||||
class restore_create_question_files extends restore_execution_step {
|
||||
|
||||
/** @var array Question-type specific component items cache. */
|
||||
private $qtypecomponentscache = array();
|
||||
|
||||
/**
|
||||
* Preform the restore_create_question_files step.
|
||||
*/
|
||||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
@@ -3690,60 +3693,93 @@ class restore_create_question_files extends restore_execution_step {
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress($this->get_name(), \core\progress\base::INDETERMINATE);
|
||||
|
||||
// Let's process only created questions
|
||||
$questionsrs = $DB->get_recordset_sql("SELECT bi.itemid, bi.newitemid, bi.parentitemid, q.qtype
|
||||
// Parentitemids of question_createds in backup_ids_temp are the category it is in.
|
||||
// MUST use a recordset, as there is no unique key in the first (or any) column.
|
||||
$catqtypes = $DB->get_recordset_sql("SELECT DISTINCT bi.parentitemid AS categoryid, q.qtype as qtype
|
||||
FROM {backup_ids_temp} bi
|
||||
JOIN {question} q ON q.id = bi.newitemid
|
||||
WHERE bi.backupid = ?
|
||||
AND bi.itemname = 'question_created'", array($this->get_restoreid()));
|
||||
foreach ($questionsrs as $question) {
|
||||
// Report progress for each question.
|
||||
$progress->progress();
|
||||
AND bi.itemname = 'question_created'
|
||||
ORDER BY categoryid ASC", array($this->get_restoreid()));
|
||||
|
||||
// Get question_category mapping, it contains the target context for the question
|
||||
if (!$qcatmapping = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question_category', $question->parentitemid)) {
|
||||
// Something went really wrong, cannot find the question_category for the question
|
||||
debugging('Error fetching target context for question', DEBUG_DEVELOPER);
|
||||
continue;
|
||||
}
|
||||
// Calculate source and target contexts
|
||||
$oldctxid = $qcatmapping->info->contextid;
|
||||
$newctxid = $qcatmapping->parentitemid;
|
||||
$currentcatid = -1;
|
||||
foreach ($catqtypes as $categoryid => $row) {
|
||||
$qtype = $row->qtype;
|
||||
|
||||
// Add common question files (question and question_answer ones)
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'questiontext',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'generalfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'correctfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'partiallycorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'incorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
// Check if we are in a new category.
|
||||
if ($currentcatid !== $categoryid) {
|
||||
// Report progress for each category.
|
||||
$progress->progress();
|
||||
|
||||
// Add qtype dependent files
|
||||
$components = backup_qtype_plugin::get_components_and_fileareas($question->qtype);
|
||||
foreach ($components as $component => $fileareas) {
|
||||
foreach ($fileareas as $filearea => $mapping) {
|
||||
// Use itemid only if mapping is question_created
|
||||
$itemid = ($mapping == 'question_created') ? $question->itemid : null;
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea,
|
||||
$oldctxid, $this->task->get_userid(), $mapping, $itemid, $newctxid, true, $progress);
|
||||
if (!$qcatmapping = restore_dbops::get_backup_ids_record($this->get_restoreid(),
|
||||
'question_category', $categoryid)) {
|
||||
// Something went really wrong, cannot find the question_category for the question_created records.
|
||||
debugging('Error fetching target context for question', DEBUG_DEVELOPER);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate source and target contexts.
|
||||
$oldctxid = $qcatmapping->info->contextid;
|
||||
$newctxid = $qcatmapping->parentitemid;
|
||||
|
||||
$this->send_common_files($oldctxid, $newctxid, $progress);
|
||||
$currentcatid = $categoryid;
|
||||
}
|
||||
|
||||
$this->send_qtype_files($qtype, $oldctxid, $newctxid, $progress);
|
||||
}
|
||||
$questionsrs->close();
|
||||
$catqtypes->close();
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the common question files to a new context.
|
||||
*
|
||||
* @param int $oldctxid Old context id.
|
||||
* @param int $newctxid New context id.
|
||||
* @param \core\progress $progress Progress object to use.
|
||||
*/
|
||||
private function send_common_files($oldctxid, $newctxid, $progress) {
|
||||
// Add common question files (question and question_answer ones).
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'questiontext',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'generalfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'correctfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'partiallycorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'incorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the question type specific files to a new context.
|
||||
*
|
||||
* @param text $qtype The qtype name to send.
|
||||
* @param int $oldctxid Old context id.
|
||||
* @param int $newctxid New context id.
|
||||
* @param \core\progress $progress Progress object to use.
|
||||
*/
|
||||
private function send_qtype_files($qtype, $oldctxid, $newctxid, $progress) {
|
||||
if (!isset($this->qtypecomponentscache[$qtype])) {
|
||||
$this->qtypecomponentscache[$qtype] = backup_qtype_plugin::get_components_and_fileareas($qtype);
|
||||
}
|
||||
$components = $this->qtypecomponentscache[$qtype];
|
||||
foreach ($components as $component => $fileareas) {
|
||||
foreach ($fileareas as $filearea => $mapping) {
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea,
|
||||
$oldctxid, $this->task->get_userid(), $mapping, null, $newctxid, true, $progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to restore aliases and references to external files.
|
||||
|
||||
@@ -547,7 +547,8 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
self::apply_general_config_defaults($controller);
|
||||
break;
|
||||
case backup::MODE_AUTOMATED:
|
||||
// TODO: Move the loading from automatic stuff to here
|
||||
// Load the automated defaults.
|
||||
self::apply_auto_config_defaults($controller);
|
||||
break;
|
||||
default:
|
||||
// Nothing to do for other modes (IMPORT/HUB...). Some day we
|
||||
@@ -555,6 +556,43 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller settings default values from the automated backup config.
|
||||
*
|
||||
* @param backup_controller $controller
|
||||
*/
|
||||
private static function apply_auto_config_defaults(backup_controller $controller) {
|
||||
$settings = array(
|
||||
// Config name => Setting name.
|
||||
'backup_auto_users' => 'users',
|
||||
'backup_auto_role_assignments' => 'role_assignments',
|
||||
'backup_auto_activities' => 'activities',
|
||||
'backup_auto_blocks' => 'blocks',
|
||||
'backup_auto_filters' => 'filters',
|
||||
'backup_auto_comments' => 'comments',
|
||||
'backup_auto_badges' => 'badges',
|
||||
'backup_auto_userscompletion' => 'userscompletion',
|
||||
'backup_auto_logs' => 'logs',
|
||||
'backup_auto_histories' => 'grade_histories',
|
||||
'backup_auto_questionbank' => 'questionbank'
|
||||
);
|
||||
$plan = $controller->get_plan();
|
||||
foreach ($settings as $config => $settingname) {
|
||||
$value = get_config('backup', $config);
|
||||
if ($value === false) {
|
||||
// The setting is not set.
|
||||
$controller->log('Could not find a value for the config ' . $config, BACKUP::LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
if ($plan->setting_exists($settingname)) {
|
||||
$setting = $plan->get_setting($settingname);
|
||||
$setting->set_value($value);
|
||||
} else {
|
||||
$controller->log('Unknown setting: ' . $settingname, BACKUP::LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller settings default values from the backup config.
|
||||
*
|
||||
@@ -583,6 +621,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
// Ignore this because the config has not been set. get_config
|
||||
// returns false if a setting doesn't exist, '0' is returned when
|
||||
// the configuration is set to false.
|
||||
$controller->log('Could not find a value for the config ' . $config, BACKUP::LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
$locked = (get_config('backup', $config.'_locked') == true);
|
||||
@@ -594,6 +633,8 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
$setting->set_status(base_setting::LOCKED_BY_CONFIG);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$controller->log('Unknown setting: ' . $setting, BACKUP::LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,18 @@ abstract class backup_structure_dbops extends backup_dbops {
|
||||
}
|
||||
}
|
||||
|
||||
public static function annotate_files($backupid, $contextid, $component, $filearea, $itemid) {
|
||||
/**
|
||||
* Adds backup id database record for all files in the given file area.
|
||||
*
|
||||
* @param string $backupid Backup ID
|
||||
* @param int $contextid Context id
|
||||
* @param string $component Component
|
||||
* @param string $filearea File area
|
||||
* @param int $itemid Item id
|
||||
* @param \core\progress\base $progress
|
||||
*/
|
||||
public static function annotate_files($backupid, $contextid, $component, $filearea, $itemid,
|
||||
\core\progress\base $progress = null) {
|
||||
global $DB;
|
||||
$sql = 'SELECT id
|
||||
FROM {files}
|
||||
@@ -120,10 +131,19 @@ abstract class backup_structure_dbops extends backup_dbops {
|
||||
$sql .= ' AND itemid = ?';
|
||||
$params[] = $itemid;
|
||||
}
|
||||
if ($progress) {
|
||||
$progress->start_progress('');
|
||||
}
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $record) {
|
||||
if ($progress) {
|
||||
$progress->progress();
|
||||
}
|
||||
self::insert_backup_ids_record($backupid, 'file', $record->id);
|
||||
}
|
||||
if ($progress) {
|
||||
$progress->end_progress();
|
||||
}
|
||||
$rs->close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,7 +1019,7 @@ abstract class restore_dbops {
|
||||
// Even if a file has been deleted since the backup was made, the file metadata will remain in the
|
||||
// files table, and the file will not be moved to the trashdir.
|
||||
// Files are not cleared from the files table by cron until several days after deletion.
|
||||
if ($foundfiles = $DB->get_records('files', array('contenthash' => $file->contenthash))) {
|
||||
if ($foundfiles = $DB->get_records('files', array('contenthash' => $file->contenthash), '', '*', 0, 1)) {
|
||||
// Only grab one of the foundfiles - the file content should be the same for all entries.
|
||||
$foundfile = reset($foundfiles);
|
||||
$fs->create_file_from_storedfile($file_record, $foundfile->id);
|
||||
|
||||
@@ -381,27 +381,6 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
try {
|
||||
|
||||
$settings = array(
|
||||
'users' => 'backup_auto_users',
|
||||
'role_assignments' => 'backup_auto_role_assignments',
|
||||
'activities' => 'backup_auto_activities',
|
||||
'blocks' => 'backup_auto_blocks',
|
||||
'filters' => 'backup_auto_filters',
|
||||
'comments' => 'backup_auto_comments',
|
||||
'badges' => 'backup_auto_badges',
|
||||
'completion_information' => 'backup_auto_userscompletion',
|
||||
'logs' => 'backup_auto_logs',
|
||||
'histories' => 'backup_auto_histories',
|
||||
'questionbank' => 'backup_auto_questionbank'
|
||||
);
|
||||
foreach ($settings as $setting => $configsetting) {
|
||||
if ($bc->get_plan()->setting_exists($setting)) {
|
||||
if (isset($config->{$configsetting})) {
|
||||
$bc->get_plan()->get_setting($setting)->set_value($config->{$configsetting});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the default filename.
|
||||
$format = $bc->get_format();
|
||||
$type = $bc->get_type();
|
||||
|
||||
@@ -232,7 +232,7 @@ abstract class backup_general_helper extends backup_helper {
|
||||
*
|
||||
* @param string $filepath absolute path to the MBZ file.
|
||||
* @return stdClass containing information.
|
||||
* @since 2.4
|
||||
* @since Moodle 2.4
|
||||
*/
|
||||
public static function get_backup_information_from_mbz($filepath) {
|
||||
global $CFG;
|
||||
|
||||
@@ -167,18 +167,21 @@ class restore_plan extends base_plan implements loggable {
|
||||
parent::execute();
|
||||
$this->controller->set_status(backup::STATUS_FINISHED_OK);
|
||||
|
||||
// Trigger a course restored event.
|
||||
$event = \core\event\course_restored::create(array(
|
||||
'objectid' => $this->get_courseid(),
|
||||
'userid' => $this->get_userid(),
|
||||
'context' => context_course::instance($this->get_courseid()),
|
||||
'other' => array('type' => $this->controller->get_type(),
|
||||
'target' => $this->controller->get_target(),
|
||||
'mode' => $this->controller->get_mode(),
|
||||
'operation' => $this->controller->get_operation(),
|
||||
'samesite' => $this->controller->is_samesite())
|
||||
));
|
||||
$event->trigger();
|
||||
// Check if we are restoring a course.
|
||||
if ($this->controller->get_type() === backup::TYPE_1COURSE) {
|
||||
// Trigger a course restored event.
|
||||
$event = \core\event\course_restored::create(array(
|
||||
'objectid' => $this->get_courseid(),
|
||||
'userid' => $this->get_userid(),
|
||||
'context' => context_course::instance($this->get_courseid()),
|
||||
'other' => array('type' => $this->controller->get_type(),
|
||||
'target' => $this->controller->get_target(),
|
||||
'mode' => $this->controller->get_mode(),
|
||||
'operation' => $this->controller->get_operation(),
|
||||
'samesite' => $this->controller->is_samesite())
|
||||
));
|
||||
$event->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,7 +86,7 @@ class backup_structure_processor extends base_processor {
|
||||
foreach ($area as $filearea => $info) {
|
||||
$contextid = !is_null($info->contextid) ? $info->contextid : $this->get_var(backup::VAR_CONTEXTID);
|
||||
$itemid = !is_null($info->element) ? $info->element->get_value() : null;
|
||||
backup_structure_dbops::annotate_files($backupid, $contextid, $component, $filearea, $itemid);
|
||||
backup_structure_dbops::annotate_files($backupid, $contextid, $component, $filearea, $itemid, $this->progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,9 +244,20 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
global $CFG, $PAGE;
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
|
||||
// These variables are used to check if the form using this function was submitted.
|
||||
$target = optional_param('target', false, PARAM_INT);
|
||||
$targetid = optional_param('targetid', null, PARAM_INT);
|
||||
|
||||
// Check if they submitted the form but did not provide all the data we need.
|
||||
$missingdata = false;
|
||||
if ($target and is_null($targetid)) {
|
||||
$missingdata = true;
|
||||
}
|
||||
|
||||
$nextstageurl->param('sesskey', sesskey());
|
||||
|
||||
$form = html_writer::start_tag('form', array('method'=>'post', 'action'=>$nextstageurl->out_omit_querystring()));
|
||||
$form = html_writer::start_tag('form', array('method' => 'post', 'action' => $nextstageurl->out_omit_querystring(),
|
||||
'class' => 'mform'));
|
||||
foreach ($nextstageurl->params() as $key=>$value) {
|
||||
$form .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$key, 'value'=>$value));
|
||||
}
|
||||
@@ -261,7 +272,16 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$html .= html_writer::start_tag('div', array('class'=>'bcs-new-course backup-section'));
|
||||
$html .= $this->output->heading(get_string('restoretonewcourse', 'backup'), 2, array('class'=>'header'));
|
||||
$html .= $this->backup_detail_input(get_string('restoretonewcourse', 'backup'), 'radio', 'target', backup::TARGET_NEW_COURSE, array('checked'=>'checked'));
|
||||
$html .= $this->backup_detail_pair(get_string('selectacategory', 'backup'), $this->render($categories));
|
||||
$selectacategoryhtml = $this->backup_detail_pair(get_string('selectacategory', 'backup'), $this->render($categories));
|
||||
// Display the category selection as required if the form was submitted but this data was not supplied.
|
||||
if ($missingdata && $target == backup::TARGET_NEW_COURSE) {
|
||||
$html .= html_writer::span(get_string('required'), 'error');
|
||||
$html .= html_writer::start_tag('fieldset', array('class' => 'error'));
|
||||
$html .= $selectacategoryhtml;
|
||||
$html .= html_writer::end_tag('fieldset');
|
||||
} else {
|
||||
$html .= $selectacategoryhtml;
|
||||
}
|
||||
$html .= $this->backup_detail_pair('', html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('continue'))));
|
||||
$html .= html_writer::end_tag('div');
|
||||
$html .= html_writer::end_tag('form');
|
||||
@@ -290,13 +310,21 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
if ($wholecourse) {
|
||||
$html .= $this->backup_detail_input(get_string('restoretoexistingcourseadding', 'backup'), 'radio', 'target', backup::TARGET_EXISTING_ADDING, array('checked'=>'checked'));
|
||||
$html .= $this->backup_detail_input(get_string('restoretoexistingcoursedeleting', 'backup'), 'radio', 'target', backup::TARGET_EXISTING_DELETING);
|
||||
$html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
|
||||
} else {
|
||||
// We only allow restore adding to existing for now. Enforce it here.
|
||||
$html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'target', 'value'=>backup::TARGET_EXISTING_ADDING));
|
||||
$courses->invalidate_results(); // Clean list of courses
|
||||
$courses->set_include_currentcourse(); // Show current course in the list
|
||||
$html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
|
||||
}
|
||||
$selectacoursehtml = $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
|
||||
// Display the course selection as required if the form was submitted but this data was not supplied.
|
||||
if ($missingdata && $target == backup::TARGET_EXISTING_ADDING) {
|
||||
$html .= html_writer::span(get_string('required'), 'error');
|
||||
$html .= html_writer::start_tag('fieldset', array('class' => 'error'));
|
||||
$html .= $selectacoursehtml;
|
||||
$html .= html_writer::end_tag('fieldset');
|
||||
} else {
|
||||
$html .= $selectacoursehtml;
|
||||
}
|
||||
$html .= $this->backup_detail_pair('', html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('continue'))));
|
||||
$html .= html_writer::end_tag('div');
|
||||
|
||||
@@ -18,7 +18,7 @@ Feature: Backup Moodle courses
|
||||
@javascript
|
||||
Scenario: Backup a course providing options
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
Then I should see "Restore"
|
||||
And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
|
||||
And I should see "URL of backup"
|
||||
@@ -27,11 +27,11 @@ Feature: Backup Moodle courses
|
||||
@javascript
|
||||
Scenario: Backup a course with default options
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Include calendar events | 0 |
|
||||
| Include course logs | 1 |
|
||||
| setting_section_section_5_userinfo | 0 |
|
||||
| setting_section_section_5_included | 0 |
|
||||
| Initial | Include calendar events | 0 |
|
||||
| Initial | Include course logs | 1 |
|
||||
| Schema | setting_section_section_5_userinfo | 0 |
|
||||
| Schema | setting_section_section_5_included | 0 |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
Then I should see "Restore"
|
||||
And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
|
||||
And I should not see "Section 3"
|
||||
@@ -44,17 +44,17 @@ Feature: Backup Moodle courses
|
||||
@javascript
|
||||
Scenario: Backup a course without blocks
|
||||
When I backup "Course 1" course using this options:
|
||||
| id_setting_root_blocks | 0 |
|
||||
| 1 | setting_root_blocks | 0 |
|
||||
Then I should see "Course backup area"
|
||||
|
||||
@javascript
|
||||
Scenario: Backup selecting just one section
|
||||
When I backup "Course 2" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| setting_section_section_2_userinfo | 0 |
|
||||
| setting_section_section_2_included | 0 |
|
||||
| setting_section_section_4_userinfo | 0 |
|
||||
| setting_section_section_4_included | 0 |
|
||||
| Schema | setting_section_section_2_userinfo | 0 |
|
||||
| Schema | setting_section_section_2_userinfo | 0 |
|
||||
| Schema | setting_section_section_4_included | 0 |
|
||||
| Schema | setting_section_section_4_included | 0 |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
Then I should see "Course backup area"
|
||||
And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
|
||||
And I should not see "Section 2"
|
||||
|
||||
@@ -50,34 +50,31 @@ class behat_backup extends behat_base {
|
||||
* @param TableNode $options Backup options or false if no options provided
|
||||
*/
|
||||
public function i_backup_course_using_this_options($backupcourse, $options = false) {
|
||||
|
||||
// We can not use other steps here as we don't know where the provided data
|
||||
// table elements are used, and we need to catch exceptions contantly.
|
||||
|
||||
// Go to homepage.
|
||||
$this->getSession()->visit($this->locate_path('/'));
|
||||
$this->wait();
|
||||
|
||||
// Click the course link.
|
||||
$this->find_link($backupcourse)->click();
|
||||
$this->wait();
|
||||
|
||||
// Click the backup link.
|
||||
$this->find_link(get_string('backup'))->click();
|
||||
$this->wait();
|
||||
|
||||
// Initial settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Initial"));
|
||||
$this->find_button(get_string('backupstage1action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Schema settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
|
||||
$this->find_button(get_string('backupstage2action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Confirmation and review, backup filename can also be specified.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Confirmation"));
|
||||
$this->find_button(get_string('backupstage4action', 'backup'))->press();
|
||||
|
||||
// Waiting for it to finish.
|
||||
@@ -132,12 +129,12 @@ class behat_backup extends behat_base {
|
||||
$this->wait();
|
||||
|
||||
// Initial settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Initial"));
|
||||
$this->find_button(get_string('importbackupstage1action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Schema settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
|
||||
$this->find_button(get_string('importbackupstage2action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
@@ -303,12 +300,12 @@ class behat_backup extends behat_base {
|
||||
// table elements are used, and we need to catch exceptions contantly.
|
||||
|
||||
// Settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Settings"));
|
||||
$this->find_button(get_string('restorestage4action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Schema.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
|
||||
$this->find_button(get_string('restorestage8action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
@@ -341,23 +338,50 @@ class behat_backup extends behat_base {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the page to be loaded and the JS ready.
|
||||
$this->wait();
|
||||
|
||||
// If we find any of the provided options in the current form we should set the value.
|
||||
$datahash = $options->getRowsHash();
|
||||
foreach ($datahash as $locator => $value) {
|
||||
|
||||
try {
|
||||
$field = behat_field_manager::get_form_field_from_label($locator, $this);
|
||||
$field->set_value($value);
|
||||
|
||||
} catch (ElementNotFoundException $e) {
|
||||
// Next provided option then, this one should be part of another page's fields.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options specific to this step of the backup/restore process.
|
||||
*
|
||||
* @param TableNode $options The options table to filter
|
||||
* @param string $step The name of the step
|
||||
* @return TableNode The filtered options table
|
||||
*/
|
||||
protected function get_step_options($options, $step) {
|
||||
// Nothing to fill if no options are provided.
|
||||
if (!$options) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pageoptions = clone $options;
|
||||
|
||||
$rows = $options->getRows();
|
||||
$newrows = array();
|
||||
foreach ($rows as $k => $data) {
|
||||
if (count($data) !== 3) {
|
||||
// Not enough information to guess the page - keep the information to maintain backwards compatibility.
|
||||
$newrows[] = $data;
|
||||
continue;
|
||||
} else if ($data[0] == $step) {
|
||||
unset($data[0]);
|
||||
$newrows[] = $data;
|
||||
}
|
||||
}
|
||||
$pageoptions->setRows($newrows);
|
||||
return $pageoptions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits until the DOM and the page Javascript code is ready.
|
||||
*
|
||||
|
||||
@@ -25,7 +25,7 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a course in another existing course
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
|
||||
Then I should see "Course 2"
|
||||
And I should see "Community finder" in the "Community finder" "block"
|
||||
@@ -34,9 +34,9 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a course in a new course
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Course name | Course 1 restored in a new course |
|
||||
| Schema | Course name | Course 1 restored in a new course |
|
||||
Then I should see "Course 1 restored in a new course"
|
||||
And I should see "Community finder" in the "Community finder" "block"
|
||||
And I should see "Test forum name"
|
||||
@@ -50,12 +50,12 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a backup into the same course
|
||||
When I backup "Course 3" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
|
||||
| setting_section_section_3_included | 0 |
|
||||
| setting_section_section_3_userinfo | 0 |
|
||||
| setting_section_section_5_included | 0 |
|
||||
| setting_section_section_5_userinfo | 0 |
|
||||
| Schema | setting_section_section_3_included | 0 |
|
||||
| Schema | setting_section_section_3_userinfo | 0 |
|
||||
| Schema | setting_section_section_5_included | 0 |
|
||||
| Schema | setting_section_section_5_userinfo | 0 |
|
||||
Then I should see "Course 2"
|
||||
And I should see "Test assign name"
|
||||
And I should not see "Test database name"
|
||||
@@ -63,15 +63,15 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a backup into the same course removing it's contents before that
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I follow "Course 1"
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum post backup name |
|
||||
| Description | Test forum post backup description |
|
||||
And I follow "Restore"
|
||||
And I merge "test_backup.mbz" backup into the current course after deleting it's contents using this options:
|
||||
| setting_section_section_5_userinfo | 0 |
|
||||
| setting_section_section_5_included | 0 |
|
||||
| Schema | setting_section_section_8_userinfo | 0 |
|
||||
| Schema | setting_section_section_8_included | 0 |
|
||||
Then I should see "Course 1"
|
||||
And I should not see "Section 3"
|
||||
And I should not see "Test forum post backup name"
|
||||
@@ -81,7 +81,7 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a backup into a new course changing the course format afterwards
|
||||
Given I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
Then I should see "Topic 1"
|
||||
And I should see "Test forum name"
|
||||
@@ -117,9 +117,9 @@ Feature: Restore Moodle 2 course backups
|
||||
And I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
|
||||
| Overwrite course configuration | Yes |
|
||||
| Schema | Overwrite course configuration | Yes |
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I expand all fieldsets
|
||||
Then the field "id_format" matches value "Topics format"
|
||||
|
||||
+10
-1
@@ -52,7 +52,16 @@ $PAGE->set_title(get_string('issuedbadge', 'badges'));
|
||||
if (isloggedin()) {
|
||||
$PAGE->set_heading($badge->badgeclass['name']);
|
||||
$PAGE->navbar->add($badge->badgeclass['name']);
|
||||
$url = new moodle_url('/badges/mybadges.php');
|
||||
if ($badge->recipient->id == $USER->id) {
|
||||
$url = new moodle_url('/badges/mybadges.php');
|
||||
} else {
|
||||
$url = new moodle_url($CFG->wwwroot);
|
||||
}
|
||||
navigation_node::override_active_url($url);
|
||||
} else {
|
||||
$PAGE->set_heading($badge->badgeclass['name']);
|
||||
$PAGE->navbar->add($badge->badgeclass['name']);
|
||||
$url = new moodle_url($CFG->wwwroot);
|
||||
navigation_node::override_active_url($url);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,14 @@ $badge = new external_badge($badge, $userid);
|
||||
|
||||
$PAGE->set_pagelayout('base');
|
||||
$PAGE->set_title(get_string('issuedbadge', 'badges'));
|
||||
$PAGE->set_heading(s($badge->issued->assertion->badge->name));
|
||||
$PAGE->navbar->add(s($badge->issued->assertion->badge->name));
|
||||
if (isloggedin() && $USER->id == $userid) {
|
||||
$url = new moodle_url('/badges/mybadges.php');
|
||||
} else {
|
||||
$url = new moodle_url($CFG->wwwroot);
|
||||
}
|
||||
navigation_node::override_active_url($url);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
+18
-16
@@ -41,7 +41,7 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
$bname = $badge->name;
|
||||
$imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false);
|
||||
} else {
|
||||
$bname = $badge->assertion->badge->name;
|
||||
$bname = s($badge->assertion->badge->name);
|
||||
$imageurl = $badge->imageUrl;
|
||||
}
|
||||
|
||||
@@ -420,47 +420,48 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), '');
|
||||
$datatable->data[] = array(get_string('issuername', 'badges'), $issuer->name);
|
||||
$datatable->data[] = array(get_string('issuername', 'badges'), s($issuer->name));
|
||||
$datatable->data[] = array(get_string('issuerurl', 'badges'),
|
||||
html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin)));
|
||||
html_writer::tag('a', s($issuer->origin), array('href' => $issuer->origin)));
|
||||
if (isset($issuer->contact)) {
|
||||
$datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($issuer->contact));
|
||||
}
|
||||
$datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), '');
|
||||
$datatable->data[] = array(get_string('name'), $assertion->badge->name);
|
||||
$datatable->data[] = array(get_string('description', 'badges'), $assertion->badge->description);
|
||||
$datatable->data[] = array(get_string('name'), s($assertion->badge->name));
|
||||
$datatable->data[] = array(get_string('description', 'badges'), s($assertion->badge->description));
|
||||
$datatable->data[] = array(get_string('bcriteria', 'badges'),
|
||||
html_writer::tag('a', $assertion->badge->criteria, array('href' => $assertion->badge->criteria)));
|
||||
html_writer::tag('a', s($assertion->badge->criteria), array('href' => $assertion->badge->criteria)));
|
||||
$datatable->data[] = array($this->output->heading(get_string('issuancedetails', 'badges'), 3), '');
|
||||
if (isset($assertion->issued_on)) {
|
||||
$datatable->data[] = array(get_string('dateawarded', 'badges'), $assertion->issued_on);
|
||||
$issuedate = !strtotime($assertion->issued_on) ? s($assertion->issued_on) : strtotime($assertion->issued_on);
|
||||
$datatable->data[] = array(get_string('dateawarded', 'badges'), userdate($issuedate));
|
||||
}
|
||||
if (isset($assertion->badge->expire)) {
|
||||
if (isset($assertion->expires)) {
|
||||
$today_date = date('Y-m-d');
|
||||
$today = strtotime($today_date);
|
||||
$expiration = strtotime($assertion->badge->expire);
|
||||
$expiration = !strtotime($assertion->expires) ? s($assertion->expires) : strtotime($assertion->expires);
|
||||
if ($expiration < $today) {
|
||||
$cell = new html_table_cell($assertion->badge->expire . get_string('warnexpired', 'badges'));
|
||||
$cell = new html_table_cell(userdate($expiration) . get_string('warnexpired', 'badges'));
|
||||
$cell->attributes = array('class' => 'notifyproblem warning');
|
||||
$datatable->data[] = array(get_string('expirydate', 'badges'), $cell);
|
||||
|
||||
$image = html_writer::start_tag('div', array('class' => 'badge'));
|
||||
$image .= html_writer::empty_tag('img', array('src' => $issued['badge']['image']));
|
||||
$image .= html_writer::empty_tag('img', array('src' => $issued->imageUrl));
|
||||
$image .= html_writer::start_tag('span', array('class' => 'expired'))
|
||||
. $this->output->pix_icon('i/expired',
|
||||
get_string('expireddate', 'badges', $assertion->badge->expire),
|
||||
get_string('expireddate', 'badges', userdate($expiration)),
|
||||
'moodle',
|
||||
array('class' => 'expireimage'))
|
||||
. html_writer::end_tag('span');
|
||||
$image .= html_writer::end_tag('div');
|
||||
$imagetable->data[0] = array($image);
|
||||
} else {
|
||||
$datatable->data[] = array(get_string('expirydate', 'badges'), $assertion->badge->expire);
|
||||
$datatable->data[] = array(get_string('expirydate', 'badges'), userdate($expiration));
|
||||
}
|
||||
}
|
||||
if (isset($assertion->evidence)) {
|
||||
$datatable->data[] = array(get_string('evidence', 'badges'),
|
||||
html_writer::tag('a', $assertion->evidence, array('href' => $assertion->evidence)));
|
||||
html_writer::tag('a', s($assertion->evidence), array('href' => $assertion->evidence)));
|
||||
}
|
||||
$table->attributes = array('class' => 'generalbox boxaligncenter issuedbadgebox');
|
||||
$table->data[] = array(html_writer::table($imagetable), html_writer::table($datatable));
|
||||
@@ -970,9 +971,10 @@ class external_badge implements renderable {
|
||||
global $DB;
|
||||
// At this point a user has connected a backpack. So, we are going to get
|
||||
// their backpack email rather than their account email.
|
||||
$user = $DB->get_record_sql('SELECT u.lastname, u.firstname, b.email
|
||||
$namefields = get_all_user_name_fields(true, 'u');
|
||||
$user = $DB->get_record_sql("SELECT {$namefields}, b.email
|
||||
FROM {user} u INNER JOIN {badge_backpack} b ON u.id = b.userid
|
||||
WHERE userid = :userid', array('userid' => $recipient), IGNORE_MISSING);
|
||||
WHERE userid = :userid", array('userid' => $recipient), IGNORE_MISSING);
|
||||
|
||||
$this->issued = $badge;
|
||||
$this->recipient = $user;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* Please do not forget to use upgrade_set_timeout()
|
||||
* before any action that may take longer time to finish.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_community
|
||||
* @copyright 2010 Jerome Mouneyrac
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -60,5 +60,8 @@ function xmldb_block_community_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* Please do not forget to use upgrade_set_timeout()
|
||||
* before any action that may take longer time to finish.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_completionstatus
|
||||
* @copyright 2012 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -67,5 +67,8 @@ function xmldb_block_completionstatus_upgrade($oldversion, $block) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -315,11 +315,11 @@ class block_course_overview_renderer extends plugin_renderer_base {
|
||||
$plural = 's';
|
||||
if ($msgcount > 0) {
|
||||
$output .= get_string('youhavemessages', 'block_course_overview', $msgcount);
|
||||
} else {
|
||||
$output .= get_string('youhavenomessages', 'block_course_overview');
|
||||
if ($msgcount == 1) {
|
||||
$plural = '';
|
||||
}
|
||||
} else {
|
||||
$output .= get_string('youhavenomessages', 'block_course_overview');
|
||||
}
|
||||
$output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview'));
|
||||
$output .= $this->output->box_end();
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* Please do not forget to use upgrade_set_timeout()
|
||||
* before any action that may take longer time to finish.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_course_summary
|
||||
* @copyright 2012 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -71,5 +71,8 @@ function xmldb_block_course_summary_upgrade($oldversion, $block) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -25,19 +25,19 @@ Feature: Course summary block used in a course
|
||||
Scenario: Student can view course summary
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then "block_course_summary" "block" should exist
|
||||
And I should see "Proved the course summary block works!" in the "block_course_summary" "block"
|
||||
Then "Course/site summary" "block" should exist
|
||||
And I should see "Proved the course summary block works!" in the "Course/site summary" "block"
|
||||
|
||||
Scenario: Teacher can see an edit icon when edit mode is on and follow it to the course edit page
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
Then I should see "Proved the course summary block works!" in the "block_course_summary" "block"
|
||||
And I click on "Edit" "link" in the "block_course_summary" "block"
|
||||
Then I should see "Proved the course summary block works!" in the "Course/site summary" "block"
|
||||
And I click on "Edit" "link" in the "Course/site summary" "block"
|
||||
Then I should see "Edit course settings" in the "h2" "css_element"
|
||||
|
||||
Scenario: Teacher can not see edit icon when edit mode is off
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "Proved the course summary block works!" in the "block_course_summary" "block"
|
||||
And "Edit" "link" should not exist in the "block_course_summary" "block"
|
||||
Then I should see "Proved the course summary block works!" in the "Course/site summary" "block"
|
||||
And "Edit" "link" should not exist in the "Course/site summary" "block"
|
||||
|
||||
@@ -15,19 +15,19 @@ Feature: Course summary block used on the frontpage
|
||||
|
||||
Scenario: Guest can view site summary
|
||||
When I am on homepage
|
||||
Then "block_course_summary" "block" should exist
|
||||
And I should see "Proved the summary block works!" in the "block_course_summary" "block"
|
||||
Then "Course/site summary" "block" should exist
|
||||
And I should see "Proved the summary block works!" in the "Course/site summary" "block"
|
||||
|
||||
Scenario: Admin can see an edit icon when edit mode is on and follow it to the front page settings
|
||||
When I log in as "admin"
|
||||
And I am on homepage
|
||||
And I follow "Turn editing on"
|
||||
Then I should see "Proved the summary block works!" in the "block_course_summary" "block"
|
||||
And I click on "Edit" "link" in the "block_course_summary" "block"
|
||||
Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
|
||||
And I click on "Edit" "link" in the "Course/site summary" "block"
|
||||
Then I should see "Front page settings" in the "h2" "css_element"
|
||||
|
||||
Scenario: Admin can not see edit icon when edit mode is off
|
||||
When I log in as "teacher1"
|
||||
And I am on homepage
|
||||
Then I should see "Proved the summary block works!" in the "block_course_summary" "block"
|
||||
And "Edit" "link" should not exist in the "block_course_summary" "block"
|
||||
Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
|
||||
And "Edit" "link" should not exist in the "Course/site summary" "block"
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
@block @block_glossary_random
|
||||
Feature: Random glossary entry block is used in a course
|
||||
In order to show the entries from glossary
|
||||
As a teacher
|
||||
I can add the random glossary entry to a course page
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Sam1 | Student1 | student1@test.com |
|
||||
| teacher1 | Terry1 | Teacher1 | teacher1@test.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
|
||||
Scenario: Student can not see the block if it is not configured
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Random glossary entry" block
|
||||
Then I should see "Please configure this block using the edit icon" in the "block_glossary_random" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And "block_glossary_random" "block" should not exist
|
||||
And I log out
|
||||
|
||||
Scenario: View random (last) entry in the glossary with auto approval
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | defaultapproval |
|
||||
| glossary | GlossaryAuto | Test glossary description | C1 | glossary1 | 1 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Random glossary entry" block
|
||||
And I configure the "block_glossary_random" block
|
||||
And I set the following fields to these values:
|
||||
| Title | AutoGlossaryblock |
|
||||
| Take entries from this glossary | GlossaryAuto |
|
||||
| How a new entry is chosen | Last modified entry |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
|
||||
And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Concept1 |
|
||||
| Definition | Definition1 |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I should see "Concept1" in the "AutoGlossaryblock" "block"
|
||||
And I should see "Definition1" in the "AutoGlossaryblock" "block"
|
||||
And I should not see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
|
||||
And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Concept2 |
|
||||
| Definition | Definition2 |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
# Only the last entry appears in the block
|
||||
And I should not see "Concept1" in the "AutoGlossaryblock" "block"
|
||||
And I should not see "Definition1" in the "AutoGlossaryblock" "block"
|
||||
And I should see "Concept2" in the "AutoGlossaryblock" "block"
|
||||
And I should see "Definition2" in the "AutoGlossaryblock" "block"
|
||||
And I click on "View all entries" "link" in the "AutoGlossaryblock" "block"
|
||||
And I should see "GlossaryAuto" in the "#page-navbar" "css_element"
|
||||
And I should see "Concept1" in the "#page-content" "css_element"
|
||||
And I should see "Concept2" in the "#page-content" "css_element"
|
||||
And I log out
|
||||
|
||||
Scenario: View random (last) entry in the glossary with manual approval
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | defaultapproval |
|
||||
| glossary | GlossaryManual | Test glossary description | C1 | glossary2 | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Random glossary entry" block
|
||||
And I configure the "block_glossary_random" block
|
||||
And I set the following fields to these values:
|
||||
| Title | ManualGlossaryblock |
|
||||
| Take entries from this glossary | GlossaryManual |
|
||||
| How a new entry is chosen | Last modified entry |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
|
||||
And I click on "Add a new entry" "link" in the "ManualGlossaryblock" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Concept1 |
|
||||
| Definition | Definition1 |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
|
||||
And I follow "GlossaryManual"
|
||||
And I follow "Waiting approval"
|
||||
And I follow "Approve"
|
||||
And I click on "Course 1" "link" in the "#page-navbar" "css_element"
|
||||
And I should see "Concept1" in the "ManualGlossaryblock" "block"
|
||||
And I should see "Definition1" in the "ManualGlossaryblock" "block"
|
||||
And I log out
|
||||
@@ -0,0 +1,26 @@
|
||||
@block @block_glossary_random
|
||||
Feature: Random glossary entry block can be added to the frontpage
|
||||
In order to show the entries from glossary on the frontpage
|
||||
As a teacher
|
||||
I can add the random glossary entry to the frontpage
|
||||
|
||||
Scenario: Admin can add random glossary block to the frontpage
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| glossary | Tips and Tricks | Frontpage glossary description | Acceptance test site | glossary0 |
|
||||
And I log in as "admin"
|
||||
And I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "Random glossary entry" block
|
||||
And I configure the "block_glossary_random" block
|
||||
And I set the following fields to these values:
|
||||
| Title | Tip of the day |
|
||||
| Take entries from this glossary | Tips and Tricks |
|
||||
And I press "Save changes"
|
||||
And I click on "Add a new entry" "link" in the "Tip of the day" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Never come late |
|
||||
| Definition | Come in time for your classes |
|
||||
And I press "Save changes"
|
||||
When I log out
|
||||
Then I should see "Never come late" in the "Tip of the day" "block"
|
||||
And I should see "Come in time for your classes" in the "Tip of the day" "block"
|
||||
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* This file keeps track of upgrades to the html block
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_html
|
||||
* @copyright 2010 Dongsheng Cai
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -47,5 +47,8 @@ function xmldb_block_html_upgrade($oldversion) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
@block @block_html @core_block
|
||||
Feature: Adding and configuring HTML blocks
|
||||
In order to have custom blocks on a page
|
||||
As admin
|
||||
I need to be able to create, configure and change HTML blocks
|
||||
|
||||
@javascript
|
||||
Scenario: Configuring the HTML block with Javascript on
|
||||
Given I log in as "admin"
|
||||
When I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Static text without a header"
|
||||
And I press "Save changes"
|
||||
Then I should not see "(new HTML block)"
|
||||
And I configure the "block_html" block
|
||||
And I set the field "Block title" to "The HTML block header"
|
||||
And I set the field "Content" to "Static text with a header"
|
||||
And I press "Save changes"
|
||||
And "block_html" "block" should exist
|
||||
And "The HTML block header" "block" should exist
|
||||
And I should see "Static text with a header" in the "The HTML block header" "block"
|
||||
|
||||
Scenario: Configuring the HTML block with Javascript off
|
||||
Given I log in as "admin"
|
||||
When I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Static text without a header"
|
||||
And I press "Save changes"
|
||||
Then I should not see "(new HTML block)"
|
||||
And I configure the "block_html" block
|
||||
And I set the field "Block title" to "The HTML block header"
|
||||
And I set the field "Content" to "Static text with a header"
|
||||
And I press "Save changes"
|
||||
And "block_html" "block" should exist
|
||||
And "The HTML block header" "block" should exist
|
||||
And I should see "Static text with a header" in the "The HTML block header" "block"
|
||||
@@ -0,0 +1,36 @@
|
||||
@block @block_html
|
||||
Feature: HTML blocks in a course
|
||||
In order to have one or multiple HTML blocks in a course
|
||||
As a teacher
|
||||
I need to be able to create and change such blocks
|
||||
|
||||
Scenario: Adding HTML block in a course
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Terry1 | Teacher1 | teacher@asd.com |
|
||||
| student1 | Sam1 | Student1 | student1@asd.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "First block content"
|
||||
And I set the field "Block title" to "First block header"
|
||||
And I press "Save changes"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Second block content"
|
||||
And I set the field "Block title" to "Second block header"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I should see "First block content" in the "First block header" "block"
|
||||
And I should see "Second block content" in the "Second block header" "block"
|
||||
@@ -0,0 +1,41 @@
|
||||
@block @block_html
|
||||
Feature: Adding and configuring HTML blocks
|
||||
In order to have one or multiple HTML blocks on a page
|
||||
As admin
|
||||
I need to be able to create, configure and change HTML blocks
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
When I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "HTML" block
|
||||
|
||||
Scenario: Other users can not see HTML block that has not been configured
|
||||
Then "(new HTML block)" "block" should exist
|
||||
And I log out
|
||||
And "(new HTML block)" "block" should not exist
|
||||
And "block_html" "block" should not exist
|
||||
|
||||
Scenario: Other users can see HTML block that has been configured even when it has no header
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Static text without a header"
|
||||
And I press "Save changes"
|
||||
Then I should not see "(new HTML block)"
|
||||
And I log out
|
||||
And I am on homepage
|
||||
And "block_html" "block" should exist
|
||||
And I should see "Static text without a header" in the "block_html" "block"
|
||||
And I should not see "(new HTML block)"
|
||||
|
||||
Scenario: Adding multiple instances of HTML block on a page
|
||||
And I configure the "block_html" block
|
||||
And I set the field "Block title" to "The HTML block header"
|
||||
And I set the field "Content" to "Static text with a header"
|
||||
And I press "Save changes"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Block title" to "The second HTML block header"
|
||||
And I set the field "Content" to "Second block contents"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I should see "Static text with a header" in the "The HTML block header" "block"
|
||||
And I should see "Second block contents" in the "The second HTML block header" "block"
|
||||
@@ -18,7 +18,7 @@
|
||||
* This file contains classes used to manage the navigation structures in Moodle
|
||||
* and was introduced as part of the changes occuring in Moodle 2.0
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_navigation
|
||||
* @copyright 2009 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* Please do not forget to use upgrade_set_timeout()
|
||||
* before any action that may take longer time to finish.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_navigation
|
||||
* @copyright 2009 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -72,5 +72,8 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Form for editing global navigation instances.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_navigation
|
||||
* @copyright 2009 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/**
|
||||
* This file contains language strings used in the global navigation block
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_navigation
|
||||
* @copyright 2009 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Outputs the navigation tree.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_navigation
|
||||
* @copyright 2009 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
@block @block_navigation
|
||||
Feature: Expand the courses nodes within the navigation block
|
||||
In order to navigate the site
|
||||
As an anonymous user, a guest, a student, and an admin
|
||||
I need to expand the courses node in the navigation block and check the display of courses and categories.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@local.host |
|
||||
| student1 | Student | 1 | student1@local.host |
|
||||
And the following "categories" exist:
|
||||
| name | category | idnumber | visible |
|
||||
| cat1 | 0 | cat1 | 1 |
|
||||
| cat2 | 0 | cat2 | 1 |
|
||||
| cat21 | cat2 | cat21 | 1 |
|
||||
| cat211 | cat21 | cat211 | 1 |
|
||||
| cat3 | 0 | cat3 | 0 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category | visible |
|
||||
| Course 1 | c1 | cat1 | 1 |
|
||||
| Course 2 | c2 | cat2 | 1 |
|
||||
| Course 3 | c3 | cat21 | 1 |
|
||||
| Course 4 | c4 | cat211 | 1 |
|
||||
| Course 5 | c5 | cat211 | 0 |
|
||||
| Course 6 | c6 | cat211 | 0 |
|
||||
| Course 7 | c7 | cat3 | 1 |
|
||||
| Course 8 | c8 | cat3 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | c1 | teacher |
|
||||
| teacher1 | c3 | teacher |
|
||||
| teacher1 | c5 | teacher |
|
||||
| student1 | c1 | student |
|
||||
| student1 | c2 | student |
|
||||
| student1 | c4 | student |
|
||||
And I log in as "admin"
|
||||
And I follow "Course 2"
|
||||
And I turn editing mode on
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I set the following fields to these values:
|
||||
| Allow guest access | Yes |
|
||||
And I press "Save changes"
|
||||
And I set the following administration settings values:
|
||||
| Show all courses | 1 |
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: As an anonymous user I expand the courses node to see courses.
|
||||
When I should see "You are not logged in." in the ".logininfo" "css_element"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should not see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And navigation node "c1" should not be expandable
|
||||
And navigation node "c2" should not be expandable
|
||||
And navigation node "c3" should not be expandable
|
||||
And navigation node "c4" should not be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As the admin user I expand the courses and category nodes to see courses.
|
||||
When I log in as "admin"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I expand "cat3" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should see "c5" in the "Navigation" "block"
|
||||
And I should see "c6" in the "Navigation" "block"
|
||||
And I should see "c7" in the "Navigation" "block"
|
||||
And I should see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should be expandable
|
||||
And navigation node "c4" should be expandable
|
||||
And navigation node "c5" should be expandable
|
||||
And navigation node "c6" should be expandable
|
||||
And navigation node "c7" should be expandable
|
||||
And navigation node "c8" should be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As teacher1 I expand the courses and category nodes to see courses.
|
||||
When I log in as "teacher1"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And I should not see "c7" in the "Navigation" "block"
|
||||
And I should not see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should be expandable
|
||||
And navigation node "c4" should not be expandable
|
||||
And navigation node "c5" should be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As student1 I expand the courses and category nodes to see courses.
|
||||
When I log in as "student1"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should not see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And I should not see "c7" in the "Navigation" "block"
|
||||
And I should not see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should not be expandable
|
||||
And navigation node "c4" should be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As guest I expand the courses and category nodes to see courses.
|
||||
When I log in as "guest"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should not see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And I should not see "c7" in the "Navigation" "block"
|
||||
And I should not see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should not be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should not be expandable
|
||||
And navigation node "c4" should not be expandable
|
||||
@@ -66,3 +66,34 @@ Feature: View my courses in navigation block
|
||||
And I expand "cat33" node
|
||||
And I should see "c331" in the "Navigation" "block"
|
||||
And I should not see "c332" in the "Navigation" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: I can expand categories and courses as guest
|
||||
Given I set the following administration settings values:
|
||||
| Show my course categories | 1 |
|
||||
| Show all courses | 1 |
|
||||
And I log out
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should see "cat3" in the "Navigation" "block"
|
||||
And I should not see "cat31" in the "Navigation" "block"
|
||||
And I should not see "cat32" in the "Navigation" "block"
|
||||
And I should not see "cat331" in the "Navigation" "block"
|
||||
And I should not see "c1" in the "Navigation" "block"
|
||||
And I should not see "c2" in the "Navigation" "block"
|
||||
And I should not see "c31" in the "Navigation" "block"
|
||||
And I should not see "c32" in the "Navigation" "block"
|
||||
When I expand "cat3" node
|
||||
And I expand "cat31" node
|
||||
And I expand "cat1" node
|
||||
Then I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should see "cat3" in the "Navigation" "block"
|
||||
And I should see "cat31" in the "Navigation" "block"
|
||||
And I should see "cat32" in the "Navigation" "block"
|
||||
And I should not see "cat331" in the "Navigation" "block"
|
||||
And I should see "c1" in the "Navigation" "block"
|
||||
And I should not see "c2" in the "Navigation" "block"
|
||||
And I should see "c31" in the "Navigation" "block"
|
||||
And I should not see "c32" in the "Navigation" "block"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
@block @block_news_items
|
||||
Feature: Latest news block displays the course latest news
|
||||
In order to be aware of the course news
|
||||
As a user
|
||||
I need to see the latest news in the main course page
|
||||
|
||||
@javascript
|
||||
Scenario: Latest course news are displayed and can be configured
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@asd.com |
|
||||
And I log in as "admin"
|
||||
And I create a course with:
|
||||
| Course full name | Course 1 |
|
||||
| Course short name | C1 |
|
||||
| News items to show | 5 |
|
||||
And I enrol "Teacher 1" user as "Teacher"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
When I add a new topic to "News forum" forum with:
|
||||
| Subject | Discussion One |
|
||||
| Message | Not important |
|
||||
And I add a new topic to "News forum" forum with:
|
||||
| Subject | Discussion Two |
|
||||
| Message | Not important |
|
||||
And I add a new topic to "News forum" forum with:
|
||||
| Subject | Discussion Three |
|
||||
| Message | Not important |
|
||||
And I follow "Course 1"
|
||||
Then I should see "Discussion One" in the "Latest news" "block"
|
||||
And I should see "Discussion Two" in the "Latest news" "block"
|
||||
And I should see "Discussion Three" in the "Latest news" "block"
|
||||
And I follow "Edit settings"
|
||||
And I set the following fields to these values:
|
||||
| News items to show | 2 |
|
||||
And I press "Save changes"
|
||||
And I should not see "Discussion One" in the "Latest news" "block"
|
||||
And I should see "Discussion Two" in the "Latest news" "block"
|
||||
And I should see "Discussion Three" in the "Latest news" "block"
|
||||
And I follow "Edit settings"
|
||||
And I set the following fields to these values:
|
||||
| News items to show | 0 |
|
||||
And I press "Save changes"
|
||||
And "Latest news" "block" should not exist
|
||||
@@ -81,5 +81,8 @@ function xmldb_block_recent_activity_upgrade($oldversion, $block) {
|
||||
upgrade_block_savepoint(true, 2014012000, 'recent_activity');
|
||||
}
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* Please do not forget to use upgrade_set_timeout()
|
||||
* before any action that may take longer time to finish.
|
||||
*
|
||||
* @since 2.5
|
||||
* @since Moodle 2.5
|
||||
* @package block_section_links
|
||||
* @copyright 2013 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -83,5 +83,8 @@ function xmldb_block_section_links_upgrade($oldversion, $block) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Renderer for the section links block.
|
||||
*
|
||||
* @since 2.5
|
||||
* @since Moodle 2.5
|
||||
* @package block_section_links
|
||||
* @copyright 2013 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* Please do not forget to use upgrade_set_timeout()
|
||||
* before any action that may take longer time to finish.
|
||||
*
|
||||
* @since 2.0
|
||||
* @since Moodle 2.0
|
||||
* @package block_selfcompletion
|
||||
* @copyright 2012 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -71,5 +71,8 @@ function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user