Compare commits
485 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 | |||
| bfa6c5080e | |||
| 0f0729b157 | |||
| f75d82450a | |||
| 3dd33e3862 | |||
| e3b98ac6b6 | |||
| 3951213860 | |||
| 24b81e0566 | |||
| 0ab271dcfd | |||
| b9cb39eaf6 | |||
| c83407f033 | |||
| da75ffce68 | |||
| d48b1de9f7 | |||
| 38d1c9a886 | |||
| 1c48d7e188 | |||
| 11b39253d2 | |||
| 56e84a7985 | |||
| 133f83d557 | |||
| 17e57aa07d | |||
| 710b364b44 | |||
| 81d72831b8 | |||
| 3cfabf7190 | |||
| 0e5791a6cd | |||
| da3e5e0c5c | |||
| ae3b9e1e1f | |||
| 3485ecf225 |
@@ -35,4 +35,3 @@ composer.lock
|
||||
/lib/yuilib/*/build/*/*-coverage.js
|
||||
# lib/yuilib/version/module/module-coverage.js
|
||||
/lib/yuilib/*/*/*-coverage.js
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
@@ -142,14 +142,14 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
|
||||
$fieldname = $field;
|
||||
if ($fieldname === 'lang') {
|
||||
$fieldname = get_string('language');
|
||||
} elseif (!empty($customfields) && in_array($field, $customfields)) {
|
||||
// If custom field then pick name from database.
|
||||
$fieldshortname = str_replace('profile_field_', '', $fieldname);
|
||||
$fieldname = $customfieldname[$fieldshortname]->name;
|
||||
} elseif (preg_match('/^(.+?)(\d+)$/', $fieldname, $matches)) {
|
||||
$fieldname = get_string($matches[1]) . ' ' . $matches[2];
|
||||
} elseif ($fieldname == 'url') {
|
||||
$fieldname = get_string('webpage');
|
||||
} elseif (!empty($customfields) && in_array($field, $customfields)) {
|
||||
// If custom field then pick name from database.
|
||||
$fieldshortname = str_replace('profile_field_', '', $fieldname);
|
||||
$fieldname = $customfieldname[$fieldshortname]->name;
|
||||
} else {
|
||||
$fieldname = get_string($fieldname);
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Validate that the current db structure matches the install.xml files.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Petr Skoda <petr.skoda@totaralms.com>
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php');
|
||||
|
||||
$help = "Validate database structure
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example:
|
||||
\$ sudo -u www-data /usr/bin/php admin/cli/check_database_schema.php
|
||||
";
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array(
|
||||
'help' => false,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
)
|
||||
);
|
||||
|
||||
if ($options['help']) {
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (empty($CFG->version)) {
|
||||
echo "Database is not yet installed.\n";
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$dbmanager = $DB->get_manager();
|
||||
$schema = $dbmanager->get_install_xml_schema();
|
||||
|
||||
if (!$errors = $dbmanager->check_database_schema($schema)) {
|
||||
echo "Database structure is ok.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
foreach ($errors as $table => $items) {
|
||||
cli_separator();
|
||||
echo "$table\n";
|
||||
foreach ($items as $item) {
|
||||
echo " * $item\n";
|
||||
}
|
||||
}
|
||||
cli_separator();
|
||||
|
||||
exit(1);
|
||||
@@ -1,202 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* MySQL table row compression tool tool.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Petr Skoda <petr.skoda@totaralms.com>
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(dirname(__FILE__).'/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
|
||||
if ($DB->get_dbfamily() !== 'mysql') {
|
||||
cli_error('This script is used for MySQL databases only.');
|
||||
}
|
||||
|
||||
$engine = strtolower($DB->get_dbengine());
|
||||
if ($engine !== 'innodb' and $engine !== 'xtradb') {
|
||||
cli_error('This script is for MySQL servers using InnoDB or XtraDB engines only.');
|
||||
}
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array('help' => false, 'info' => false, 'list' => false, 'fix' => false, 'showsql' => false),
|
||||
array('h' => 'help', 'i' => 'info', 'l' => 'list', 'f' => 'fix', 's' => 'showsql')
|
||||
);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
$help =
|
||||
"Script for detection of row size problems in MySQL InnoDB tables.
|
||||
|
||||
By default InnoDB storage table is using legacy Antelope file format
|
||||
which has major restriction on database row size.
|
||||
Use this script to detect and fix database tables with potentail data
|
||||
overflow problems.
|
||||
|
||||
Options:
|
||||
-i, --info Show database information
|
||||
-l, --list List problematic tables
|
||||
-f, --fix Attempt to fix all tables (requires SUPER privilege)
|
||||
-s, --showsql Print SQL statements for fixing of tables
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_compressed_rows.php -l
|
||||
";
|
||||
|
||||
/** @var mysql_sql_generator $generator */
|
||||
$generator = $DB->get_manager()->generator;
|
||||
|
||||
$info = $DB->get_server_info();
|
||||
$filepertable = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_per_table'");
|
||||
$filepertable = $filepertable ? $filepertable->value : '';
|
||||
$fileformat = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_format'");
|
||||
$fileformat = $fileformat ? $fileformat->value : '';
|
||||
$prefix = $DB->get_prefix();
|
||||
$database = $CFG->dbname;
|
||||
|
||||
if (!empty($options['info'])) {
|
||||
echo "Database version: " . $info['description'] . "\n";
|
||||
echo "Database name: $database\n";
|
||||
echo "Database engine: " . $DB->get_dbengine() . "\n";
|
||||
echo "innodb_file_per_table: $filepertable\n";
|
||||
echo "innodb_file_format: $fileformat\n";
|
||||
|
||||
exit(0);
|
||||
|
||||
} else if (!empty($options['list'])) {
|
||||
$problem = false;
|
||||
foreach ($DB->get_tables(false) as $table) {
|
||||
$columns = $DB->get_columns($table, false);
|
||||
$size = $generator->guess_antolope_row_size($columns);
|
||||
$format = $DB->get_row_format($table);
|
||||
if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT);
|
||||
echo str_pad($format, 11, ' ', STR_PAD_RIGHT);
|
||||
|
||||
if ($format === 'Compact' or $format === 'Redundant') {
|
||||
$problem = true;
|
||||
echo " (needs fixing)\n";
|
||||
|
||||
} else if ($format !== 'Compressed' and $format !== 'Dynamic') {
|
||||
echo " (unknown)\n";
|
||||
|
||||
} else {
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($problem) {
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
|
||||
} else if (!empty($options['fix'])) {
|
||||
$fixtables = array();
|
||||
foreach ($DB->get_tables(false) as $table) {
|
||||
$columns = $DB->get_columns($table, false);
|
||||
$size = $generator->guess_antolope_row_size($columns);
|
||||
$format = $DB->get_row_format($table);
|
||||
if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
|
||||
continue;
|
||||
}
|
||||
if ($format === 'Compact' or $format === 'Redundant') {
|
||||
$fixtables[$table] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fixtables) {
|
||||
echo "No changes necessary\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($filepertable !== 'ON') {
|
||||
try {
|
||||
$DB->execute("SET GLOBAL innodb_file_per_table=1");
|
||||
} catch (dml_exception $e) {
|
||||
echo "Cannot enable GLOBAL innodb_file_per_table setting, use --showsql option and execute the statements manually.";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
if ($fileformat !== 'Barracuda') {
|
||||
try {
|
||||
$DB->execute("SET GLOBAL innodb_file_format=Barracuda");
|
||||
} catch (dml_exception $e) {
|
||||
echo "Cannot change GLOBAL innodb_file_format setting, use --showsql option and execute the statements manually.";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$DB->is_compressed_row_format_supported(false)) {
|
||||
echo "MySQL server is not compatible with compressed row format.";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
foreach ($fixtables as $table) {
|
||||
$DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
|
||||
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
} else if (!empty($options['showsql'])) {
|
||||
$fixtables = array();
|
||||
|
||||
foreach ($DB->get_tables(false) as $table) {
|
||||
$columns = $DB->get_columns($table, false);
|
||||
$size = $generator->guess_antolope_row_size($columns);
|
||||
$format = $DB->get_row_format($table);
|
||||
if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
|
||||
continue;
|
||||
}
|
||||
if ($format === 'Compact' or $format === 'Redundant') {
|
||||
$fixtables[$table] = $table;
|
||||
}
|
||||
}
|
||||
if (!$fixtables) {
|
||||
echo "No changes necessary\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
echo "Copy the following SQL statements and execute them using account with SUPER privilege:\n\n";
|
||||
echo "USE $database;\n";
|
||||
echo "SET SESSION sql_mode=STRICT_ALL_TABLES;\n";
|
||||
echo "SET GLOBAL innodb_file_per_table=1;\n";
|
||||
echo "SET GLOBAL innodb_file_format=Barracuda;\n";
|
||||
foreach ($fixtables as $table) {
|
||||
echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
|
||||
}
|
||||
echo "\n";
|
||||
exit(0);
|
||||
|
||||
} else {
|
||||
echo $help;
|
||||
die;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ admin_externalpage_setup('environment', '', $extraurlparams);
|
||||
// Handle the 'updatecomponent' action
|
||||
if ($action == 'updatecomponent' && confirm_sesskey()) {
|
||||
// Create component installer and execute it
|
||||
if ($cd = new component_installer('https://download.moodle.org',
|
||||
if ($cd = new component_installer('http://download.moodle.org',
|
||||
'environment',
|
||||
'environment.zip')) {
|
||||
$status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
|
||||
@@ -53,7 +53,7 @@ if ($action == 'updatecomponent' && confirm_sesskey()) {
|
||||
case COMPONENT_ERROR:
|
||||
if ($cd->get_error() == 'remotedownloaderror') {
|
||||
$a = new stdClass();
|
||||
$a->url = 'https://download.moodle.org/environment/environment.zip';
|
||||
$a->url = 'http://download.moodle.org/environment/environment.zip';
|
||||
$a->dest = $CFG->dataroot . '/';
|
||||
print_error($cd->get_error(), 'error', $PAGE->url, $a);
|
||||
die();
|
||||
@@ -102,7 +102,7 @@ if ($contents = load_environment_xml()) {
|
||||
}
|
||||
|
||||
// Get the results of the environment check.
|
||||
list($envstatus, $environment_results) = check_moodle_environment($version, ENV_SELECT_NEWER);
|
||||
list($envstatus, $environment_results) = check_moodle_environment($version);
|
||||
|
||||
// Display the page.
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
@@ -1136,127 +1136,4 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="2.8" requires="2.2">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.1" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.4.4" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opensslrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="intlrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
+4
-9
@@ -555,8 +555,7 @@ if (isset($SESSION->pluginuninstallreturn)) {
|
||||
// Print default admin page with notifications.
|
||||
$errorsdisplayed = defined('WARN_DISPLAY_ERRORS_ENABLED');
|
||||
|
||||
// We make the assumption that at least one schedule task should run once per day.
|
||||
$lastcron = $DB->get_field_sql('SELECT MAX(lastruntime) FROM {task_scheduled}');
|
||||
$lastcron = $DB->get_field_sql('SELECT MAX(lastcron) FROM {modules}');
|
||||
$cronoverdue = ($lastcron < time() - 3600 * 24);
|
||||
$dbproblems = $DB->diagnose();
|
||||
$maintenancemode = !empty($CFG->maintenance_enabled);
|
||||
@@ -590,14 +589,10 @@ $availableupdatesfetch = $updateschecker->get_last_timefetched();
|
||||
$buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
|
||||
//check if the site is registered on Moodle.org
|
||||
$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
|
||||
// Check if there are any cache warnings.
|
||||
$cachewarnings = cache_helper::warnings();
|
||||
|
||||
admin_externalpage_setup('adminnotifications');
|
||||
|
||||
/* @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
|
||||
$maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
|
||||
$registered, $cachewarnings);
|
||||
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
|
||||
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
|
||||
$registered);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?PHP
|
||||
|
||||
// Allows the admin to configure mnet stuff
|
||||
|
||||
|
||||
@@ -34,12 +34,21 @@ if (!defined('MOODLE_INTERNAL')) {
|
||||
}
|
||||
|
||||
$strmnetservices = get_string('mnetservices', 'mnet');
|
||||
$strmnetlog = get_string('mnetlog', 'mnet');
|
||||
$strmnetedithost = get_string('reviewhostdetails', 'mnet');
|
||||
|
||||
$logurl = $CFG->wwwroot.
|
||||
'/report/log/index.php?chooselog=1&showusers=1&showcourses=1&host_course='.$mnet_peer->id.
|
||||
'%2F1&user='.'0'.
|
||||
'&date=0'.
|
||||
'&modid=&modaction=0&logformat=showashtml';
|
||||
$tabs = array();
|
||||
if (isset($mnet_peer->id) && $mnet_peer->id > 0) {
|
||||
$tabs[] = new tabobject('mnetdetails', 'peers.php?step=update&hostid='.$mnet_peer->id, $strmnetedithost, $strmnetedithost, false);
|
||||
$tabs[] = new tabobject('mnetservices', 'services.php?hostid='.$mnet_peer->id, $strmnetservices, $strmnetservices, false);
|
||||
if ($mnet_peer->application->name == 'moodle' && $mnet_peer->id != $CFG->mnet_all_hosts_id) {
|
||||
$tabs[] = new tabobject('mnetlog', $logurl, $strmnetlog, $strmnetlog, false);
|
||||
}
|
||||
$tabs[] = new tabobject('mnetprofilefields', 'profilefields.php?hostid=' . $mnet_peer->id, get_string('profilefields', 'mnet'), get_string('profilefields', 'mnet'), false);
|
||||
} else {
|
||||
$tabs[] = new tabobject('mnetdetails', '#', $strmnetedithost, $strmnetedithost, false);
|
||||
|
||||
+18
-46
@@ -303,13 +303,12 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @param bool $buggyiconvnomb warn iconv problems
|
||||
* @param array|null $availableupdates array of \core\update\info objects or null
|
||||
* @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
|
||||
* @param string[] $cachewarnings An array containing warnings from the Cache API.
|
||||
*
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
|
||||
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
|
||||
$buggyiconvnomb, $registered, array $cachewarnings = array()) {
|
||||
$buggyiconvnomb, $registered) {
|
||||
global $CFG;
|
||||
$output = '';
|
||||
|
||||
@@ -322,7 +321,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$output .= $this->cron_overdue_warning($cronoverdue);
|
||||
$output .= $this->db_problems($dbproblems);
|
||||
$output .= $this->maintenance_mode_warning($maintenancemode);
|
||||
$output .= $this->cache_warnings($cachewarnings);
|
||||
$output .= $this->registration_warning($registered);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -597,19 +595,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
return $this->warning($dbproblems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders cache warnings if there are any.
|
||||
*
|
||||
* @param string[] $cachewarnings
|
||||
* @return string
|
||||
*/
|
||||
public function cache_warnings(array $cachewarnings) {
|
||||
if (!count($cachewarnings)) {
|
||||
return '';
|
||||
}
|
||||
return join("\n", array_map(array($this, 'warning'), $cachewarnings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an appropriate message if the site in in maintenance mode.
|
||||
* @param bool $maintenancemode
|
||||
@@ -1039,28 +1024,19 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
foreach ($plugin->get_other_required_plugins() as $component => $requiredversion) {
|
||||
$ok = true;
|
||||
$otherplugin = $pluginman->get_plugin_info($component);
|
||||
$actions = array();
|
||||
|
||||
if (is_null($otherplugin)) {
|
||||
// The required plugin is not installed.
|
||||
$class = 'requires-failed requires-missing';
|
||||
$installurl = new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $component));
|
||||
$uploadurl = new moodle_url('/admin/tool/installaddon/');
|
||||
$actions[] = html_writer::link($installurl, get_string('dependencyinstall', 'core_plugin'));
|
||||
$actions[] = html_writer::link($uploadurl, get_string('dependencyupload', 'core_plugin'));
|
||||
|
||||
$ok = false;
|
||||
} else if ($requiredversion != ANY_VERSION and $otherplugin->versiondisk < $requiredversion) {
|
||||
// The required plugin is installed but needs to be updated.
|
||||
$class = 'requires-failed requires-outdated';
|
||||
if (!$otherplugin->is_standard()) {
|
||||
$updateurl = new moodle_url($this->page->url, array('sesskey' => sesskey(), 'fetchupdates' => 1));
|
||||
$actions[] = html_writer::link($updateurl, get_string('checkforupdates', 'core_plugin'));
|
||||
}
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Already installed plugin with sufficient version.
|
||||
if ($ok) {
|
||||
$class = 'requires-ok';
|
||||
} else {
|
||||
$class = 'requires-failed';
|
||||
}
|
||||
|
||||
if ($requiredversion != ANY_VERSION) {
|
||||
@@ -1068,11 +1044,11 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
} else {
|
||||
$str = 'otherplugin';
|
||||
}
|
||||
|
||||
$componenturl = new moodle_url('https://moodle.org/plugins/view.php?plugin='.$component);
|
||||
$componenturl = html_writer::tag('a', $component, array('href' => $componenturl->out()));
|
||||
$requires[] = html_writer::tag('li',
|
||||
html_writer::div(get_string($str, 'core_plugin',
|
||||
array('component' => $component, 'version' => $requiredversion)), 'component').
|
||||
html_writer::div(implode(' | ', $actions), 'actions'),
|
||||
get_string($str, 'core_plugin',
|
||||
array('component' => $componenturl, 'version' => $requiredversion)),
|
||||
array('class' => $class));
|
||||
}
|
||||
|
||||
@@ -1394,7 +1370,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* configuration and how it suits Moodle needs.
|
||||
*
|
||||
* @param boolean $result final result of the check (true/false)
|
||||
* @param environment_results[] $environment_results array of results gathered
|
||||
* @param array $environment_results array of results gathered
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function environment_check_table($result, $environment_results) {
|
||||
@@ -1406,10 +1382,9 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
get_string('name'),
|
||||
get_string('info'),
|
||||
get_string('report'),
|
||||
get_string('plugin'),
|
||||
get_string('status'),
|
||||
);
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'leftalign plugin', 'centeralign status');
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'centeralign status');
|
||||
$servertable->attributes['class'] = 'admintable environmenttable generaltable';
|
||||
$servertable->id = 'serverstatus';
|
||||
|
||||
@@ -1419,10 +1394,9 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$othertable->head = array(
|
||||
get_string('info'),
|
||||
get_string('report'),
|
||||
get_string('plugin'),
|
||||
get_string('status'),
|
||||
);
|
||||
$othertable->colclasses = array('aligncenter info', 'alignleft report', 'alignleft plugin', 'aligncenter status');
|
||||
$othertable->colclasses = array('aligncenter info', 'alignleft report', 'aligncenter status');
|
||||
$othertable->attributes['class'] = 'admintable environmenttable generaltable';
|
||||
$othertable->id = 'otherserverstatus';
|
||||
|
||||
@@ -1438,7 +1412,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$type = $environment_result->getPart();
|
||||
$info = $environment_result->getInfo();
|
||||
$status = $environment_result->getStatus();
|
||||
$plugin = $environment_result->getPluginName();
|
||||
$error_code = $environment_result->getErrorCode();
|
||||
// Process Report field
|
||||
$rec = new stdClass();
|
||||
@@ -1515,8 +1488,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
if (!empty($info)){
|
||||
$linkparts[] = $info;
|
||||
}
|
||||
// Plugin environments do not have docs pages yet.
|
||||
if (empty($CFG->docroot) or $environment_result->plugin) {
|
||||
if (empty($CFG->docroot)) {
|
||||
$report = get_string($stringtouse, 'admin', $rec);
|
||||
} else {
|
||||
$report = $this->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec));
|
||||
@@ -1542,9 +1514,9 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
// Add the row to the table
|
||||
if ($environment_result->getPart() == 'custom_check'){
|
||||
$otherdata[$messagetype][] = array ($info, $report, $plugin, $status);
|
||||
$otherdata[$messagetype][] = array ($info, $report, $status);
|
||||
} else {
|
||||
$serverdata[$messagetype][] = array ($type, $info, $report, $plugin, $status);
|
||||
$serverdata[$messagetype][] = array ($type, $info, $report, $status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,12 +48,11 @@ class core_role_potential_assignees_below_course extends core_role_assign_user_s
|
||||
$fields = 'SELECT ' . $this->required_fields_sql('u');
|
||||
$countfields = 'SELECT COUNT(u.id)';
|
||||
|
||||
$sql = " FROM ($enrolsql) enrolled_users_view
|
||||
JOIN {user} u ON u.id = enrolled_users_view.id
|
||||
LEFT JOIN {role_assignments} ra ON (ra.userid = enrolled_users_view.id AND
|
||||
ra.roleid = :roleid AND ra.contextid = :contextid)
|
||||
WHERE ra.id IS NULL
|
||||
$wherecondition";
|
||||
$sql = " FROM {user} u
|
||||
LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
|
||||
WHERE u.id IN ($enrolsql)
|
||||
$wherecondition
|
||||
AND ra.id IS NULL";
|
||||
$params['contextid'] = $this->context->id;
|
||||
$params['roleid'] = $this->roleid;
|
||||
|
||||
|
||||
@@ -122,7 +122,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
$temp->add(new admin_setting_configcheckbox('navshowcategories', new lang_string('navshowcategories', 'admin'), new lang_string('confignavshowcategories', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('navshowmycoursecategories', new lang_string('navshowmycoursecategories', 'admin'), new lang_string('navshowmycoursecategories_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('navshowallcourses', new lang_string('navshowallcourses', 'admin'), new lang_string('confignavshowallcourses', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('navexpandmycourses', new lang_string('navexpandmycourses', 'admin'), new lang_string('navexpandmycourses_desc', 'admin'), 1));
|
||||
$sortoptions = array(
|
||||
'sortorder' => new lang_string('sort_sortorder', 'admin'),
|
||||
'fullname' => new lang_string('sort_fullname', 'admin'),
|
||||
|
||||
@@ -11,6 +11,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
//TODO: Re-enable cc-import once re-implemented in 2.0.x
|
||||
//$temp->add(new admin_setting_configcheckbox('enableimsccimport', new lang_string('enable_cc_import', 'imscc'), new lang_string('enable_cc_import_description', 'imscc'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('enablesafebrowserintegration', new lang_string('enablesafebrowserintegration', 'admin'), new lang_string('configenablesafebrowserintegration', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('enablegroupmembersonly', new lang_string('enablegroupmembersonly', 'admin'), new lang_string('configenablegroupmembersonly', 'admin'), 0));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('dndallowtextandlinks', new lang_string('dndallowtextandlinks', 'admin'), new lang_string('configdndallowtextandlinks', 'admin'), 0));
|
||||
// The CSS optimiser setting. When changed we need to reset the theme caches in order to ensure they are regenerated through the optimiser.
|
||||
|
||||
@@ -68,10 +68,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
$temp->add(new admin_setting_special_gradelimiting());
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('grade_report_showmin',
|
||||
get_string('minimum_show', 'grades'),
|
||||
get_string('minimum_show_help', 'grades'), '1'));
|
||||
|
||||
$temp->add(new admin_setting_special_gradepointmax());
|
||||
|
||||
$temp->add(new admin_setting_special_gradepointdefault());
|
||||
@@ -96,9 +92,11 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
GRADE_AGGREGATE_MODE =>new lang_string('aggregatemode', 'grades'),
|
||||
GRADE_AGGREGATE_SUM =>new lang_string('aggregatesum', 'grades'));
|
||||
|
||||
$defaultvisible = array(GRADE_AGGREGATE_SUM);
|
||||
$defaultvisible = array(GRADE_AGGREGATE_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN2,
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN, GRADE_AGGREGATE_MEDIAN, GRADE_AGGREGATE_MIN,
|
||||
GRADE_AGGREGATE_MAX, GRADE_AGGREGATE_MODE, GRADE_AGGREGATE_SUM);
|
||||
|
||||
$defaults = array('value' => GRADE_AGGREGATE_SUM, 'forced' => false, 'adv' => false);
|
||||
$defaults = array('value'=>GRADE_AGGREGATE_WEIGHTED_MEAN2, 'forced'=>false, 'adv'=>false);
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregation', new lang_string('aggregation', 'grades'), new lang_string('aggregation_help', 'grades'), $defaults, $options));
|
||||
|
||||
$temp->add(new admin_setting_configmultiselect('grade_aggregations_visible', new lang_string('aggregationsvisible', 'grades'),
|
||||
@@ -127,9 +125,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
$defaults['forced'] = false;
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_droplow', new lang_string('droplow', 'grades'),
|
||||
new lang_string('droplow_help', 'grades'), $defaults, $options));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('grade_overridecat', new lang_string('overridecat', 'grades'),
|
||||
new lang_string('overridecat_help', 'grades'), 1));
|
||||
}
|
||||
$ADMIN->add('grades', $temp);
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
|
||||
2 => get_string('showmarkandmax', 'question'),
|
||||
);
|
||||
$settings->add(new admin_setting_configselect('question_preview/marks',
|
||||
get_string('marks', 'question'), '', 2, $marksoptions));
|
||||
get_string('marks', 'question'), '', 1, $marksoptions));
|
||||
|
||||
$settings->add(new admin_setting_configselect('question_preview/markdp',
|
||||
get_string('decimalplacesingrades', 'question'), '', 2, array(0, 1, 2, 3, 4, 5, 6, 7)));
|
||||
|
||||
@@ -11,7 +11,6 @@ $temp = new admin_settingpage('systempaths', new lang_string('systempaths','admi
|
||||
$temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('pathtodu', 'admin'), new lang_string('configpathtodu', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'), new lang_string('edhelpaspellpath'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'), new lang_string('pathtodot_help', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'), new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
@@ -24,44 +24,6 @@ if ($hassiteconfig
|
||||
$ADMIN->add('accounts', new admin_externalpage('editusers', new lang_string('userlist','admin'), "$CFG->wwwroot/$CFG->admin/user.php", array('moodle/user:update', 'moodle/user:delete')));
|
||||
$ADMIN->add('accounts', new admin_externalpage('userbulk', new lang_string('userbulk','admin'), "$CFG->wwwroot/$CFG->admin/user/user_bulk.php", array('moodle/user:update', 'moodle/user:delete')));
|
||||
$ADMIN->add('accounts', new admin_externalpage('addnewuser', new lang_string('addnewuser'), "$securewwwroot/user/editadvanced.php?id=-1", 'moodle/user:create'));
|
||||
|
||||
// "User default preferences" settingpage.
|
||||
$temp = new admin_settingpage('userdefaultpreferences', new lang_string('userdefaultpreferences', 'admin'));
|
||||
if ($ADMIN->fulltree) {
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('emaildisplayno');
|
||||
$choices['1'] = new lang_string('emaildisplayyes');
|
||||
$choices['2'] = new lang_string('emaildisplaycourse');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_maildisplay', new lang_string('emaildisplay'),
|
||||
'', 2, $choices));
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('textformat');
|
||||
$choices['1'] = new lang_string('htmlformat');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_mailformat', new lang_string('emailformat'), '', 1, $choices));
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('emaildigestoff');
|
||||
$choices['1'] = new lang_string('emaildigestcomplete');
|
||||
$choices['2'] = new lang_string('emaildigestsubjects');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_maildigest', new lang_string('emaildigest'),
|
||||
new lang_string('emaildigest_help'), 0, $choices));
|
||||
|
||||
|
||||
$choices = array();
|
||||
$choices['1'] = new lang_string('autosubscribeyes');
|
||||
$choices['0'] = new lang_string('autosubscribeno');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_autosubscribe', new lang_string('autosubscribe'),
|
||||
'', 1, $choices));
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('trackforumsno');
|
||||
$choices['1'] = new lang_string('trackforumsyes');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_trackforums', new lang_string('trackforums'),
|
||||
'', 0, $choices));
|
||||
}
|
||||
$ADMIN->add('accounts', $temp);
|
||||
|
||||
$ADMIN->add('accounts', new admin_externalpage('profilefields', new lang_string('profilefields','admin'), "$CFG->wwwroot/user/profile/index.php", 'moodle/site:config'));
|
||||
$ADMIN->add('accounts', new admin_externalpage('cohorts', new lang_string('cohorts', 'cohort'), $CFG->wwwroot . '/cohort/index.php', array('moodle/cohort:manage', 'moodle/cohort:view')));
|
||||
|
||||
@@ -190,9 +152,6 @@ if ($hassiteconfig
|
||||
'institution' => new lang_string('institution'),
|
||||
)));
|
||||
$temp->add(new admin_setting_configtext('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'), new lang_string('configfullnamedisplay', 'admin'), 'language', PARAM_TEXT, 50));
|
||||
$temp->add(new admin_setting_configtext('alternativefullnameformat', new lang_string('alternativefullnameformat', 'admin'),
|
||||
new lang_string('alternativefullnameformat_desc', 'admin'),
|
||||
'language', PARAM_RAW, 50));
|
||||
$temp->add(new admin_setting_configtext('maxusersperpage', new lang_string('maxusersperpage','admin'), new lang_string('configmaxusersperpage','admin'), 100, PARAM_INT));
|
||||
$temp->add(new admin_setting_configcheckbox('enablegravatar', new lang_string('enablegravatar', 'admin'), new lang_string('enablegravatar_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configtext('gravatardefaulturl', new lang_string('gravatardefaulturl', 'admin'), new lang_string('gravatardefaulturl_help', 'admin'), 'mm'));
|
||||
|
||||
@@ -252,58 +252,3 @@ Feature: Set up contextual data for tests
|
||||
And the "members" select box should contain "Student 1"
|
||||
And I set the field "groups" to "Group 2 (1)"
|
||||
And the "members" select box should contain "Student 2"
|
||||
|
||||
Scenario: Add cohorts and cohort members with data generator
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@asd.com |
|
||||
| student2 | Student | 2 | student2@asd.com |
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber |
|
||||
| System cohort A | CHSA |
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber | contextlevel | reference |
|
||||
| System cohort B | CHSB | System | |
|
||||
| Cohort in category | CHC | Category | CAT1 |
|
||||
| Empty cohort | CHE | Category | CAT1 |
|
||||
And the following "cohort members" exist:
|
||||
| user | cohort |
|
||||
| student1 | CHSA |
|
||||
| student2 | CHSB |
|
||||
| student1 | CHSB |
|
||||
| student1 | CHC |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Cohorts" node in "Site administration > Users > Accounts"
|
||||
Then the following should exist in the "cohorts" table:
|
||||
| Name | Cohort size |
|
||||
| System cohort A | 1 |
|
||||
| System cohort B | 2 |
|
||||
And I should not see "Cohort in category"
|
||||
And I follow "Courses"
|
||||
And I follow "Cat 1"
|
||||
And I follow "Cohorts"
|
||||
And I should not see "System cohort"
|
||||
And the following should exist in the "cohorts" table:
|
||||
| Name | Cohort size |
|
||||
| Cohort in category | 1 |
|
||||
| Empty cohort | 0 |
|
||||
|
||||
Scenario: Add grade categories with data generator
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course |
|
||||
| Grade category 1 | C1|
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course | gradecategory |
|
||||
| Grade sub category 2 | C1 | Grade category 1|
|
||||
When I log in as "admin"
|
||||
And I follow "Courses"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
Then I should see "Grade category 1"
|
||||
And I should see "Grade sub category 2"
|
||||
|
||||
@@ -159,7 +159,6 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I add a "Lesson" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson |
|
||||
| Description | Test lesson description |
|
||||
| available[enabled] | 1 |
|
||||
And I set the field "deadline[enabled]" to "1"
|
||||
# Checkbox (AJAX) - Checking "the field matches value" before saving.
|
||||
|
||||
@@ -11,7 +11,6 @@ Feature: Forms manipulation
|
||||
When I set the field "First name" to "Field value"
|
||||
And I set the field "Text editor" to "Plain text area"
|
||||
And I set the field "Unmask" to "1"
|
||||
And I expand all fieldsets
|
||||
Then the field "First name" matches value "Field value"
|
||||
And the "Text editor" select box should contain "Plain text area"
|
||||
And the field "Unmask" matches value "1"
|
||||
|
||||
@@ -36,10 +36,6 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
* @var array Number of sections in course
|
||||
*/
|
||||
private static $paramsections = array(1, 10, 100, 500, 1000, 2000);
|
||||
/**
|
||||
* @var array Number of assignments in course
|
||||
*/
|
||||
private static $paramassignments = array(1, 10, 100, 500, 1000, 2000);
|
||||
/**
|
||||
* @var array Number of Page activities in course
|
||||
*/
|
||||
@@ -183,7 +179,6 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
// Make course.
|
||||
$this->course = $this->create_course();
|
||||
$this->create_users();
|
||||
$this->create_assignments();
|
||||
$this->create_pages();
|
||||
$this->create_small_files();
|
||||
$this->create_big_files();
|
||||
@@ -323,26 +318,6 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
$this->end_log();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a number of Assignment activities.
|
||||
*/
|
||||
private function create_assignments() {
|
||||
// Set up generator.
|
||||
$assigngenerator = $this->generator->get_plugin_generator('mod_assign');
|
||||
|
||||
// Create assignments.
|
||||
$number = self::$paramassignments[$this->size];
|
||||
$this->log('createassignments', $number, true);
|
||||
for ($i = 0; $i < $number; $i++) {
|
||||
$record = array('course' => $this->course);
|
||||
$options = array('section' => $this->get_target_section());
|
||||
$assigngenerator->create_instance($record, $options);
|
||||
$this->dot($i, $number);
|
||||
}
|
||||
|
||||
$this->end_log();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a number of Page activities.
|
||||
*/
|
||||
|
||||
@@ -71,7 +71,6 @@ $string['pluginname'] = 'Development data generator';
|
||||
$string['progress_checkaccounts'] = 'Checking user accounts ({$a})';
|
||||
$string['progress_coursecompleted'] = 'Course completed ({$a}s)';
|
||||
$string['progress_createaccounts'] = 'Creating user accounts ({$a->from} - {$a->to})';
|
||||
$string['progress_createassignments'] = 'Creating assignments ({$a})';
|
||||
$string['progress_createbigfiles'] = 'Creating big files ({$a})';
|
||||
$string['progress_createcourse'] = 'Creating course {$a}';
|
||||
$string['progress_createforum'] = 'Creating forum ({$a} posts)';
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Lang import controller
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
/**
|
||||
* Lang import controller
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class controller {
|
||||
/** @var array list of informational messages */
|
||||
public $info;
|
||||
/** @var array list of error messages */
|
||||
public $errors;
|
||||
/** @var \lang_installer */
|
||||
private $installer;
|
||||
/** @var array languages available on the remote server */
|
||||
public $availablelangs;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
make_temp_directory('');
|
||||
make_upload_directory('lang');
|
||||
|
||||
$this->info = array();
|
||||
$this->errors = array();
|
||||
$this->installer = new \lang_installer();
|
||||
|
||||
$this->availablelangs = $this->installer->get_remote_list_of_languages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Install language packs provided
|
||||
*
|
||||
* @param string|array $langs array of langcodes or individual langcodes
|
||||
* @param bool $updating true if updating the langpacks
|
||||
* @return int false if an error encountered or
|
||||
* @throws \moodle_exception when error is encountered installing langpack
|
||||
*/
|
||||
public function install_languagepacks($langs, $updating = false) {
|
||||
global $CFG;
|
||||
|
||||
$this->installer->set_queue($langs);
|
||||
$results = $this->installer->run();
|
||||
|
||||
$updatedpacks = 0;
|
||||
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
switch ($langstatus) {
|
||||
case \lang_installer::RESULT_DOWNLOADERROR:
|
||||
$a = new \stdClass();
|
||||
$a->url = $this->installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
$this->errors[] = get_string('remotedownloaderror', 'error', $a);
|
||||
throw new \moodle_exception('remotedownloaderror', 'error', $a);
|
||||
break;
|
||||
case \lang_installer::RESULT_INSTALLED:
|
||||
$updatedpacks++;
|
||||
if ($updating) {
|
||||
event\langpack_updated::event_with_langcode($langcode)->trigger();
|
||||
$this->info[] = get_string('langpackupdated', 'tool_langimport', $langcode);
|
||||
} else {
|
||||
$this->info[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
|
||||
event\langpack_imported::event_with_langcode($langcode)->trigger();
|
||||
}
|
||||
break;
|
||||
case \lang_installer::RESULT_UPTODATE:
|
||||
$this->info[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $updatedpacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall language pack
|
||||
*
|
||||
* @param string $lang language code
|
||||
* @return bool true if language succesfull installed
|
||||
*/
|
||||
public function uninstall_language($lang) {
|
||||
global $CFG;
|
||||
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$lang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$lang;
|
||||
$rm1 = false;
|
||||
$rm2 = false;
|
||||
if (file_exists($dest1)) {
|
||||
$rm1 = remove_dir($dest1);
|
||||
}
|
||||
if (file_exists($dest2)) {
|
||||
$rm2 = remove_dir($dest2);
|
||||
}
|
||||
|
||||
if ($rm1 or $rm2) {
|
||||
$this->info[] = get_string('langpackremoved', 'tool_langimport', $lang);
|
||||
event\langpack_removed::event_with_langcode($lang)->trigger();
|
||||
return true;
|
||||
} else { // Nothing deleted, possibly due to permission error.
|
||||
$this->errors[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated all install language packs with the latest found on servre
|
||||
*
|
||||
* @return bool true if languages succesfully updated.
|
||||
*/
|
||||
public function update_all_installed_languages() {
|
||||
global $CFG;
|
||||
|
||||
if (!$availablelangs = $this->installer->get_remote_list_of_languages()) {
|
||||
$this->errors[] = get_string('cannotdownloadlanguageupdatelist', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
$md5array = array(); // Convert to (string)langcode => (string)md5.
|
||||
foreach ($availablelangs as $alang) {
|
||||
$md5array[$alang[0]] = $alang[1];
|
||||
}
|
||||
|
||||
// Filter out unofficial packs.
|
||||
$currentlangs = array_keys(get_string_manager()->get_list_of_translations(true));
|
||||
$updateablelangs = array();
|
||||
foreach ($currentlangs as $clang) {
|
||||
if (!array_key_exists($clang, $md5array)) {
|
||||
$noticeok[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
|
||||
continue;
|
||||
}
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$clang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$clang;
|
||||
|
||||
if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')) {
|
||||
$updateablelangs[] = $clang;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out packs that have the same md5 key.
|
||||
$neededlangs = array();
|
||||
foreach ($updateablelangs as $ulang) {
|
||||
if (!$this->is_installed_lang($ulang, $md5array[$ulang])) {
|
||||
$neededlangs[] = $ulang;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean-up currently installed versions of the packs.
|
||||
foreach ($neededlangs as $packindex => $pack) {
|
||||
if ($pack == 'en') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete old directories.
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$pack;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$pack;
|
||||
if (file_exists($dest1)) {
|
||||
if (!remove_dir($dest1)) {
|
||||
$noticeerror[] = 'Could not delete old directory '.$dest1.', update of '.$pack
|
||||
.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (file_exists($dest2)) {
|
||||
if (!remove_dir($dest2)) {
|
||||
$noticeerror[] = 'Could not delete old directory '.$dest2.', update of '.$pack
|
||||
.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$updated = $this->install_languagepacks($neededlangs, true);
|
||||
} catch (\moodle_exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($updated) {
|
||||
$this->info[] = get_string('langupdatecomplete', 'tool_langimport');
|
||||
} else {
|
||||
$this->info[] = get_string('nolangupdateneeded', 'tool_langimport');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the md5 of the zip file, grabbed from download.moodle.org,
|
||||
* against the md5 of the local language file from last update
|
||||
* @param string $lang language code
|
||||
* @param string $md5check md5 to check
|
||||
* @return bool true if installed
|
||||
*/
|
||||
public function is_installed_lang($lang, $md5check) {
|
||||
global $CFG;
|
||||
$md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
|
||||
if (file_exists($md5file)) {
|
||||
return (file_get_contents($md5file) == $md5check);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The langimport langpack imported event.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_langimport langpack imported event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string langcode: the langpage pack code.
|
||||
* }
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class langpack_imported extends \core\event\base {
|
||||
/**
|
||||
* Create instance of event.
|
||||
*
|
||||
* @param string $langcode
|
||||
* @return langpack_updated
|
||||
*/
|
||||
public static function event_with_langcode($langcode) {
|
||||
$data = array(
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'langcode' => $langcode,
|
||||
)
|
||||
);
|
||||
|
||||
return self::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The language pack '{$this->other['langcode']}' was installed.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('langpackinstalledevent', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relevant URL.
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/langimport/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['langcode'])) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set');
|
||||
}
|
||||
// We can't use PARAM_LANG here as the string manager might not be aware of langpack yet.
|
||||
$cleanedlang = clean_param($this->other['langcode'], PARAM_SAFEDIR);
|
||||
if ($cleanedlang !== $this->other['langcode']) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The langimport langpack removed event.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_langimport langpack removed event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string langcode: the langpage pack code.
|
||||
* }
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class langpack_removed extends \core\event\base {
|
||||
/**
|
||||
* Create instance of event.
|
||||
*
|
||||
* @param string $langcode
|
||||
* @return langpack_updated
|
||||
*/
|
||||
public static function event_with_langcode($langcode) {
|
||||
$data = array(
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'langcode' => $langcode,
|
||||
)
|
||||
);
|
||||
|
||||
return self::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The language pack '{$this->other['langcode']}' was removed.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relevant URL.
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/langimport/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('langpackremovedevent', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['langcode'])) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set');
|
||||
}
|
||||
|
||||
// We can't use PARAM_LANG here as it queries installed strings.
|
||||
$cleanedlang = clean_param($this->other['langcode'], PARAM_SAFEDIR);
|
||||
if ($cleanedlang !== $this->other['langcode']) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The langimport langpack updated event.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_langimport langpack updated event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string langcode: the langpage pack code.
|
||||
* }
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class langpack_updated extends \core\event\base {
|
||||
/**
|
||||
* Create instance of event.
|
||||
*
|
||||
* @param string $langcode
|
||||
* @return langpack_updated
|
||||
*/
|
||||
public static function event_with_langcode($langcode) {
|
||||
$data = array(
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'langcode' => $langcode,
|
||||
)
|
||||
);
|
||||
|
||||
return self::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The language pack '{$this->other['langcode']}' was updated.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('langpackupdatedevent', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relevant URL.
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/langimport/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['langcode'])) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set');
|
||||
}
|
||||
|
||||
$cleanedlang = clean_param($this->other['langcode'], PARAM_LANG);
|
||||
if ($cleanedlang !== $this->other['langcode']) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A scheduled task for updating langpacks.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_langimport\task;
|
||||
|
||||
/**
|
||||
* A scheduled task for updating langpacks.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class update_langpacks_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('updatelangs', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run langpack update
|
||||
*/
|
||||
public function execute() {
|
||||
$controller = new \tool_langimport\controller();
|
||||
if ($controller->update_all_installed_languages()) {
|
||||
foreach ($controller->info as $message) {
|
||||
mtrace($message);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
foreach ($controller->errors as $message) {
|
||||
mtrace($message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+166
-15
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Fetches language packages from download.moodle.org server
|
||||
*
|
||||
* Language packages are available at https://download.moodle.org/langpack/
|
||||
* Language packages are available at http://download.moodle.org/langpack/
|
||||
* in ZIP format together with a file languages.md5 containing their hashes
|
||||
* and meta info.
|
||||
* Locally, language packs are saved into $CFG->dataroot/lang/
|
||||
@@ -28,8 +28,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require(__DIR__.'/../../../config.php');
|
||||
require(dirname(dirname(dirname(dirname(__FILE__)))) . '/config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
admin_externalpage_setup('toollangimport');
|
||||
|
||||
@@ -63,17 +65,37 @@ define('UPDATE_ALL_LANG', 5);
|
||||
|
||||
get_string_manager()->reset_caches();
|
||||
|
||||
$controller = new tool_langimport\controller();
|
||||
$notice_ok = array();
|
||||
$notice_error = array();
|
||||
|
||||
if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($pack)) {
|
||||
core_php_time_limit::raise();
|
||||
$controller->install_languagepacks($pack);
|
||||
make_temp_directory('');
|
||||
make_upload_directory('lang');
|
||||
|
||||
$installer = new lang_installer($pack);
|
||||
$results = $installer->run();
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
switch ($langstatus) {
|
||||
case lang_installer::RESULT_DOWNLOADERROR:
|
||||
$a = new stdClass();
|
||||
$a->url = $installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
print_error('remotedownloaderror', 'error', 'index.php', $a);
|
||||
break;
|
||||
case lang_installer::RESULT_INSTALLED:
|
||||
$notice_ok[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
|
||||
break;
|
||||
case lang_installer::RESULT_UPTODATE:
|
||||
$notice_ok[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
|
||||
if ($uninstalllang == 'en') {
|
||||
// TODO.
|
||||
$controller->errors[] = 'English language pack can not be uninstalled';
|
||||
$notice_error[] = 'English language pack can not be uninstalled';
|
||||
|
||||
} else if (!$confirm and confirm_sesskey()) {
|
||||
echo $OUTPUT->header();
|
||||
@@ -84,13 +106,120 @@ if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
|
||||
die;
|
||||
|
||||
} else if (confirm_sesskey()) {
|
||||
$controller->uninstall_language($uninstalllang);
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$uninstalllang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$uninstalllang;
|
||||
$rm1 = false;
|
||||
$rm2 = false;
|
||||
if (file_exists($dest1)){
|
||||
$rm1 = remove_dir($dest1);
|
||||
}
|
||||
if (file_exists($dest2)){
|
||||
$rm2 = remove_dir($dest2);
|
||||
}
|
||||
if ($rm1 or $rm2) {
|
||||
$notice_ok[] = get_string('langpackremoved', 'tool_langimport');
|
||||
} else { //nothing deleted, possibly due to permission error
|
||||
$notice_error[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode == UPDATE_ALL_LANG) {
|
||||
core_php_time_limit::raise();
|
||||
$controller->update_all_installed_languages();
|
||||
|
||||
$installer = new lang_installer();
|
||||
|
||||
if (!$availablelangs = $installer->get_remote_list_of_languages()) {
|
||||
print_error('cannotdownloadlanguageupdatelist', 'error');
|
||||
}
|
||||
$md5array = array(); // (string)langcode => (string)md5
|
||||
foreach ($availablelangs as $alang) {
|
||||
$md5array[$alang[0]] = $alang[1];
|
||||
}
|
||||
|
||||
// filter out unofficial packs
|
||||
$currentlangs = array_keys(get_string_manager()->get_list_of_translations(true));
|
||||
$updateablelangs = array();
|
||||
foreach ($currentlangs as $clang) {
|
||||
if (!array_key_exists($clang, $md5array)) {
|
||||
$notice_ok[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
|
||||
continue;
|
||||
}
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$clang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$clang;
|
||||
|
||||
if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')){
|
||||
$updateablelangs[] = $clang;
|
||||
}
|
||||
}
|
||||
|
||||
// then filter out packs that have the same md5 key
|
||||
$neededlangs = array(); // all the packs that needs updating
|
||||
foreach ($updateablelangs as $ulang) {
|
||||
if (!is_installed_lang($ulang, $md5array[$ulang])) {
|
||||
$neededlangs[] = $ulang;
|
||||
}
|
||||
}
|
||||
|
||||
make_temp_directory('');
|
||||
make_upload_directory('lang');
|
||||
|
||||
// clean-up currently installed versions of the packs
|
||||
foreach ($neededlangs as $packindex => $pack) {
|
||||
if ($pack == 'en') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// delete old directories
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$pack;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$pack;
|
||||
$rm1 = false;
|
||||
$rm2 = false;
|
||||
if (file_exists($dest1)) {
|
||||
if (!remove_dir($dest1)) {
|
||||
$notice_error[] = 'Could not delete old directory '.$dest1.', update of '.$pack.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (file_exists($dest2)) {
|
||||
if (!remove_dir($dest2)) {
|
||||
$notice_error[] = 'Could not delete old directory '.$dest2.', update of '.$pack.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// install all needed language packs
|
||||
$installer->set_queue($neededlangs);
|
||||
$results = $installer->run();
|
||||
$updated = false; // any packs updated?
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
switch ($langstatus) {
|
||||
case lang_installer::RESULT_DOWNLOADERROR:
|
||||
$a = new stdClass();
|
||||
$a->url = $installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
print_error('remotedownloaderror', 'error', 'index.php', $a);
|
||||
break;
|
||||
case lang_installer::RESULT_INSTALLED:
|
||||
$updated = true;
|
||||
$notice_ok[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
|
||||
break;
|
||||
case lang_installer::RESULT_UPTODATE:
|
||||
$notice_ok[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($updated) {
|
||||
$notice_ok[] = get_string('langupdatecomplete', 'tool_langimport');
|
||||
} else {
|
||||
$notice_ok[] = get_string('nolangupdateneeded', 'tool_langimport');
|
||||
}
|
||||
|
||||
unset($installer);
|
||||
}
|
||||
get_string_manager()->reset_caches();
|
||||
|
||||
@@ -110,7 +239,9 @@ foreach ($installedlangs as $installedlang => $unused) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($availablelangs = $controller->availablelangs) {
|
||||
$installer = new lang_installer();
|
||||
|
||||
if ($availablelangs = $installer->get_remote_list_of_languages()) {
|
||||
$remote = true;
|
||||
} else {
|
||||
$remote = false;
|
||||
@@ -120,18 +251,18 @@ if ($availablelangs = $controller->availablelangs) {
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
if ($controller->info) {
|
||||
$info = implode('<br />', $controller->info);
|
||||
if ($notice_ok) {
|
||||
$info = implode('<br />', $notice_ok);
|
||||
echo $OUTPUT->notification($info, 'notifysuccess');
|
||||
}
|
||||
|
||||
if ($controller->errors) {
|
||||
$info = implode('<br />', $controller->errors);
|
||||
if ($notice_error) {
|
||||
$info = implode('<br />', $notice_error);
|
||||
echo $OUTPUT->notification($info, 'notifyproblem');
|
||||
}
|
||||
|
||||
if ($missingparents) {
|
||||
foreach ($missingparents as $l => $parent) {
|
||||
foreach ($missingparents as $l=>$parent) {
|
||||
$a = new stdClass();
|
||||
$a->lang = $installedlangs[$l];
|
||||
$a->parent = $parent;
|
||||
@@ -175,7 +306,7 @@ echo html_writer::end_tag('td');
|
||||
// list of available languages
|
||||
$options = array();
|
||||
foreach ($availablelangs as $alang) {
|
||||
if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !$controller->is_installed_lang($alang[0], $alang[1])) {
|
||||
if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !is_installed_lang($alang[0], $alang[1])) {
|
||||
$options[$alang[0]] = $alang[2].' ('.$alang[0].')';
|
||||
}
|
||||
}
|
||||
@@ -200,3 +331,23 @@ echo html_writer::end_tag('table');
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Local functions /////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* checks the md5 of the zip file, grabbed from download.moodle.org,
|
||||
* against the md5 of the local language file from last update
|
||||
* @param string $lang
|
||||
* @param string $md5check
|
||||
* @return bool
|
||||
*/
|
||||
function is_installed_lang($lang, $md5check) {
|
||||
global $CFG;
|
||||
$md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
|
||||
if (file_exists($md5file)){
|
||||
return (file_get_contents($md5file) == $md5check);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,21 +27,17 @@ $string['install'] = 'Install selected language pack(s)';
|
||||
$string['installedlangs'] = 'Installed language packs';
|
||||
$string['langimport'] = 'Language import utility';
|
||||
$string['langimportdisabled'] = 'Language import feature has been disabled. You have to update your language packs manually at the file-system level. Do not forget to purge string caches after you do so.';
|
||||
$string['langpackinstalled'] = 'Language pack \'{$a}\' was successfully installed';
|
||||
$string['langpackinstalledevent'] = 'Language pack installed';
|
||||
$string['langpackremoved'] = 'Language pack \'{$a}\' was uninstalled';
|
||||
$string['langpackremovedevent'] = 'Language pack uninstalled';
|
||||
$string['langpackupdateskipped'] = 'Update of \'{$a}\' language pack skipped';
|
||||
$string['langpackuptodate'] = 'Language pack \'{$a}\' is up-to-date';
|
||||
$string['langpackupdated'] = 'Language pack \'{$a}\' was successfully updated';
|
||||
$string['langpackupdatedevent'] = 'Language pack updated';
|
||||
$string['langpackinstalled'] = 'Language pack {$a} was successfully installed';
|
||||
$string['langpackremoved'] = 'Language pack was uninstalled';
|
||||
$string['langpackupdateskipped'] = 'Update of {$a} language pack skipped';
|
||||
$string['langpackuptodate'] = 'Language pack {$a} is up-to-date';
|
||||
$string['langupdatecomplete'] = 'Language pack update completed';
|
||||
$string['missingcfglangotherroot'] = 'Missing configuration value $CFG->langotherroot';
|
||||
$string['missinglangparent'] = 'Missing parent language <em>{$a->parent}</em> of <em>{$a->lang}</em>.';
|
||||
$string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed';
|
||||
$string['pluginname'] = 'Language packs';
|
||||
$string['purgestringcaches'] = 'Purge string caches';
|
||||
$string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="https://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
|
||||
$string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="http://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
|
||||
$string['uninstall'] = 'Uninstall selected language pack';
|
||||
$string['uninstallconfirm'] = 'You are about to completely uninstall language pack {$a}, are you sure?';
|
||||
$string['updatelangs'] = 'Update all installed language packs';
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Behat steps definitions for Language import tool
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
|
||||
use Moodle\BehatExtension\Exception\SkippedException;
|
||||
|
||||
/**
|
||||
* Steps definitions related with the Language import tool
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_tool_langimport extends behat_base {
|
||||
|
||||
/**
|
||||
* This step looks to see if the remote language import tests should be run (indicated by
|
||||
* setting TOOL_LANGIMPORT_REMOTE_TESTS in config.php.
|
||||
*
|
||||
* @Given /^remote langimport tests are enabled$/
|
||||
*/
|
||||
public function remote_langimport_tests_are_enabled() {
|
||||
if (!defined('TOOL_LANGIMPORT_REMOTE_TESTS')) {
|
||||
throw new SkippedException('To run the remote langimport tests you must '.
|
||||
'define TOOL_LANGIMPORT_REMOTE_TESTS in config.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a langpack and fakes it being outdated
|
||||
*
|
||||
* @param string $langcode The language code (e.g. en)
|
||||
* @Given /^outdated langpack \'([^\']*)\' is installed$/
|
||||
*/
|
||||
public function outdated_langpack_is_installed($langcode) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
// Download the langpack.
|
||||
$dir = make_upload_directory('lang');
|
||||
$installer = new lang_installer($langcode);
|
||||
$result = $installer->run();
|
||||
|
||||
if ($result[$langcode] !== lang_installer::RESULT_INSTALLED) {
|
||||
throw new coding_exception("Failed to install langpack '$langcode'");
|
||||
}
|
||||
|
||||
$path = "$dir/$langcode/$langcode.md5";
|
||||
|
||||
if (!file_exists($path)) {
|
||||
throw new coding_exception("Failed to find '$langcode' checksum");
|
||||
}
|
||||
file_put_contents($path, '000000');
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
@tool @tool_langimport
|
||||
Feature: Manage language packs
|
||||
In order to support different languages
|
||||
As an administrator
|
||||
I need to be able to add, update and remove language packs
|
||||
|
||||
|
||||
Background:
|
||||
Given remote langimport tests are enabled
|
||||
|
||||
# The pirate language pack is used for testing because its small to download.
|
||||
|
||||
Scenario: Install language pack
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
When I set the field "Available language packs" to "English - Pirate (en_ar)"
|
||||
And I press "Install selected language pack(s)"
|
||||
Then I should see "Language pack 'en_ar' was successfully installed"
|
||||
And the "Installed language packs" select box should contain "English - Pirate (en_ar)"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should see "The language pack 'en_ar' was installed."
|
||||
And I log out
|
||||
|
||||
Scenario: Update language pack
|
||||
Given outdated langpack 'en_ar' is installed
|
||||
And I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
When I press "Update all installed language packs"
|
||||
Then I should see "Language pack 'en_ar' was successfully updated"
|
||||
And I should see "Language pack update completed"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should see "The language pack 'en_ar' was updated."
|
||||
And I log out
|
||||
|
||||
Scenario: Try to uninstall language pack
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
And I set the field "Available language packs" to "English - Pirate (en_ar)"
|
||||
And I press "Install selected language pack(s)"
|
||||
When I set the field "Installed language packs" to "English - Pirate (en_ar)"
|
||||
And I press "Uninstall selected language pack"
|
||||
And I press "Continue"
|
||||
Then I should see "Language pack 'en_ar' was uninstalled"
|
||||
And the "Installed language packs" select box should not contain "English - Pirate (en_ar)"
|
||||
And the "Available language packs" select box should contain "English - Pirate (en_ar)"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should see "The language pack 'en_ar' was removed."
|
||||
And I should see "Language pack uninstalled"
|
||||
And I log out
|
||||
|
||||
Scenario: Try to uninstall English language pack
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
When I set the field "Installed language packs" to "English (en)"
|
||||
And I press "Uninstall selected language pack"
|
||||
Then I should see "English language pack can not be uninstalled"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should not see "Language pack uninstalled"
|
||||
And I log out
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for langimport events.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Test class for langimport events.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
class tool_langimport_events_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Setup testcase.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
public function test_langpack_updated() {
|
||||
global $CFG;
|
||||
|
||||
$event = \tool_langimport\event\langpack_updated::event_with_langcode($CFG->lang);
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\tool_langimport\event\langpack_updated', $event);
|
||||
$this->assertEquals(context_system::instance(), $event->get_context());
|
||||
}
|
||||
|
||||
public function test_langpack_updated_validation() {
|
||||
$this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
|
||||
|
||||
\tool_langimport\event\langpack_updated::event_with_langcode('broken langcode');
|
||||
}
|
||||
|
||||
public function test_langpack_installed() {
|
||||
$event = \tool_langimport\event\langpack_imported::event_with_langcode('fr');
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\tool_langimport\event\langpack_imported', $event);
|
||||
$this->assertEquals(context_system::instance(), $event->get_context());
|
||||
}
|
||||
|
||||
public function test_langpack_installed_validation() {
|
||||
$this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
|
||||
|
||||
\tool_langimport\event\langpack_imported::event_with_langcode('broken langcode');
|
||||
}
|
||||
|
||||
public function test_langpack_removed() {
|
||||
$event = \tool_langimport\event\langpack_removed::event_with_langcode('fr');
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\tool_langimport\event\langpack_removed', $event);
|
||||
$this->assertEquals(context_system::instance(), $event->get_context());
|
||||
}
|
||||
|
||||
public function test_langpack_removed_validation() {
|
||||
$this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
|
||||
|
||||
\tool_langimport\event\langpack_removed::event_with_langcode('broken langcode');
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014092801; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version
|
||||
$plugin->component = 'tool_langimport'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Form to edit handlers.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
/**
|
||||
* Form to edit handlers.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_messageinbound_edit_handler_form extends moodleform {
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$handler = $this->_customdata['handler'];
|
||||
|
||||
// Set up the options for formatting text for descriptions, etc.
|
||||
$formatoptions = new stdClass();
|
||||
$formatoptions->trusted = false;
|
||||
$formatoptions->noclean = false;
|
||||
$formatoptions->smiley = false;
|
||||
$formatoptions->filter = false;
|
||||
$formatoptions->para = true;
|
||||
$formatoptions->newlines = false;
|
||||
$formatoptions->overflowdiv = true;
|
||||
|
||||
// General information about the handler.
|
||||
$mform->addElement('header', 'general', get_string('general'));
|
||||
$mform->addElement('static', 'name', get_string('name', 'tool_messageinbound'),
|
||||
$handler->name);
|
||||
$mform->addElement('static', 'classname', get_string('classname', 'tool_messageinbound'));
|
||||
|
||||
$description = format_text($handler->description, FORMAT_MARKDOWN, $formatoptions);
|
||||
|
||||
$mform->addElement('static', 'description', get_string('description', 'tool_messageinbound'),
|
||||
$description);
|
||||
|
||||
// Items which can be configured.
|
||||
$mform->addElement('header', 'configuration', get_string('configuration'));
|
||||
|
||||
$options = array(
|
||||
HOURSECS => get_string('onehour', 'tool_messageinbound'),
|
||||
DAYSECS => get_string('oneday', 'tool_messageinbound'),
|
||||
WEEKSECS => get_string('oneweek', 'tool_messageinbound'),
|
||||
YEARSECS => get_string('oneyear', 'tool_messageinbound'),
|
||||
'' => get_string('noexpiry', 'tool_messageinbound'),
|
||||
);
|
||||
$mform->addElement('select', 'defaultexpiration', get_string('defaultexpiration', 'tool_messageinbound'), $options);
|
||||
$mform->addHelpButton('defaultexpiration', 'defaultexpiration', 'tool_messageinbound');
|
||||
|
||||
if ($handler->can_change_validateaddress()) {
|
||||
$mform->addElement('checkbox', 'validateaddress', get_string('requirevalidation', 'tool_messageinbound'));
|
||||
$mform->addHelpButton('validateaddress', 'validateaddress', 'tool_messageinbound');
|
||||
} else {
|
||||
if ($handler->validateaddress) {
|
||||
$text = get_string('yes');
|
||||
} else {
|
||||
$text = get_string('no');
|
||||
}
|
||||
$mform->addElement('static', 'validateaddress_fake', get_string('requirevalidation', 'tool_messageinbound'), $text);
|
||||
$mform->addElement('hidden', 'validateaddress');
|
||||
$mform->addHelpButton('validateaddress_fake', 'fixedvalidateaddress', 'tool_messageinbound');
|
||||
$mform->setType('validateaddress', PARAM_INT);
|
||||
}
|
||||
|
||||
if ($handler->can_change_enabled()) {
|
||||
$mform->addElement('checkbox', 'enabled', get_string('enabled', 'tool_messageinbound'));
|
||||
} else {
|
||||
if ($handler->enabled) {
|
||||
$text = get_string('yes');
|
||||
} else {
|
||||
$text = get_string('no');
|
||||
}
|
||||
$mform->addElement('static', 'enabled_fake', get_string('enabled', 'tool_messageinbound'), $text);
|
||||
$mform->addHelpButton('enabled', 'fixedenabled', 'tool_messageinbound');
|
||||
$mform->addElement('hidden', 'enabled');
|
||||
$mform->setType('enabled', PARAM_INT);
|
||||
}
|
||||
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
}
|
||||
}
|
||||
@@ -1,962 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The Mail Pickup Manager.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Mail Pickup Manager.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class manager {
|
||||
|
||||
/**
|
||||
* @var string The main mailbox to check.
|
||||
*/
|
||||
const MAILBOX = 'INBOX';
|
||||
|
||||
/**
|
||||
* @var string The mailbox to store messages in when they are awaiting confirmation.
|
||||
*/
|
||||
const CONFIRMATIONFOLDER = 'tobeconfirmed';
|
||||
|
||||
/**
|
||||
* @var string The flag for seen/read messages.
|
||||
*/
|
||||
const MESSAGE_SEEN = '\seen';
|
||||
|
||||
/**
|
||||
* @var string The flag for flagged messages.
|
||||
*/
|
||||
const MESSAGE_FLAGGED = '\flagged';
|
||||
|
||||
/**
|
||||
* @var string The flag for deleted messages.
|
||||
*/
|
||||
const MESSAGE_DELETED = '\deleted';
|
||||
|
||||
/**
|
||||
* @var Horde_Imap_Client_Socket A reference to the IMAP client.
|
||||
*/
|
||||
protected $client = null;
|
||||
|
||||
/**
|
||||
* @var \core\message\inbound\address_manager A reference to the Inbound Message Address Manager instance.
|
||||
*/
|
||||
protected $addressmanager = null;
|
||||
|
||||
/**
|
||||
* @var stdClass The data for the current message being processed.
|
||||
*/
|
||||
protected $currentmessagedata = null;
|
||||
|
||||
/**
|
||||
* Retrieve the connection to the IMAP client.
|
||||
*
|
||||
* @return bool Whether a connection was successfully established.
|
||||
*/
|
||||
protected function get_imap_client() {
|
||||
global $CFG;
|
||||
|
||||
if (!\core\message\inbound\manager::is_enabled()) {
|
||||
// E-mail processing not set up.
|
||||
mtrace("Inbound Message not fully configured - exiting early.");
|
||||
return false;
|
||||
}
|
||||
|
||||
mtrace("Connecting to {$CFG->messageinbound_host} as {$CFG->messageinbound_hostuser}...");
|
||||
|
||||
$configuration = array(
|
||||
'username' => $CFG->messageinbound_hostuser,
|
||||
'password' => $CFG->messageinbound_hostpass,
|
||||
'hostspec' => $CFG->messageinbound_host,
|
||||
'secure' => $CFG->messageinbound_hostssl,
|
||||
);
|
||||
|
||||
$this->client = new \Horde_Imap_Client_Socket($configuration);
|
||||
|
||||
try {
|
||||
$this->client->login();
|
||||
mtrace("Connection established.");
|
||||
return true;
|
||||
|
||||
} catch (\Horde_Imap_Client_Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
mtrace("Unable to connect to IMAP server. Failed with '{$message}'");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown and close the connection to the IMAP client.
|
||||
*/
|
||||
protected function close_connection() {
|
||||
if ($this->client) {
|
||||
$this->client->close();
|
||||
}
|
||||
$this->client = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current mailbox information.
|
||||
*
|
||||
* @return \Horde_Imap_Client_Mailbox
|
||||
*/
|
||||
protected function get_mailbox() {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->client->currentMailbox();
|
||||
|
||||
if (isset($mailbox['mailbox'])) {
|
||||
return $mailbox['mailbox'];
|
||||
} else {
|
||||
throw new \core\message\inbound\processing_failed_exception('couldnotopenmailbox', 'tool_messageinbound');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the main Inbound Message pickup task.
|
||||
*/
|
||||
public function pickup_messages() {
|
||||
if (!$this->get_imap_client()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restrict results to messages which are unseen, and have not been flagged.
|
||||
$search = new \Horde_Imap_Client_Search_Query();
|
||||
$search->flag(self::MESSAGE_SEEN, false);
|
||||
$search->flag(self::MESSAGE_FLAGGED, false);
|
||||
mtrace("Searching for Unseen, Unflagged email in the folder '" . self::MAILBOX . "'");
|
||||
$results = $this->client->search(self::MAILBOX, $search);
|
||||
|
||||
// We require the envelope data and structure of each message.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->envelope();
|
||||
$query->structure();
|
||||
|
||||
// Retrieve the message id.
|
||||
$messages = $this->client->fetch(self::MAILBOX, $query, array('ids' => $results['match']));
|
||||
|
||||
mtrace("Found " . $messages->count() . " messages to parse. Parsing...");
|
||||
$this->addressmanager = new \core\message\inbound\address_manager();
|
||||
foreach ($messages as $message) {
|
||||
$this->process_message($message);
|
||||
}
|
||||
|
||||
// Close the client connection.
|
||||
$this->close_connection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message received and validated by the Inbound Message processor.
|
||||
*
|
||||
* @param stdClass $maildata The data retrieved from the database for the current record.
|
||||
* @return bool Whether the message was successfully processed.
|
||||
*/
|
||||
public function process_existing_message(\stdClass $maildata) {
|
||||
// Grab the new IMAP client.
|
||||
if (!$this->get_imap_client()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the search.
|
||||
$search = new \Horde_Imap_Client_Search_Query();
|
||||
// When dealing with Inbound Message messages, we mark them as flagged and seen. Restrict the search to those criterion.
|
||||
$search->flag(self::MESSAGE_SEEN, true);
|
||||
$search->flag(self::MESSAGE_FLAGGED, true);
|
||||
mtrace("Searching for a Seen, Flagged message in the folder '" . self::CONFIRMATIONFOLDER . "'");
|
||||
|
||||
// Match the message ID.
|
||||
$search->headerText('message-id', $maildata->messageid);
|
||||
$search->headerText('to', $maildata->address);
|
||||
|
||||
$results = $this->client->search(self::CONFIRMATIONFOLDER, $search);
|
||||
|
||||
// Build the base query.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->envelope();
|
||||
$query->structure();
|
||||
|
||||
|
||||
// Fetch the first message from the client.
|
||||
$messages = $this->client->fetch(self::CONFIRMATIONFOLDER, $query, array('ids' => $results['match']));
|
||||
$this->addressmanager = new \core\message\inbound\address_manager();
|
||||
if ($message = $messages->first()) {
|
||||
mtrace("--> Found the message. Passing back to the pickup system.");
|
||||
|
||||
// Process the message.
|
||||
$this->process_message($message, true, true);
|
||||
|
||||
// Close the client connection.
|
||||
$this->close_connection();
|
||||
|
||||
mtrace("============================================================================");
|
||||
return true;
|
||||
} else {
|
||||
// Close the client connection.
|
||||
$this->close_connection();
|
||||
|
||||
mtrace("============================================================================");
|
||||
throw new \core\message\inbound\processing_failed_exception('oldmessagenotfound', 'tool_messageinbound');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tidy up old messages in the confirmation folder.
|
||||
*
|
||||
* @return bool Whether tidying occurred successfully.
|
||||
*/
|
||||
public function tidy_old_messages() {
|
||||
// Grab the new IMAP client.
|
||||
if (!$this->get_imap_client()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the mailbox.
|
||||
mtrace("Searching for messages older than 24 hours in the '" .
|
||||
self::CONFIRMATIONFOLDER . "' folder.");
|
||||
$this->client->openMailbox(self::CONFIRMATIONFOLDER);
|
||||
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Build the search.
|
||||
$search = new \Horde_Imap_Client_Search_Query();
|
||||
|
||||
// Delete messages older than 24 hours old.
|
||||
$search->intervalSearch(DAYSECS, \Horde_Imap_Client_Search_Query::INTERVAL_OLDER);
|
||||
|
||||
$results = $this->client->search($mailbox, $search);
|
||||
|
||||
// Build the base query.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->envelope();
|
||||
|
||||
// Retrieve the messages and mark them for removal.
|
||||
$messages = $this->client->fetch($mailbox, $query, array('ids' => $results['match']));
|
||||
mtrace("Found " . $messages->count() . " messages for removal.");
|
||||
foreach ($messages as $message) {
|
||||
$this->add_flag_to_message($message->getUid(), self::MESSAGE_DELETED);
|
||||
}
|
||||
|
||||
mtrace("Finished removing messages.");
|
||||
$this->close_connection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message and pass it through the Inbound Message handling systems.
|
||||
*
|
||||
* @param Horde_Imap_Client_Data_Fetch $message The message to process
|
||||
* @param bool $viewreadmessages Whether to also look at messages which have been marked as read
|
||||
* @param bool $skipsenderverification Whether to skip the sender verificiation stage
|
||||
*/
|
||||
public function process_message(
|
||||
\Horde_Imap_Client_Data_Fetch $message,
|
||||
$viewreadmessages = false,
|
||||
$skipsenderverification = false) {
|
||||
global $USER;
|
||||
|
||||
// We use the Client IDs several times - store them here.
|
||||
$messageid = new \Horde_Imap_Client_Ids($message->getUid());
|
||||
|
||||
mtrace("- Parsing message " . $messageid);
|
||||
|
||||
// First flag this message to prevent another running hitting this message while we look at the headers.
|
||||
$this->add_flag_to_message($messageid, self::MESSAGE_FLAGGED);
|
||||
|
||||
// Record the user that this script is currently being run as. This is important when re-processing existing
|
||||
// messages, as cron_setup_user is called multiple times.
|
||||
$originaluser = $USER;
|
||||
|
||||
$envelope = $message->getEnvelope();
|
||||
$recipients = $envelope->to->bare_addresses;
|
||||
foreach ($recipients as $recipient) {
|
||||
if (!\core\message\inbound\address_manager::is_correct_format($recipient)) {
|
||||
// Message did not contain a subaddress.
|
||||
mtrace("- Recipient '{$recipient}' did not match Inbound Message headers.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Message contained a match.
|
||||
$senders = $message->getEnvelope()->from->bare_addresses;
|
||||
if (count($senders) !== 1) {
|
||||
mtrace("- Received multiple senders. Only the first sender will be used.");
|
||||
}
|
||||
$sender = array_shift($senders);
|
||||
|
||||
mtrace("-- Subject:\t" . $envelope->subject);
|
||||
mtrace("-- From:\t" . $sender);
|
||||
mtrace("-- Recipient:\t" . $recipient);
|
||||
|
||||
// Grab messagedata including flags.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->structure();
|
||||
$messagedata = $this->client->fetch($this->get_mailbox(), $query, array(
|
||||
'ids' => $messageid,
|
||||
))->first();
|
||||
|
||||
if (!$viewreadmessages && $this->message_has_flag($messageid, self::MESSAGE_SEEN)) {
|
||||
// Something else has already seen this message. Skip it now.
|
||||
mtrace("-- Skipping the message - it has been marked as seen - perhaps by another process.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark it as read to lock the message.
|
||||
$this->add_flag_to_message($messageid, self::MESSAGE_SEEN);
|
||||
|
||||
// Now pass it through the Inbound Message processor.
|
||||
$status = $this->addressmanager->process_envelope($recipient, $sender);
|
||||
|
||||
if (($status & ~ \core\message\inbound\address_manager::VALIDATION_DISABLED_HANDLER) !== $status) {
|
||||
// The handler is disabled.
|
||||
mtrace("-- Skipped message - Handler is disabled. Fail code {$status}");
|
||||
// In order to handle the user error, we need more information about the message being failed.
|
||||
$this->process_message_data($envelope, $messagedata, $messageid);
|
||||
$this->inform_user_of_error(get_string('handlerdisabled', 'tool_messageinbound', $this->currentmessagedata));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the validation status early. No point processing garbage messages, but we do need to process it
|
||||
// for some validation failure types.
|
||||
if (!$this->passes_key_validation($status, $messageid)) {
|
||||
// None of the above validation failures were found. Skip this message.
|
||||
mtrace("-- Skipped message - it does not appear to relate to a Inbound Message pickup. Fail code {$status}");
|
||||
|
||||
// Remove the seen flag from the message as there may be multiple recipients.
|
||||
$this->remove_flag_from_message($messageid, self::MESSAGE_SEEN);
|
||||
|
||||
// Skip further processing for this recipient.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process the message as the user.
|
||||
$user = $this->addressmanager->get_data()->user;
|
||||
mtrace("-- Processing the message as user {$user->id} ({$user->username}).");
|
||||
cron_setup_user($user);
|
||||
|
||||
// Process and retrieve the message data for this message.
|
||||
// This includes fetching the full content, as well as all headers, and attachments.
|
||||
$this->process_message_data($envelope, $messagedata, $messageid);
|
||||
|
||||
// When processing validation replies, we need to skip the sender verification phase as this has been
|
||||
// manually completed.
|
||||
if (!$skipsenderverification && $status !== 0) {
|
||||
// Check the validation status for failure types which require confirmation.
|
||||
// The validation result is tested in a bitwise operation.
|
||||
mtrace("-- Message did not meet validation but is possibly recoverable. Fail code {$status}");
|
||||
// This is a recoverable error, but requires user input.
|
||||
|
||||
if ($this->handle_verification_failure($messageid, $recipient)) {
|
||||
mtrace("--- Original message retained on mail server and confirmation message sent to user.");
|
||||
} else {
|
||||
mtrace("--- Invalid Recipient Handler - unable to save. Informing the user of the failure.");
|
||||
$this->inform_user_of_error(get_string('invalidrecipientfinal', 'tool_messageinbound', $this->currentmessagedata));
|
||||
}
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the content and attachment data.
|
||||
mtrace("-- Validation completed. Fetching rest of message content.");
|
||||
$this->process_message_data_body($messagedata, $messageid);
|
||||
|
||||
// The message processor throws exceptions upon failure. These must be caught and notifications sent to
|
||||
// the user here.
|
||||
try {
|
||||
$result = $this->send_to_handler();
|
||||
} catch (\core\message\inbound\processing_failed_exception $e) {
|
||||
// We know about these kinds of errors and they should result in the user being notified of the
|
||||
// failure. Send the user a notification here.
|
||||
$this->inform_user_of_error($e->getMessage());
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
return;
|
||||
} catch (Exception $e) {
|
||||
// An unknown error occurred. The user is not informed, but the administrator is.
|
||||
mtrace("-- Message processing failed. An unexpected exception was thrown. Details follow.");
|
||||
mtrace($e->getMessage());
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
// Handle message cleanup. Messages are deleted once fully processed.
|
||||
mtrace("-- Marking the message for removal.");
|
||||
$this->add_flag_to_message($messageid, self::MESSAGE_DELETED);
|
||||
} else {
|
||||
mtrace("-- The Inbound Message processor did not return a success status. Skipping message removal.");
|
||||
}
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
|
||||
mtrace("-- Finished processing " . $message->getUid());
|
||||
|
||||
// Skip the outer loop too. The message has already been processed and it could be possible for there to
|
||||
// be two recipients in the envelope which match somehow.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message to retrieve it's header data without body and attachemnts.
|
||||
*
|
||||
* @param Horde_Imap_Client_Data_Envelope $envelope The Envelope of the message
|
||||
* @param Horde_Imap_Client_Data_Fetch $messagedata The structure and part of the message body
|
||||
* @param string|Horde_Imap_Client_Ids $messageid The Hore message Uid
|
||||
* @return \stdClass The current value of the messagedata
|
||||
*/
|
||||
private function process_message_data(
|
||||
\Horde_Imap_Client_Data_Envelope $envelope,
|
||||
\Horde_Imap_Client_Data_Fetch $basemessagedata,
|
||||
$messageid) {
|
||||
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// We need the structure at various points below.
|
||||
$structure = $basemessagedata->getStructure();
|
||||
|
||||
// Now fetch the rest of the message content.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->imapDate();
|
||||
|
||||
// Fetch all of the message parts too.
|
||||
$typemap = $structure->contentTypeMap();
|
||||
foreach ($typemap as $part => $type) {
|
||||
// The header.
|
||||
$query->headerText(array(
|
||||
'id' => $part,
|
||||
));
|
||||
}
|
||||
|
||||
$messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first();
|
||||
|
||||
// Store the data for this message.
|
||||
$headers = '';
|
||||
|
||||
foreach ($typemap as $part => $type) {
|
||||
// Grab all of the header data into a string.
|
||||
$headers .= $messagedata->getHeaderText($part);
|
||||
|
||||
// We don't handle any of the other MIME content at this stage.
|
||||
}
|
||||
|
||||
$data = new \stdClass();
|
||||
|
||||
// The message ID should always be in the first part.
|
||||
$data->messageid = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Message-ID');
|
||||
$data->subject = $envelope->subject;
|
||||
$data->timestamp = $messagedata->getImapDate()->__toString();
|
||||
$data->envelope = $envelope;
|
||||
$data->data = $this->addressmanager->get_data();
|
||||
$data->headers = $headers;
|
||||
|
||||
$this->currentmessagedata = $data;
|
||||
|
||||
return $this->currentmessagedata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message again to add body and attachment data.
|
||||
*
|
||||
* @param Horde_Imap_Client_Data_Envelope $envelope The Envelope of the message
|
||||
* @param Horde_Imap_Client_Data_Fetch $basemessagedata The structure and part of the message body
|
||||
* @param string|Horde_Imap_Client_Ids $messageid The Hore message Uid
|
||||
* @return \stdClass The current value of the messagedata
|
||||
*/
|
||||
private function process_message_data_body(
|
||||
\Horde_Imap_Client_Data_Fetch $basemessagedata,
|
||||
$messageid) {
|
||||
global $CFG;
|
||||
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// We need the structure at various points below.
|
||||
$structure = $basemessagedata->getStructure();
|
||||
|
||||
// Now fetch the rest of the message content.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->fullText();
|
||||
|
||||
// Fetch all of the message parts too.
|
||||
$typemap = $structure->contentTypeMap();
|
||||
foreach ($typemap as $part => $type) {
|
||||
// The body of the part - attempt to decode it on the server.
|
||||
$query->bodyPart($part, array(
|
||||
'decode' => true,
|
||||
'peek' => true,
|
||||
));
|
||||
$query->bodyPartSize($part);
|
||||
}
|
||||
|
||||
$messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first();
|
||||
|
||||
// Store the data for this message.
|
||||
$contentplain = '';
|
||||
$contenthtml = '';
|
||||
$attachments = array(
|
||||
'inline' => array(),
|
||||
'attachment' => array(),
|
||||
);
|
||||
|
||||
$plainpartid = $structure->findBody('plain');
|
||||
$htmlpartid = $structure->findBody('html');
|
||||
|
||||
foreach ($typemap as $part => $type) {
|
||||
// Get the message data from the body part, and combine it with the structure to give a fully-formed output.
|
||||
$stream = $messagedata->getBodyPart($part, true);
|
||||
$partdata = $structure->getPart($part);
|
||||
$partdata->setContents($stream, array(
|
||||
'usestream' => true,
|
||||
));
|
||||
|
||||
if ($part === $plainpartid) {
|
||||
$contentplain = $this->process_message_part_body($messagedata, $partdata, $part);
|
||||
|
||||
} else if ($part === $htmlpartid) {
|
||||
$contenthtml = $this->process_message_part_body($messagedata, $partdata, $part);
|
||||
|
||||
} else if ($filename = $partdata->getName($part)) {
|
||||
if ($attachment = $this->process_message_part_attachment($messagedata, $partdata, $part, $filename)) {
|
||||
// The disposition should be one of 'attachment', 'inline'.
|
||||
// If an empty string is provided, default to 'attachment'.
|
||||
$disposition = $partdata->getDisposition();
|
||||
$disposition = $disposition == 'inline' ? 'inline' : 'attachment';
|
||||
$attachments[$disposition][] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't handle any of the other MIME content at this stage.
|
||||
}
|
||||
|
||||
// The message ID should always be in the first part.
|
||||
$this->currentmessagedata->plain = $contentplain;
|
||||
$this->currentmessagedata->html = $contenthtml;
|
||||
$this->currentmessagedata->attachments = $attachments;
|
||||
|
||||
return $this->currentmessagedata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the messagedata and part data to extract the content of this part.
|
||||
*
|
||||
* @param $messagedata The structure and part of the message body
|
||||
* @param $partdata The part data
|
||||
* @param $part The part ID
|
||||
* @return string
|
||||
*/
|
||||
private function process_message_part_body($messagedata, $partdata, $part) {
|
||||
// This is a content section for the main body.
|
||||
|
||||
// Get the string version of it.
|
||||
$content = $messagedata->getBodyPart($part);
|
||||
if (!$messagedata->getBodyPartDecode($part)) {
|
||||
// Decode the content.
|
||||
$partdata->setContents($content);
|
||||
$content = $partdata->getContents();
|
||||
}
|
||||
|
||||
// Convert the text from the current encoding to UTF8.
|
||||
$content = \core_text::convert($content, $partdata->getCharset());
|
||||
|
||||
// Fix any invalid UTF8 characters.
|
||||
// Note: XSS cleaning is not the responsibility of this code. It occurs immediately before display when
|
||||
// format_text is called.
|
||||
$content = clean_param($content, PARAM_RAW);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message again to add body and attachment data.
|
||||
*
|
||||
* @param $messagedata The structure and part of the message body
|
||||
* @param $partdata The part data
|
||||
* @param $filename The filename of the attachment
|
||||
* @return \stdClass
|
||||
*/
|
||||
private function process_message_part_attachment($messagedata, $partdata, $part, $filename) {
|
||||
global $CFG;
|
||||
|
||||
// If a filename is present, assume that this part is an attachment.
|
||||
$attachment = new \stdClass();
|
||||
$attachment->filename = $filename;
|
||||
$attachment->type = $partdata->getType();
|
||||
$attachment->content = $partdata->getContents();
|
||||
$attachment->charset = $partdata->getCharset();
|
||||
$attachment->description = $partdata->getDescription();
|
||||
$attachment->contentid = $partdata->getContentId();
|
||||
$attachment->filesize = $messagedata->getBodyPartSize($part);
|
||||
|
||||
if (empty($CFG->runclamonupload) or empty($CFG->pathtoclam)) {
|
||||
mtrace("--> Attempting virus scan of '{$attachment->filename}'");
|
||||
|
||||
// Store the file on disk - it will need to be virus scanned first.
|
||||
$itemid = rand(1, 999999999);;
|
||||
$directory = make_temp_directory("/messageinbound/{$itemid}", false);
|
||||
$filepath = $directory . "/" . $attachment->filename;
|
||||
if (!$fp = fopen($filepath, "w")) {
|
||||
// Unable to open the temporary file to write this to disk.
|
||||
mtrace("--> Unable to save the file to disk for virus scanning. Check file permissions.");
|
||||
|
||||
throw new \core\message\inbound\processing_failed_exception('attachmentfilepermissionsfailed',
|
||||
'tool_messageinbound');
|
||||
}
|
||||
|
||||
fwrite($fp, $attachment->content);
|
||||
fclose($fp);
|
||||
|
||||
// Perform a virus scan now.
|
||||
try {
|
||||
\repository::antivir_scan_file($filepath, $attachment->filename, true);
|
||||
} catch (moodle_exception $e) {
|
||||
mtrace("--> A virus was found in the attachment '{$attachment->filename}'.");
|
||||
$this->inform_attachment_virus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the key provided is valid.
|
||||
*
|
||||
* @param $status The Message to process
|
||||
* @param $messageid The Hore message Uid
|
||||
* @return bool
|
||||
*/
|
||||
private function passes_key_validation($status, $messageid) {
|
||||
// The validation result is tested in a bitwise operation.
|
||||
if ((
|
||||
$status & ~ \core\message\inbound\address_manager::VALIDATION_SUCCESS
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_UNKNOWN_DATAKEY
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_EXPIRED_DATAKEY
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_INVALID_HASH
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_ADDRESS_MISMATCH) !== 0) {
|
||||
|
||||
// One of the above bits was found in the status - fail the validation.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified flag to the message.
|
||||
*
|
||||
* @param $messageid
|
||||
* @param string $flag The flag to add
|
||||
*/
|
||||
private function add_flag_to_message($messageid, $flag) {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Mark it as read to lock the message.
|
||||
$this->client->store($mailbox, array(
|
||||
'ids' => new \Horde_Imap_Client_Ids($messageid),
|
||||
'add' => $flag,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified flag from the message.
|
||||
*
|
||||
* @param $messageid
|
||||
* @param string $flag The flag to remove
|
||||
*/
|
||||
private function remove_flag_from_message($messageid, $flag) {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Mark it as read to lock the message.
|
||||
$this->client->store($mailbox, array(
|
||||
'ids' => $messageid,
|
||||
'delete' => $flag,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the message has the specified flag
|
||||
*
|
||||
* @param $messageid
|
||||
* @param string $flag The flag to check
|
||||
* @return bool
|
||||
*/
|
||||
private function message_has_flag($messageid, $flag) {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Grab messagedata including flags.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->flags();
|
||||
$query->structure();
|
||||
$messagedata = $this->client->fetch($mailbox, $query, array(
|
||||
'ids' => $messageid,
|
||||
))->first();
|
||||
$flags = $messagedata->getFlags();
|
||||
|
||||
return in_array($flag, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message to the appropriate handler.
|
||||
*
|
||||
*/
|
||||
private function send_to_handler() {
|
||||
try {
|
||||
mtrace("--> Passing to Inbound Message handler {$this->addressmanager->get_handler()->classname}");
|
||||
if ($result = $this->addressmanager->handle_message($this->currentmessagedata)) {
|
||||
$this->inform_user_of_success($this->currentmessagedata, $result);
|
||||
// Request that this message be marked for deletion.
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (\core\message\inbound\processing_failed_exception $e) {
|
||||
mtrace("-> The Inbound Message handler threw an exception. Unable to process this message. The user has been informed.");
|
||||
mtrace("--> " . $e->getMessage());
|
||||
// Throw the exception again, with additional data.
|
||||
$error = new \stdClass();
|
||||
$error->subject = $this->currentmessagedata->envelope->subject;
|
||||
$error->message = $e->getMessage();
|
||||
throw new \core\message\inbound\processing_failed_exception('messageprocessingfailed', 'tool_messageinbound', $error);
|
||||
|
||||
} catch (Exception $e) {
|
||||
mtrace("-> The Inbound Message handler threw an exception. Unable to process this message. User informed.");
|
||||
mtrace("--> " . $e->getMessage());
|
||||
// An unknown error occurred. Still inform the user but, this time do not include the specific
|
||||
// message information.
|
||||
$error = new \stdClass();
|
||||
$error->subject = $this->currentmessagedata->envelope->subject;
|
||||
throw new \core\message\inbound\processing_failed_exception('messageprocessingfailedunknown',
|
||||
'tool_messageinbound', $error);
|
||||
|
||||
}
|
||||
|
||||
// Something went wrong and the message was not handled well in the Inbound Message handler.
|
||||
mtrace("-> The Inbound Message handler reported an error. The message may not have been processed.");
|
||||
|
||||
// It is the responsiblity of the handler to throw an appropriate exception if the message was not processed.
|
||||
// Do not inform the user at this point.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle failure of sender verification.
|
||||
*
|
||||
* This will send a notification to the user identified in the Inbound Message address informing them that a message has been
|
||||
* stored. The message includes a verification link and reply-to address which is handled by the
|
||||
* invalid_recipient_handler.
|
||||
*
|
||||
* @param $recipient The message recipient
|
||||
*/
|
||||
private function handle_verification_failure(
|
||||
\Horde_Imap_Client_Ids $messageids,
|
||||
$recipient) {
|
||||
global $DB, $USER;
|
||||
|
||||
if (!$messageid = $this->currentmessagedata->messageid) {
|
||||
mtrace("---> Warning: Unable to determine the Message-ID of the message.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move the message into a new mailbox.
|
||||
$this->client->copy(self::MAILBOX, self::CONFIRMATIONFOLDER, array(
|
||||
'create' => true,
|
||||
'ids' => $messageids,
|
||||
'move' => true,
|
||||
));
|
||||
|
||||
// Store the data from the failed message in the associated table.
|
||||
$record = new \stdClass();
|
||||
$record->messageid = $messageid;
|
||||
$record->userid = $USER->id;
|
||||
$record->address = $recipient;
|
||||
$record->timecreated = time();
|
||||
$record->id = $DB->insert_record('messageinbound_messagelist', $record);
|
||||
|
||||
// Setup the Inbound Message generator for the invalid recipient handler.
|
||||
$addressmanager = new \core\message\inbound\address_manager();
|
||||
$addressmanager->set_handler('\tool_messageinbound\message\inbound\invalid_recipient_handler');
|
||||
$addressmanager->set_data($record->id);
|
||||
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->component = 'tool_messageinbound';
|
||||
$eventdata->name = 'invalidrecipienthandler';
|
||||
|
||||
$userfrom = clone $USER;
|
||||
$userfrom->customheaders = array();
|
||||
// Adding the In-Reply-To header ensures that it is seen as a reply.
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$eventdata->userfrom = \core_user::get_noreply_user();
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = $this->get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = get_string('invalidrecipientdescription', 'tool_messageinbound', $this->currentmessagedata);
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = get_string('invalidrecipientdescriptionhtml', 'tool_messageinbound', $this->currentmessagedata);
|
||||
$eventdata->smallmessage = $eventdata->fullmessage;
|
||||
$eventdata->notification = 1;
|
||||
$eventdata->replyto = $addressmanager->generate($USER->id);
|
||||
|
||||
mtrace("--> Sending a message to the user to report an verification failure.");
|
||||
if (!message_send($eventdata)) {
|
||||
mtrace("---> Warning: Message could not be sent.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the identified sender of a processing error.
|
||||
*
|
||||
* @param string $error The error message
|
||||
*/
|
||||
private function inform_user_of_error($error) {
|
||||
global $USER;
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$userfrom = clone $USER;
|
||||
$userfrom->customheaders = array();
|
||||
|
||||
if ($messageid = $this->currentmessagedata->messageid) {
|
||||
// Adding the In-Reply-To header ensures that it is seen as a reply and threading is maintained.
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
}
|
||||
|
||||
$messagedata = new \stdClass();
|
||||
$messagedata->subject = $this->currentmessagedata->envelope->subject;
|
||||
$messagedata->error = $error;
|
||||
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->component = 'tool_messageinbound';
|
||||
$eventdata->name = 'messageprocessingerror';
|
||||
$eventdata->userfrom = $userfrom;
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = self::get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = get_string('messageprocessingerror', 'tool_messageinbound', $messagedata);
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = get_string('messageprocessingerrorhtml', 'tool_messageinbound', $messagedata);
|
||||
$eventdata->smallmessage = $eventdata->fullmessage;
|
||||
$eventdata->notification = 1;
|
||||
|
||||
if (message_send($eventdata)) {
|
||||
mtrace("---> Notification sent to {$USER->email}.");
|
||||
} else {
|
||||
mtrace("---> Unable to send notification.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the identified sender that message processing was successful.
|
||||
*
|
||||
* @param stdClass $messagedata The data for the current message being processed.
|
||||
* @param mixed $handlerresult The result returned by the handler.
|
||||
*/
|
||||
private function inform_user_of_success(\stdClass $messagedata, $handlerresult) {
|
||||
global $USER;
|
||||
|
||||
// Check whether the handler has a success notification.
|
||||
$handler = $this->addressmanager->get_handler();
|
||||
$message = $handler->get_success_message($messagedata, $handlerresult);
|
||||
|
||||
if (!$message) {
|
||||
mtrace("---> Handler has not defined a success notification e-mail.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wrap the message in the notification wrapper.
|
||||
$messageparams = new \stdClass();
|
||||
$messageparams->html = $message->html;
|
||||
$messageparams->plain = $message->plain;
|
||||
$messagepreferencesurl = new \moodle_url("/message/edit.php", array('id' => $USER->id));
|
||||
$messageparams->messagepreferencesurl = $messagepreferencesurl->out();
|
||||
$htmlmessage = get_string('messageprocessingsuccesshtml', 'tool_messageinbound', $messageparams);
|
||||
$plainmessage = get_string('messageprocessingsuccess', 'tool_messageinbound', $messageparams);
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$userfrom = clone $USER;
|
||||
$userfrom->customheaders = array();
|
||||
|
||||
if ($messageid = $this->currentmessagedata->messageid) {
|
||||
// Adding the In-Reply-To header ensures that it is seen as a reply and threading is maintained.
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
}
|
||||
|
||||
$messagedata = new \stdClass();
|
||||
$messagedata->subject = $this->currentmessagedata->envelope->subject;
|
||||
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->component = 'tool_messageinbound';
|
||||
$eventdata->name = 'messageprocessingsuccess';
|
||||
$eventdata->userfrom = $userfrom;
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = self::get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = $plainmessage;
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = $htmlmessage;
|
||||
$eventdata->smallmessage = $eventdata->fullmessage;
|
||||
$eventdata->notification = 1;
|
||||
|
||||
if (message_send($eventdata)) {
|
||||
mtrace("---> Success notification sent to {$USER->email}.");
|
||||
} else {
|
||||
mtrace("---> Unable to send success notification.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a formatted subject line for replies.
|
||||
*
|
||||
* @param $subject string The subject string
|
||||
* @return string The formatted reply subject
|
||||
*/
|
||||
private function get_reply_subject($subject) {
|
||||
$prefix = get_string('replysubjectprefix', 'tool_messageinbound');
|
||||
if (!(substr($subject, 0, strlen($prefix)) == $prefix)) {
|
||||
$subject = $prefix . ' ' . $subject;
|
||||
}
|
||||
|
||||
return $subject;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A Handler to re-process messages which previously failed sender
|
||||
* verification.
|
||||
*
|
||||
* @package task_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound\message\inbound;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/repository/lib.php');
|
||||
|
||||
/**
|
||||
* A Handler to re-process messages which previously failed sender
|
||||
* verification.
|
||||
*
|
||||
* This may happen if the user did not use their registerd e-mail address,
|
||||
* the verification hash used had expired, or if some erroneous content was
|
||||
* introduced into the content hash.
|
||||
*
|
||||
* @package task
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class invalid_recipient_handler extends \core\message\inbound\handler {
|
||||
|
||||
/**
|
||||
* Do not allow changes to the address validation setting.
|
||||
*/
|
||||
public function allow_validateaddress_change() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for the current handler.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return get_string('invalid_recipient_handler', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name for the current handler.
|
||||
* This appears in the admin pages as a human-readable name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('invalid_recipient_handler_name', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message received and validated by the Inbound Message processor.
|
||||
*
|
||||
* @param $messagedata The Inbound Message record
|
||||
* @param $messagedata The message data packet.
|
||||
* @return bool Whether the message was successfully processed.
|
||||
*/
|
||||
public function process_message(\stdClass $record, \stdClass $data) {
|
||||
global $DB;
|
||||
|
||||
if (!$maildata = $DB->get_record('messageinbound_messagelist', array('id' => $record->datavalue))) {
|
||||
// The message requested couldn't be found. Failing here will alert the user that we failed.
|
||||
throw new \core\message\inbound\processing_failed_exception('oldmessagenotfound', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
mtrace("=== Request to re-process message {$record->datavalue} from server.");
|
||||
mtrace("=== Message-Id:\t{$maildata->messageid}");
|
||||
mtrace("=== Recipient:\t{$maildata->address}");
|
||||
|
||||
$manager = new \tool_messageinbound\manager();
|
||||
return $manager->process_existing_message($maildata);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A scheduled task to handle cleanup of old, unconfirmed e-mails.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound\task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A scheduled task to handle cleanup of old, unconfirmed e-mails.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cleanup_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskcleanup', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the main Inbound Message pickup task.
|
||||
*/
|
||||
public function execute() {
|
||||
$manager = new \tool_messageinbound\manager();
|
||||
return $manager->tidy_old_messages();
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A scheduled task to handle Inbound Message e-mail pickup.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound\task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A scheduled task to handle Inbound Message e-mail pickup.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class pickup_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskpickup', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the main Inbound Message pickup task.
|
||||
*/
|
||||
public function execute() {
|
||||
$manager = new \tool_messageinbound\manager();
|
||||
return $manager->pickup_messages();
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Handlers for tool_messageinbound.
|
||||
*
|
||||
* @package task
|
||||
* @category tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$handlers = array(
|
||||
array(
|
||||
'classname' => '\tool_messageinbound\message\inbound\invalid_recipient_handler',
|
||||
'enabled' => true,
|
||||
'validateaddress' => false,
|
||||
),
|
||||
);
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Message Providers for task_messageinbound.
|
||||
*
|
||||
* @package task
|
||||
* @category messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$messageproviders = array (
|
||||
// Invalid recipient handler.
|
||||
'invalidrecipienthandler' => array(),
|
||||
|
||||
// A generic message processing error.
|
||||
'messageprocessingerror' => array(),
|
||||
|
||||
// A generic message processing success message.
|
||||
'messageprocessingsuccess' => array(),
|
||||
);
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The Main Manager tasks.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$tasks = array(
|
||||
array(
|
||||
'classname' => '\tool_messageinbound\task\pickup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '*',
|
||||
'hour' => '*',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
|
||||
array(
|
||||
'classname' => '\tool_messageinbound\task\cleanup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '55',
|
||||
'hour' => '1',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
);
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Inbound Message Settings pages.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew NIcols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
admin_externalpage_setup('messageinbound_handlers');
|
||||
|
||||
$classname = optional_param('classname', '', PARAM_RAW);
|
||||
|
||||
$pageurl = new moodle_url('/admin/tool/messageinbound/index.php');
|
||||
|
||||
if (empty($classname)) {
|
||||
$renderer = $PAGE->get_renderer('tool_messageinbound');
|
||||
|
||||
$records = $DB->get_recordset('messageinbound_handlers', null, 'enabled desc', 'classname');
|
||||
$instances = array();
|
||||
foreach ($records as $record) {
|
||||
$instances[] = \core\message\inbound\manager::get_handler($record->classname);
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $renderer->messageinbound_handlers_table($instances);
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
} else {
|
||||
// Retrieve the handler and its record.
|
||||
$handler = \core\message\inbound\manager::get_handler($classname);
|
||||
$record = \core\message\inbound\manager::record_from_handler($handler);
|
||||
|
||||
$formurl = new moodle_url($PAGE->url, array('classname' => $classname));
|
||||
$mform = new tool_messageinbound_edit_handler_form($formurl, array(
|
||||
'handler' => $handler,
|
||||
));
|
||||
|
||||
if ($mform->is_cancelled()) {
|
||||
redirect($PAGE->url);
|
||||
} else if ($data = $mform->get_data()) {
|
||||
// Update the record from the form.
|
||||
$record->defaultexpiration = (int) $data->defaultexpiration;
|
||||
|
||||
if ($handler->can_change_validateaddress()) {
|
||||
$record->validateaddress = !empty($data->validateaddress);
|
||||
}
|
||||
|
||||
if ($handler->can_change_enabled()) {
|
||||
$record->enabled = !empty($data->enabled);
|
||||
}
|
||||
$DB->update_record('messageinbound_handlers', $record);
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Add the breadcrumb.
|
||||
$pageurl->param('classname', $handler->classname);
|
||||
$PAGE->navbar->add($handler->name, $pageurl);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('editinghandler', 'tool_messageinbound', $handler->name));
|
||||
$mform->set_data($record);
|
||||
$mform->display();
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'tool_messageinbound', language 'en'
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['classname'] = 'Class name';
|
||||
$string['component'] = 'Component';
|
||||
$string['configmessageinboundhost'] = 'The address of the server that Moodle should check mail against. To specify a non-default port, you can use the [server]:[port], for example mail.example.com:587 format. If you leave this field blank, Moodle will use the default port for the type of mail server you specify.';
|
||||
$string['defaultexpiration'] = 'Default address expiry period';
|
||||
$string['defaultexpiration_help'] = 'When an email address is generated by the handler, it can be set to automatically expire after a period of time, so that it can no longer be used. It is advisable to set an expiry period.';
|
||||
$string['description'] = 'Description';
|
||||
$string['domain'] = 'Email Domain';
|
||||
$string['edit'] = 'Edit';
|
||||
$string['edithandler'] = 'Edit settings for the {$a} handler';
|
||||
$string['editinghandler'] = 'Editing {$a}';
|
||||
$string['enabled'] = 'Enabled';
|
||||
$string['fixedvalidateaddress'] = 'Validate sender address';
|
||||
$string['fixedvalidateaddress_help'] = 'You cannot change the address validation for this handler. This may be because the handler requires a specific setting.';
|
||||
$string['fixedenabled_help'] = 'You cannot change the state of this handler. This may be because the handler is required by other handlers.';
|
||||
$string['handlerdisabled'] = 'The email handler you tried to contact has been disabled. Unable to process message at this time.';
|
||||
$string['incomingmailconfiguration'] = 'Incoming mail configuration';
|
||||
$string['incomingmailserversettings'] = 'Incoming mail server settings';
|
||||
$string['incomingmailserversettings_desc'] = 'Moodle is capable of connecting to appropriately configured IMAP servers. You can specify the settings used to connect to your IMAP server here.';
|
||||
$string['invalid_recipient_handler'] = 'If a valid message is received but the sender cannot be authenticated, the message is stored on the email server and the user is contacted using the email address in their user profile. The user is given the chance to reply to confirm the authenticity of the original message.
|
||||
|
||||
This handler processes those replies.
|
||||
|
||||
It is not possible to disable sender verification of this handler because the user may reply from an incorrect email address if their email client configuration is incorrect.';
|
||||
$string['invalid_recipient_handler_name'] = 'Invalid recipient handler';
|
||||
$string['invalidrecipientdescription'] = 'The message "{$a->subject}" could not be authenticated, since it was sent from a different email address than in your user profile. For the message to be authenticated, you need to reply to this message.';
|
||||
$string['invalidrecipientdescriptionhtml'] = 'The message "{$a->subject}" could not be authenticated, since it was sent from a different email address than in your user profile. For the message to be authenticated, you need to reply to this message.';
|
||||
$string['invalidrecipientfinal'] = 'The message you sent with subject "{$a->subject}" could not be authenticated. Please check that you are sending your message from the e-mail account listed in your Moodle profile.';
|
||||
$string['mailbox'] = 'Mailbox name';
|
||||
$string['mailboxconfiguration'] = 'Mailbox configuration';
|
||||
$string['mailboxdescription'] = '[mailbox]+subaddress@[domain]';
|
||||
$string['mailsettings'] = 'Mail settings';
|
||||
$string['message_handlers'] = 'Message handlers';
|
||||
$string['messageprocessingerror'] = 'You recently sent an e-mail to Moodle with the subject "{$a->subject}" but Moodle was unable to process it.
|
||||
|
||||
The details of the error are shown below.
|
||||
|
||||
{$a->error}';
|
||||
$string['messageprocessingerrorhtml'] = '<p>You recently sent an e-mail to Moodle with the subject "{$a->subject}" but Moodle was unable to process it.</p>
|
||||
<p>The details of the error are shown below.</p>
|
||||
<p>{$a->error}</p>';
|
||||
$string['messageprocessingfailed'] = 'Moodle was unable to process the e-mail you sent with subject "{$a->subject}". The following error was given: "{$a->message}".';
|
||||
$string['messageprocessingfailedunknown'] = 'Moodle was unable to process the e-mail you sent with subject "{$a->subject}". Contact your system administrator for further information.';
|
||||
$string['messageprocessingsuccess'] = '{$a->plain}
|
||||
|
||||
If you do not wish to receive these notifications in the future, you can edit your personal messaging preferences by opening {$a->messagepreferencesurl} in your browser.';
|
||||
$string['messageprocessingsuccesshtml'] = '{$a->html}
|
||||
<p>If you do not wish to receive these notifications in the future, you can <a href="{$a->messagepreferencesurl}">edit your personal messaging preferences</a>.</p>';
|
||||
$string['messageinbound'] = 'Message Inbound';
|
||||
$string['messageinboundenabled'] = 'Enable incoming mail processing';
|
||||
$string['messageinboundenabled_desc'] = 'Incoming mail processing must be enabled in order for messages to be sent with the appropriate information.';
|
||||
$string['messageinboundgeneralconfiguration'] = 'General configuration';
|
||||
$string['messageinboundgeneralconfiguration_desc'] = 'Inbound message processing allows you to receive and process email within Moodle. This has applications such as sending email replies to forum posts or adding files to a user\'s private files.';
|
||||
$string['messageinboundhost'] = 'Incoming Mail Server';
|
||||
$string['messageinboundhostpass'] = 'Password';
|
||||
$string['messageinboundhostpass_desc'] = 'This is the password your service provider will have provided to log into your e-mail account with.';
|
||||
$string['messageinboundhostssl'] = 'Use SSL';
|
||||
$string['messageinboundhostssl_desc'] = 'Some mail servers support an additional level of security by encrypting communication between Moodle and your server. We recommend using this SSL encryption if your server supports it.';
|
||||
$string['messageinboundhosttype'] = 'Server type';
|
||||
$string['messageinboundhostuser'] = 'Username';
|
||||
$string['messageinboundhostuser_desc'] = 'This is the username your service provider will have provided to log into your e-mail account with.';
|
||||
$string['messageinboundmailboxconfiguration_desc'] = 'When messages are sent out, they fit into the format address+data@example.com. To reliably generate addresses from Moodle, please specify the address that you would normally use before the @ sign, and the domain after the @ sign separately. For example, the Mailbox name in the example would be "address", and the E-mail domain would be "example.com". You should use a dedicated e-mail account for this purpose.';
|
||||
$string['messageprovider:invalidrecipienthandler'] = 'Messages to confirm that an inbound messages came from you';
|
||||
$string['messageprovider:messageprocessingerror'] = 'Warning when an inbound message could not be processed';
|
||||
$string['messageprovider:messageprocessingsuccess'] = 'Confirmation that a message was successfully processed';
|
||||
$string['noencryption'] = 'Off - No encryption';
|
||||
$string['noexpiry'] = 'No expiry';
|
||||
$string['oldmessagenotfound'] = 'You tried to manually authenticate a message, but the message could not be found. This could be because it has already been processed, or because the message expired.';
|
||||
$string['oneday'] = 'One day';
|
||||
$string['onehour'] = 'One hour';
|
||||
$string['oneweek'] = 'One week';
|
||||
$string['oneyear'] = 'One year';
|
||||
$string['pluginname'] = 'Inbound message configuration';
|
||||
$string['replysubjectprefix'] = 'Re:';
|
||||
$string['requirevalidation'] = 'Validate sender address';
|
||||
$string['name'] = 'Name';
|
||||
$string['ssl'] = 'SSL (Auto-detect SSL version)';
|
||||
$string['sslv2'] = 'SSLv2 (Force SSL Version 2)';
|
||||
$string['sslv3'] = 'SSLv2 (Force SSL Version 3)';
|
||||
$string['taskcleanup'] = 'Cleanup of unverified incoming email';
|
||||
$string['taskpickup'] = 'Incoming email pickup';
|
||||
$string['tls'] = 'TLS (TLS; started via protocol-level negotiation over unencrypted channel; RECOMMENDED way of initiating secure connection)';
|
||||
$string['tlsv1'] = 'TLSv1 (TLS direct version 1.x connection to server)';
|
||||
$string['validateaddress'] = 'Validate sender email address';
|
||||
$string['validateaddress_help'] = 'When a message is received from a user, Moodle attempts to validate the message by comparing the email address of the sender with the email address in their user profile.
|
||||
|
||||
If the sender does not match, then the user is sent a notification to confirm that they really did send the email.
|
||||
|
||||
If this setting is disabled, then the email address of the sender is not checked at all.';
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Output rendering for the plugin.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Implements the plugin renderer
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_messageinbound_renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Render a table listing all of the Inbound Message handlers.
|
||||
*
|
||||
* @param array $handlers - list of all messageinbound handlers.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function messageinbound_handlers_table(array $handlers) {
|
||||
global $CFG;
|
||||
|
||||
$table = new html_table();
|
||||
$handlername = new html_table_cell(get_string('name', 'tool_messageinbound') . "\n" .
|
||||
html_writer::tag('span', get_string('classname', 'tool_messageinbound'), array('class' => 'handler-function')));
|
||||
|
||||
// Prepare some of the rows with additional styling.
|
||||
$enabled = new html_table_cell(get_string('enabled', 'tool_messageinbound'));
|
||||
$enabled->attributes['class'] = 'state';
|
||||
$edit = new html_table_cell(get_string('edit', 'tool_messageinbound'));
|
||||
$edit->attributes['class'] = 'edit';
|
||||
$table->head = array(
|
||||
$handlername,
|
||||
get_string('description', 'tool_messageinbound'),
|
||||
$enabled,
|
||||
$edit,
|
||||
);
|
||||
$table->attributes['class'] = 'admintable generaltable messageinboundhandlers';
|
||||
|
||||
$yes = get_string('yes');
|
||||
$no = get_string('no');
|
||||
|
||||
$data = array();
|
||||
|
||||
// Options for description formatting.
|
||||
$descriptionoptions = new stdClass();
|
||||
$descriptionoptions->trusted = false;
|
||||
$descriptionoptions->noclean = false;
|
||||
$descriptionoptions->smiley = false;
|
||||
$descriptionoptions->filter = false;
|
||||
$descriptionoptions->para = true;
|
||||
$descriptionoptions->newlines = false;
|
||||
$descriptionoptions->overflowdiv = true;
|
||||
|
||||
$editurlbase = new moodle_url('/admin/tool/messageinbound/index.php');
|
||||
foreach ($handlers as $handler) {
|
||||
$handlername = new html_table_cell($handler->name . "\n" .
|
||||
html_writer::tag('span', $handler->classname, array('class' => 'handler-function')));
|
||||
$handlername->header = true;
|
||||
|
||||
$editurl = new moodle_url($editurlbase, array('classname' => $handler->classname));
|
||||
$editlink = $this->action_icon($editurl, new pix_icon('t/edit',
|
||||
get_string('edithandler', 'tool_messageinbound', $handler->classname)));
|
||||
|
||||
// Prepare some of the rows with additional styling.
|
||||
$enabled = new html_table_cell($handler->enabled ? $yes : $no);
|
||||
$enabled->attributes['class'] = 'state';
|
||||
$edit = new html_table_cell($editlink);
|
||||
$edit->attributes['class'] = 'edit';
|
||||
|
||||
// Add the row.
|
||||
$row = new html_table_row(array(
|
||||
$handlername,
|
||||
format_text($handler->description, FORMAT_MARKDOWN, $descriptionoptions),
|
||||
$enabled,
|
||||
$edit,
|
||||
));
|
||||
|
||||
if (!$handler->enabled) {
|
||||
$row->attributes['class'] = 'disabled';
|
||||
}
|
||||
$data[] = $row;
|
||||
}
|
||||
$table->data = $data;
|
||||
return html_writer::table($table);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Inbound Message Settings.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($hassiteconfig) {
|
||||
$category = new admin_category('messageinbound', new lang_string('incomingmailconfiguration', 'tool_messageinbound'));
|
||||
|
||||
// Create a settings page for all of the mail server settings.
|
||||
$settings = new admin_settingpage('messageinbound_mailsettings', new lang_string('mailsettings', 'tool_messageinbound'));
|
||||
|
||||
$settings->add(new admin_setting_heading('messageinbound_generalconfiguration',
|
||||
new lang_string('messageinboundgeneralconfiguration', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundgeneralconfiguration_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configcheckbox('messageinbound_enabled',
|
||||
new lang_string('messageinboundenabled', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundenabled_desc', 'tool_messageinbound'), 0));
|
||||
|
||||
// These settings are used when generating a Inbound Message address.
|
||||
$settings->add(new admin_setting_heading('messageinbound_mailboxconfiguration',
|
||||
new lang_string('mailboxconfiguration', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundmailboxconfiguration_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_mailbox',
|
||||
new lang_string('mailbox', 'tool_messageinbound'),
|
||||
null, '', PARAM_RAW));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_domain',
|
||||
new lang_string('domain', 'tool_messageinbound'),
|
||||
null, '', PARAM_RAW));
|
||||
|
||||
// These settings are used when checking the incoming mailbox for mail.
|
||||
$settings->add(new admin_setting_heading('messageinbound_serversettings',
|
||||
new lang_string('incomingmailserversettings', 'tool_messageinbound'),
|
||||
new lang_string('incomingmailserversettings_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_host',
|
||||
new lang_string('messageinboundhost', 'tool_messageinbound'),
|
||||
new lang_string('configmessageinboundhost', 'tool_messageinbound'), '', PARAM_RAW));
|
||||
|
||||
$options = array(
|
||||
'' => get_string('noencryption', 'tool_messageinbound'),
|
||||
'ssl' => get_string('ssl', 'tool_messageinbound'),
|
||||
'sslv2' => get_string('sslv2', 'tool_messageinbound'),
|
||||
'sslv3' => get_string('sslv3', 'tool_messageinbound'),
|
||||
'tls' => get_string('tls', 'tool_messageinbound'),
|
||||
'tlsv1' => get_string('tlsv1', 'tool_messageinbound'),
|
||||
);
|
||||
$settings->add(new admin_setting_configselect('messageinbound_hostssl',
|
||||
new lang_string('messageinboundhostssl', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundhostssl_desc', 'tool_messageinbound'), 'ssl', $options));
|
||||
|
||||
$settings->add(new admin_setting_configtext('messageinbound_hostuser',
|
||||
new lang_string('messageinboundhostuser', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundhostuser_desc', 'tool_messageinbound'), '', PARAM_NOTAGS));
|
||||
$settings->add(new admin_setting_configpasswordunmask('messageinbound_hostpass',
|
||||
new lang_string('messageinboundhostpass', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundhostpass_desc', 'tool_messageinbound'), ''));
|
||||
|
||||
$category->add('messageinbound', $settings);
|
||||
|
||||
// Link to the external page for Inbound Message handler configuration.
|
||||
$category->add('messageinbound', new admin_externalpage('messageinbound_handlers',
|
||||
new lang_string('message_handlers', 'tool_messageinbound'),
|
||||
"$CFG->wwwroot/$CFG->admin/tool/messageinbound/index.php"));
|
||||
|
||||
// Add the category to the admin tree.
|
||||
$ADMIN->add('server', $category);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#page-admin-tool-messageinbound-index .handler-function {
|
||||
display: block;
|
||||
padding: 0 0.5em;
|
||||
color: #888;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
#page-admin-tool-messageinbound-index .state,
|
||||
#page-admin-tool-messageinbound-index .edit {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -45,7 +45,7 @@
|
||||
$message = '<br /><br />';
|
||||
$message .= $CFG->tempdir.'/olson.txt<br />';
|
||||
$message .= $CFG->tempdir.'/timezone.txt<br />';
|
||||
$message .= '<a href="https://download.moodle.org/timezone/">https://download.moodle.org/timezone/</a><br />';
|
||||
$message .= '<a href="http://download.moodle.org/timezone/">http://download.moodle.org/timezone/</a><br />';
|
||||
$message .= '<a href="'.$CFG->wwwroot.'/lib/timezone.txt">'.$CFG->dirroot.'/lib/timezone.txt</a><br />';
|
||||
$message .= '<br />';
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
}
|
||||
|
||||
/// Otherwise, let's try moodle.org's copy
|
||||
$source = 'https://download.moodle.org/timezone/';
|
||||
$source = 'http://download.moodle.org/timezone/';
|
||||
if (!$importdone && ($content=download_file_content($source))) {
|
||||
if ($file = fopen($CFG->tempdir.'/timezone.txt', 'w')) { // Make local copy
|
||||
fwrite($file, $content);
|
||||
|
||||
@@ -850,15 +850,6 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
$cohort = $DB->get_record('cohort', array('id'=>$addcohort));
|
||||
} else {
|
||||
$cohort = $DB->get_record('cohort', array('idnumber'=>$addcohort));
|
||||
if (empty($cohort) && has_capability('moodle/cohort:manage', context_system::instance())) {
|
||||
// Cohort was not found. Create a new one.
|
||||
$cohortid = cohort_add_cohort((object)array(
|
||||
'idnumber' => $addcohort,
|
||||
'name' => $addcohort,
|
||||
'contextid' => context_system::instance()->id
|
||||
));
|
||||
$cohort = $DB->get_record('cohort', array('id'=>$cohortid));
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($cohort)) {
|
||||
|
||||
@@ -221,21 +221,21 @@ class admin_uploaduser_form2 extends moodleform {
|
||||
|
||||
$choices = array(0 => get_string('emaildisplayno'), 1 => get_string('emaildisplayyes'), 2 => get_string('emaildisplaycourse'));
|
||||
$mform->addElement('select', 'maildisplay', get_string('emaildisplay'), $choices);
|
||||
$mform->setDefault('maildisplay', $CFG->defaultpreference_maildisplay);
|
||||
$mform->setDefault('maildisplay', 2);
|
||||
|
||||
$choices = array(0 => get_string('textformat'), 1 => get_string('htmlformat'));
|
||||
$mform->addElement('select', 'mailformat', get_string('emailformat'), $choices);
|
||||
$mform->setDefault('mailformat', $CFG->defaultpreference_mailformat);
|
||||
$mform->setDefault('mailformat', 1);
|
||||
$mform->setAdvanced('mailformat');
|
||||
|
||||
$choices = array(0 => get_string('emaildigestoff'), 1 => get_string('emaildigestcomplete'), 2 => get_string('emaildigestsubjects'));
|
||||
$mform->addElement('select', 'maildigest', get_string('emaildigest'), $choices);
|
||||
$mform->setDefault('maildigest', $CFG->defaultpreference_maildigest);
|
||||
$mform->setDefault('maildigest', 0);
|
||||
$mform->setAdvanced('maildigest');
|
||||
|
||||
$choices = array(1 => get_string('autosubscribeyes'), 0 => get_string('autosubscribeno'));
|
||||
$mform->addElement('select', 'autosubscribe', get_string('autosubscribe'), $choices);
|
||||
$mform->setDefault('autosubscribe', $CFG->defaultpreference_autosubscribe);
|
||||
$mform->setDefault('autosubscribe', 1);
|
||||
|
||||
$mform->addElement('text', 'city', get_string('city'), 'maxlength="120" size="25"');
|
||||
$mform->setType('city', PARAM_TEXT);
|
||||
|
||||
+32
-31
@@ -46,8 +46,6 @@
|
||||
|
||||
$returnurl = new moodle_url('/admin/user.php', array('sort' => $sort, 'dir' => $dir, 'perpage' => $perpage, 'page'=>$page));
|
||||
|
||||
// The $user variable is also used outside of these if statements.
|
||||
$user = null;
|
||||
if ($confirmuser and confirm_sesskey()) {
|
||||
require_capability('moodle/user:update', $sitecontext);
|
||||
if (!$user = $DB->get_record('user', array('id'=>$confirmuser, 'mnethostid'=>$CFG->mnet_localhost_id))) {
|
||||
@@ -160,9 +158,8 @@
|
||||
// Carry on with the user listing
|
||||
$context = context_system::instance();
|
||||
$extracolumns = get_extra_user_fields($context);
|
||||
// Get all user name fields as an array.
|
||||
$allusernamefields = get_all_user_name_fields(false, null, null, null, true);
|
||||
$columns = array_merge($allusernamefields, $extracolumns, array('city', 'country', 'lastaccess'));
|
||||
$columns = array_merge(array('firstname', 'lastname'), $extracolumns,
|
||||
array('city', 'country', 'lastaccess'));
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$string[$column] = get_user_field_name($column);
|
||||
@@ -186,28 +183,22 @@
|
||||
$$column = "<a href=\"user.php?sort=$column&dir=$columndir\">".$string[$column]."</a>$columnicon";
|
||||
}
|
||||
|
||||
// We need to check that alternativefullnameformat is not set to '' or language.
|
||||
// We don't need to check the fullnamedisplay setting here as the fullname function call further down has
|
||||
// the override parameter set to true.
|
||||
$fullnamesetting = $CFG->alternativefullnameformat;
|
||||
// If we are using language or it is empty, then retrieve all of the user's names.
|
||||
if ($fullnamesetting == 'language' || empty($fullnamesetting)) {
|
||||
$fullnamesetting = implode(' ', $allusernamefields);
|
||||
}
|
||||
|
||||
// Order in string will ensure that the name columns are in the correct order.
|
||||
$usernames = order_in_string($allusernamefields, $fullnamesetting);
|
||||
$fullnamedisplay = array();
|
||||
foreach ($usernames as $name) {
|
||||
// Use the link from $$column for sorting on the user's name.
|
||||
$fullnamedisplay[] = ${$name};
|
||||
}
|
||||
// All of the names are in one column. Put them into a string and separate them with a /.
|
||||
$fullnamedisplay = implode(' / ', $fullnamedisplay);
|
||||
// If $sort = name then it is the default for the setting and we should use the first name to sort by.
|
||||
if ($sort == "name") {
|
||||
// Use the first item in the array.
|
||||
$sort = reset($usernames);
|
||||
$override = new stdClass();
|
||||
$override->firstname = 'firstname';
|
||||
$override->lastname = 'lastname';
|
||||
$fullnamelanguage = get_string('fullnamedisplay', '', $override);
|
||||
if (($CFG->fullnamedisplay == 'firstname lastname') or
|
||||
($CFG->fullnamedisplay == 'firstname') or
|
||||
($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'firstname lastname' )) {
|
||||
$fullnamedisplay = "$firstname / $lastname";
|
||||
if ($sort == "name") { // If sort has already been set to something else then ignore.
|
||||
$sort = "firstname";
|
||||
}
|
||||
} else { // ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'lastname firstname').
|
||||
$fullnamedisplay = "$lastname / $firstname";
|
||||
if ($sort == "name") { // This should give the desired sorting based on fullnamedisplay.
|
||||
$sort = "lastname";
|
||||
}
|
||||
}
|
||||
|
||||
list($extrasql, $params) = $ufiltering->get_sql_filter();
|
||||
@@ -265,12 +256,17 @@
|
||||
$table->colclasses = array();
|
||||
$table->head[] = $fullnamedisplay;
|
||||
$table->attributes['class'] = 'admintable generaltable';
|
||||
$table->colclasses[] = 'leftalign';
|
||||
foreach ($extracolumns as $field) {
|
||||
$table->head[] = ${$field};
|
||||
$table->colclasses[] = 'leftalign';
|
||||
}
|
||||
$table->head[] = $city;
|
||||
$table->colclasses[] = 'leftalign';
|
||||
$table->head[] = $country;
|
||||
$table->colclasses[] = 'leftalign';
|
||||
$table->head[] = $lastaccess;
|
||||
$table->colclasses[] = 'leftalign';
|
||||
$table->head[] = get_string('edit');
|
||||
$table->colclasses[] = 'centeralign';
|
||||
$table->head[] = "";
|
||||
@@ -373,15 +369,20 @@
|
||||
$ufiltering->display_add();
|
||||
$ufiltering->display_active();
|
||||
|
||||
if (has_capability('moodle/user:create', $sitecontext)) {
|
||||
echo $OUTPUT->heading('<a href="'.$securewwwroot.'/user/editadvanced.php?id=-1">'.get_string('addnewuser').'</a>');
|
||||
}
|
||||
if (!empty($table)) {
|
||||
echo html_writer::start_tag('div', array('class'=>'no-overflow'));
|
||||
echo html_writer::table($table);
|
||||
echo html_writer::end_tag('div');
|
||||
echo $OUTPUT->paging_bar($usercount, $page, $perpage, $baseurl);
|
||||
}
|
||||
if (has_capability('moodle/user:create', $sitecontext)) {
|
||||
$url = new moodle_url($securewwwroot . '/user/editadvanced.php', array('id' => -1));
|
||||
echo $OUTPUT->single_button($url, get_string('addnewuser'), 'get');
|
||||
if (has_capability('moodle/user:create', $sitecontext)) {
|
||||
echo $OUTPUT->heading('<a href="'.$securewwwroot.'/user/editadvanced.php?id=-1">'.get_string('addnewuser').'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
|
||||
|
||||
|
||||
+349
-261
@@ -63,7 +63,7 @@ if (!defined('E_USER_DEPRECATED')) {
|
||||
/**
|
||||
* phpCAS version. accessible for the user by phpCAS::getVersion().
|
||||
*/
|
||||
define('PHPCAS_VERSION', '1.3.3');
|
||||
define('PHPCAS_VERSION', '1.3.2');
|
||||
|
||||
/**
|
||||
* @addtogroup public
|
||||
@@ -78,10 +78,6 @@ define("CAS_VERSION_1_0", '1.0');
|
||||
* CAS version 2.0
|
||||
*/
|
||||
define("CAS_VERSION_2_0", '2.0');
|
||||
/**
|
||||
* CAS version 3.0
|
||||
*/
|
||||
define("CAS_VERSION_3_0", '3.0');
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// SAML defines
|
||||
@@ -322,6 +318,18 @@ class phpCAS
|
||||
if (is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
|
||||
}
|
||||
if (gettype($server_version) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');
|
||||
}
|
||||
if (gettype($server_hostname) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');
|
||||
}
|
||||
if (gettype($server_port) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');
|
||||
}
|
||||
if (gettype($server_uri) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');
|
||||
}
|
||||
|
||||
// store where the initializer is called from
|
||||
$dbg = debug_backtrace();
|
||||
@@ -333,14 +341,10 @@ class phpCAS
|
||||
);
|
||||
|
||||
// initialize the object $_PHPCAS_CLIENT
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, false, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, false, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -366,6 +370,18 @@ class phpCAS
|
||||
if (is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
|
||||
}
|
||||
if (gettype($server_version) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');
|
||||
}
|
||||
if (gettype($server_hostname) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');
|
||||
}
|
||||
if (gettype($server_port) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');
|
||||
}
|
||||
if (gettype($server_uri) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');
|
||||
}
|
||||
|
||||
// store where the initialzer is called from
|
||||
$dbg = debug_backtrace();
|
||||
@@ -377,14 +393,10 @@ class phpCAS
|
||||
);
|
||||
|
||||
// initialize the object $_PHPCAS_CLIENT
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, true, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, true, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -624,13 +636,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setLang($lang)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setLang($lang);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($lang) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $lang (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setLang($lang);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -670,13 +682,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setHTMLHeader($header)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setHTMLHeader($header);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($header) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $header (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setHTMLHeader($header);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -688,13 +700,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setHTMLFooter($footer)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($footer) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $footer (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -717,13 +729,19 @@ class phpCAS
|
||||
public static function setPGTStorage($storage)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setPGTStorage($storage);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
|
||||
}
|
||||
if ( !($storage instanceof CAS_PGTStorage) ) {
|
||||
phpCAS :: error('type mismatched for parameter $storage (should be a CAS_PGTStorage `object\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setPGTStorage($storage);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -748,13 +766,25 @@ class phpCAS
|
||||
$password='', $table='', $driver_options=null
|
||||
) {
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
|
||||
}
|
||||
if (gettype($username) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $username (should be `string\')');
|
||||
}
|
||||
if (gettype($password) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $password (should be `string\')');
|
||||
}
|
||||
if (gettype($table) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $table (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -769,13 +799,19 @@ class phpCAS
|
||||
public static function setPGTStorageFile($path = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
|
||||
}
|
||||
if (gettype($path) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $path (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
/** @} */
|
||||
@@ -800,13 +836,23 @@ class phpCAS
|
||||
public static function getProxiedService ($type)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
$res = self::$_PHPCAS_CLIENT->getProxiedService($type);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
if (gettype($type) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $type (should be `string\')');
|
||||
}
|
||||
|
||||
$res = self::$_PHPCAS_CLIENT->getProxiedService($type);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
return $res;
|
||||
@@ -826,13 +872,20 @@ class phpCAS
|
||||
*/
|
||||
public static function initializeProxiedService (CAS_ProxiedService $proxiedService)
|
||||
{
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
|
||||
self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -853,13 +906,23 @@ class phpCAS
|
||||
public static function serviceWeb($url, & $err_code, & $output)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
$res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
|
||||
$res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
|
||||
|
||||
phpCAS :: traceEnd($res);
|
||||
return $res;
|
||||
@@ -887,13 +950,27 @@ class phpCAS
|
||||
public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
$res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
|
||||
if (gettype($flags) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $flags (should be `integer\')');
|
||||
}
|
||||
|
||||
$res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
|
||||
|
||||
phpCAS :: traceEnd($res);
|
||||
return $res;
|
||||
@@ -921,13 +998,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setCacheTimesForAuthRecheck($n)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($n) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $n (should be `integer\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -951,7 +1028,9 @@ class phpCAS
|
||||
*/
|
||||
public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);
|
||||
}
|
||||
@@ -972,7 +1051,9 @@ class phpCAS
|
||||
*/
|
||||
public static function setSingleSignoutCallback ($function, array $additionalArgs = array())
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);
|
||||
}
|
||||
@@ -990,7 +1071,9 @@ class phpCAS
|
||||
public static function checkAuthentication()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
$auth = self::$_PHPCAS_CLIENT->checkAuthentication();
|
||||
|
||||
@@ -1011,13 +1094,16 @@ class phpCAS
|
||||
public static function forceAuthentication()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
$auth = self::$_PHPCAS_CLIENT->forceAuthentication();
|
||||
|
||||
// store where the authentication has been checked and the result
|
||||
self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
|
||||
|
||||
/* if (!$auth) {
|
||||
/* if (!$auth) {
|
||||
phpCAS :: trace('user is not authenticated, redirecting to the CAS server');
|
||||
self::$_PHPCAS_CLIENT->forceAuthentication();
|
||||
} else {
|
||||
@@ -1036,8 +1122,9 @@ class phpCAS
|
||||
public static function renewAuthentication()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
$auth = self::$_PHPCAS_CLIENT->renewAuthentication();
|
||||
|
||||
// store where the authentication has been checked and the result
|
||||
@@ -1056,7 +1143,9 @@ class phpCAS
|
||||
public static function isAuthenticated()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
// call the isAuthenticated method of the $_PHPCAS_CLIENT object
|
||||
$auth = self::$_PHPCAS_CLIENT->isAuthenticated();
|
||||
@@ -1077,8 +1166,9 @@ class phpCAS
|
||||
*/
|
||||
public static function isSessionAuthenticated()
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());
|
||||
}
|
||||
|
||||
@@ -1086,56 +1176,65 @@ class phpCAS
|
||||
* This method returns the CAS user's login name.
|
||||
*
|
||||
* @return string the login name of the authenticated user
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
* */
|
||||
public static function getUser()
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->getUser();
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer attributes about the authenticated user.
|
||||
*
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAttributes()
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->getAttributes();
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer true if there are attributes for the authenticated user.
|
||||
*
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasAttributes()
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->hasAttributes();
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->hasAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1144,18 +1243,21 @@ class phpCAS
|
||||
* @param string $key attribute name
|
||||
*
|
||||
* @return bool
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*/
|
||||
public static function hasAttribute($key)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->hasAttribute($key);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->hasAttribute($key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1164,18 +1266,21 @@ class phpCAS
|
||||
* @param string $key attribute name
|
||||
*
|
||||
* @return mixed string for a single value or an array if multiple values exist.
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*/
|
||||
public static function getAttribute($key)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->getAttribute($key);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getAttribute($key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1188,8 +1293,9 @@ class phpCAS
|
||||
*/
|
||||
public static function handleLogoutRequests($check_client = true, $allowed_clients = false)
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));
|
||||
}
|
||||
|
||||
@@ -1201,8 +1307,9 @@ class phpCAS
|
||||
*/
|
||||
public static function getServerLoginURL()
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getServerLoginURL();
|
||||
}
|
||||
|
||||
@@ -1217,14 +1324,13 @@ class phpCAS
|
||||
public static function setServerLoginURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerLoginURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
}
|
||||
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string`)');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerLoginURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1239,14 +1345,13 @@ class phpCAS
|
||||
public static function setServerServiceValidateURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
}
|
||||
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string`)');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1261,14 +1366,13 @@ class phpCAS
|
||||
public static function setServerProxyValidateURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
}
|
||||
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string`)');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1282,14 +1386,13 @@ class phpCAS
|
||||
public static function setServerSamlValidateURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
}
|
||||
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be`string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1301,8 +1404,9 @@ class phpCAS
|
||||
*/
|
||||
public static function getServerLogoutURL()
|
||||
{
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getServerLogoutURL();
|
||||
}
|
||||
|
||||
@@ -1317,14 +1421,17 @@ class phpCAS
|
||||
public static function setServerLogoutURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error(
|
||||
'this method should only be called after' . __CLASS__ . '::client()'
|
||||
);
|
||||
}
|
||||
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error(
|
||||
'type mismatched for parameter $url (should be `string`)'
|
||||
);
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1339,8 +1446,9 @@ class phpCAS
|
||||
public static function logout($params = "")
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
$parsedParams = array ();
|
||||
if ($params != "") {
|
||||
if (is_string($params)) {
|
||||
@@ -1372,8 +1480,9 @@ class phpCAS
|
||||
public static function logoutWithRedirectService($service)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!is_string($service)) {
|
||||
phpCAS :: error('type mismatched for parameter $service (should be `string\')');
|
||||
}
|
||||
@@ -1423,8 +1532,9 @@ class phpCAS
|
||||
{
|
||||
trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!is_string($service)) {
|
||||
phpCAS :: error('type mismatched for parameter $service (should be `string\')');
|
||||
}
|
||||
@@ -1453,14 +1563,16 @@ class phpCAS
|
||||
public static function setFixedCallbackURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setCallbackURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setCallbackURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1475,14 +1587,13 @@ class phpCAS
|
||||
public static function setFixedServiceURL($url)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setURL($url);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1493,7 +1604,9 @@ class phpCAS
|
||||
*/
|
||||
public static function getServiceURL()
|
||||
{
|
||||
phpCAS::_validateProxyExists();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
return (self::$_PHPCAS_CLIENT->getURL());
|
||||
}
|
||||
|
||||
@@ -1508,13 +1621,13 @@ class phpCAS
|
||||
*/
|
||||
public static function retrievePT($target_service, & $err_code, & $err_msg)
|
||||
{
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($target_service) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $target_service(should be `string\')');
|
||||
}
|
||||
return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1529,14 +1642,16 @@ class phpCAS
|
||||
public static function setCasServerCACert($cert, $validate_cn = true)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
if (gettype($cert) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $cert (should be `string\')');
|
||||
}
|
||||
if (gettype($validate_cn) != 'boolean') {
|
||||
phpCAS :: error('type mismatched for parameter $validate_cn (should be `boolean\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1548,8 +1663,9 @@ class phpCAS
|
||||
public static function setNoCasServerValidation()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');
|
||||
self::$_PHPCAS_CLIENT->setNoCasServerValidation();
|
||||
phpCAS :: traceEnd();
|
||||
@@ -1568,8 +1684,9 @@ class phpCAS
|
||||
public static function setNoClearTicketsFromUrl()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
@@ -1588,8 +1705,9 @@ class phpCAS
|
||||
public static function setExtraCurlOption($key, $value)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
@@ -1633,11 +1751,11 @@ class phpCAS
|
||||
public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0
|
||||
&& self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0) {
|
||||
phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols');
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0) {
|
||||
phpCAS :: error('this method can only be used with the cas 2.0 protool');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);
|
||||
phpCAS :: traceEnd();
|
||||
@@ -1654,7 +1772,9 @@ class phpCAS
|
||||
*/
|
||||
public static function getProxies ()
|
||||
{
|
||||
phpCAS::_validateProxyExists();
|
||||
if ( !is_object(self::$_PHPCAS_CLIENT) ) {
|
||||
phpCAS::error('this method should only be called after '.__CLASS__.'::client()');
|
||||
}
|
||||
|
||||
return(self::$_PHPCAS_CLIENT->getProxies());
|
||||
}
|
||||
@@ -1675,14 +1795,13 @@ class phpCAS
|
||||
{
|
||||
phpCAS::traceBegin();
|
||||
phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl)) {
|
||||
phpCAS::error('type mismatched for parameter $rebroadcastNodeUrl (should be `url\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
|
||||
phpCAS::traceEnd();
|
||||
}
|
||||
|
||||
@@ -1697,45 +1816,14 @@ class phpCAS
|
||||
public static function addRebroadcastHeader($header)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a client already exists
|
||||
*
|
||||
* @throws CAS_OutOfSequenceBeforeClientException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function _validateClientExists()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
throw new CAS_OutOfSequenceBeforeClientException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks of a proxy client aready exists
|
||||
*
|
||||
* @throws CAS_OutOfSequenceBeforeProxyException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function _validateProxyExists()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
throw new CAS_OutOfSequenceBeforeProxyException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ########################################################################
|
||||
// DOCUMENTATION
|
||||
// ########################################################################
|
||||
|
||||
@@ -74,7 +74,7 @@ implements CAS_Exception
|
||||
printf(
|
||||
$lang->getYouWereNotAuthenticated(),
|
||||
htmlentities($client->getURL()),
|
||||
isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
|
||||
$_SERVER['SERVER_ADMIN']
|
||||
);
|
||||
phpCAS::trace('CAS URL: '.$cas_url);
|
||||
phpCAS::trace('Authentication failure: '.$failure);
|
||||
@@ -89,7 +89,6 @@ implements CAS_Exception
|
||||
phpCAS::trace('Reason: CAS error');
|
||||
break;
|
||||
case CAS_VERSION_2_0:
|
||||
case CAS_VERSION_3_0:
|
||||
if ( empty($err_code) ) {
|
||||
phpCAS::trace('Reason: no CAS error');
|
||||
} else {
|
||||
|
||||
@@ -25,39 +25,35 @@ function CAS_autoload($class)
|
||||
{
|
||||
// Static to hold the Include Path to CAS
|
||||
static $include_path;
|
||||
// Check only for CAS classes
|
||||
// Setup the include path if it's not already set from a previous call
|
||||
if (!$include_path) {
|
||||
$include_path = dirname(dirname(__FILE__));
|
||||
}
|
||||
if (substr($class, 0, 4) !== 'CAS_') {
|
||||
return false;
|
||||
}
|
||||
// Setup the include path if it's not already set from a previous call
|
||||
if (empty($include_path)) {
|
||||
$include_path = array(dirname(dirname(__FILE__)), dirname(dirname(__FILE__)) . '/../test/' );
|
||||
}
|
||||
|
||||
// Declare local variable to store the expected full path to the file
|
||||
$file_path = $include_path . '/' . str_replace('_', '/', $class) . '.php';
|
||||
|
||||
foreach ($include_path as $path) {
|
||||
$file_path = $path . '/' . str_replace('_', '/', $class) . '.php';
|
||||
$fp = @fopen($file_path, 'r', true);
|
||||
if ($fp) {
|
||||
fclose($fp);
|
||||
include $file_path;
|
||||
if (!class_exists($class, false) && !interface_exists($class, false)) {
|
||||
die(
|
||||
new Exception(
|
||||
'Class ' . $class . ' was not present in ' .
|
||||
$file_path .
|
||||
' [CAS_autoload]'
|
||||
)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
$fp = @fopen($file_path, 'r', true);
|
||||
if ($fp) {
|
||||
fclose($fp);
|
||||
include $file_path;
|
||||
if (!class_exists($class, false) && !interface_exists($class, false)) {
|
||||
die(
|
||||
new Exception(
|
||||
'Class ' . $class . ' was not present in ' .
|
||||
$file_path .
|
||||
' [CAS_autoload]'
|
||||
)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
$e = new Exception(
|
||||
'Class ' . $class . ' could not be loaded from ' .
|
||||
$file_path . ', file does not exist (Path="'
|
||||
. implode(':', $include_path) .'") [CAS_autoload]'
|
||||
. $include_path .'") [CAS_autoload]'
|
||||
);
|
||||
$trace = $e->getTrace();
|
||||
if (isset($trace[2]) && isset($trace[2]['function'])
|
||||
@@ -75,13 +71,9 @@ function CAS_autoload($class)
|
||||
|
||||
// set up __autoload
|
||||
if (function_exists('spl_autoload_register')) {
|
||||
if (!(spl_autoload_functions())
|
||||
|| !in_array('CAS_autoload', spl_autoload_functions())
|
||||
) {
|
||||
if (!(spl_autoload_functions()) || !in_array('CAS_autoload', spl_autoload_functions())) {
|
||||
spl_autoload_register('CAS_autoload');
|
||||
if (function_exists('__autoload')
|
||||
&& !in_array('__autoload', spl_autoload_functions())
|
||||
) {
|
||||
if (function_exists('__autoload') && !in_array('__autoload', spl_autoload_functions())) {
|
||||
// __autoload() was being used, but now would be ignored, add
|
||||
// it to the autoload stack
|
||||
spl_autoload_register('__autoload');
|
||||
|
||||
+137
-571
File diff suppressed because it is too large
Load Diff
@@ -161,9 +161,7 @@ class CAS_CookieJar
|
||||
protected function parseCookieHeader ($line, $defaultDomain)
|
||||
{
|
||||
if (!$defaultDomain) {
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'$defaultDomain was not provided.'
|
||||
);
|
||||
throw new CAS_InvalidArgumentException('$defaultDomain was not provided.');
|
||||
}
|
||||
|
||||
// Set our default values
|
||||
@@ -317,14 +315,10 @@ class CAS_CookieJar
|
||||
protected function cookieMatchesTarget ($cookie, $target)
|
||||
{
|
||||
if (!is_array($target)) {
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'$target must be an array of URL attributes as generated by parse_url().'
|
||||
);
|
||||
throw new CAS_InvalidArgumentException('$target must be an array of URL attributes as generated by parse_url().');
|
||||
}
|
||||
if (!isset($target['host'])) {
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'$target must be an array of URL attributes as generated by parse_url().'
|
||||
);
|
||||
throw new CAS_InvalidArgumentException('$target must be an array of URL attributes as generated by parse_url().');
|
||||
}
|
||||
|
||||
// Verify that the scheme matches
|
||||
@@ -358,17 +352,15 @@ class CAS_CookieJar
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the cookie host doesn't begin with '.',
|
||||
// the host must case-insensitive match exactly
|
||||
// If the cookie host doesn't begin with '.', the host must case-insensitive
|
||||
// match exactly
|
||||
if (strcasecmp($target['host'], $cookie['domain']) !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the port matches
|
||||
if (isset($cookie['ports'])
|
||||
&& !in_array($target['port'], $cookie['ports'])
|
||||
) {
|
||||
if (isset($cookie['ports']) && !in_array($target['port'], $cookie['ports'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class CAS_Languages_German implements CAS_Languages_LanguageInterface
|
||||
*/
|
||||
public function getYouWereNotAuthenticated()
|
||||
{
|
||||
return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontaktieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>';
|
||||
return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontkatieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,4 +113,4 @@ class CAS_Languages_German implements CAS_Languages_LanguageInterface
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeAuthenticationCallException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines Exceptions that should be thrown when the sequence of
|
||||
* operations is invalid. In this case it should be thrown when an
|
||||
* authentication call has not yet happened.
|
||||
*
|
||||
* @class CAS_OutOfSequenceBeforeAuthenticationCallException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_OutOfSequenceBeforeAuthenticationCallException
|
||||
extends CAS_OutOfSequenceException
|
||||
implements CAS_Exception
|
||||
{
|
||||
/**
|
||||
* Return standard error meessage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
parent::__construct('An authentication call hasn\'t happened yet.');
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeClientException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines Exceptions that should be thrown when the sequence of
|
||||
* operations is invalid. In this case it should be thrown when the client() or
|
||||
* proxy() call has not yet happened and no client or proxy object exists.
|
||||
*
|
||||
* @class CAS_OutOfSequenceBeforeClientException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_OutOfSequenceBeforeClientException
|
||||
extends CAS_OutOfSequenceException
|
||||
implements CAS_Exception
|
||||
{
|
||||
/**
|
||||
* Return standard error message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
parent::__construct(
|
||||
'this method cannot be called before phpCAS::client() or phpCAS::proxy()'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeProxyException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines Exceptions that should be thrown when the sequence of
|
||||
* operations is invalid. In this case it should be thrown when the proxy() call
|
||||
* has not yet happened and no proxy object exists.
|
||||
*
|
||||
* @class CAS_OutOfSequenceBeforeProxyException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_OutOfSequenceBeforeProxyException
|
||||
extends CAS_OutOfSequenceException
|
||||
implements CAS_Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* Return standard error message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
parent::__construct(
|
||||
'this method cannot be called before phpCAS::proxy()'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -68,9 +68,7 @@ abstract class CAS_PGTStorage_AbstractStorage
|
||||
{
|
||||
phpCAS::traceBegin();
|
||||
if ( !$cas_parent->isProxy() ) {
|
||||
phpCAS::error(
|
||||
'defining PGT storage makes no sense when not using a CAS proxy'
|
||||
);
|
||||
phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy');
|
||||
}
|
||||
phpCAS::traceEnd();
|
||||
}
|
||||
|
||||
@@ -135,10 +135,8 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
* @param string $driver_options any driver options to use when
|
||||
* connecting to the database
|
||||
*/
|
||||
public function __construct(
|
||||
$cas_parent, $dsn_or_pdo, $username='', $password='', $table='',
|
||||
$driver_options=null
|
||||
) {
|
||||
public function __construct($cas_parent, $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
|
||||
{
|
||||
phpCAS::traceBegin();
|
||||
// call the ancestor's constructor
|
||||
parent::__construct($cas_parent);
|
||||
@@ -190,10 +188,7 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
// create the PDO object if it doesn't exist already
|
||||
if (!($this->_pdo instanceof PDO)) {
|
||||
try {
|
||||
$this->_pdo = new PDO(
|
||||
$this->_dsn, $this->_username, $this->_password,
|
||||
$this->_driver_options
|
||||
);
|
||||
$this->_pdo = new PDO($this->_dsn, $this->_username, $this->_password, $this->_driver_options);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
phpCAS::error('Database connection error: ' . $e->getMessage());
|
||||
@@ -252,28 +247,23 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
*/
|
||||
protected function createTableSql()
|
||||
{
|
||||
return 'CREATE TABLE ' . $this->_getTable()
|
||||
. ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';
|
||||
return 'CREATE TABLE ' . $this->_getTable() . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the query used to store a pgt
|
||||
*
|
||||
* @return the store PGT SQL, :pgt and :pgt_iou are the bind params contained
|
||||
* in the query
|
||||
* @return the store PGT SQL, :pgt and :pgt_iou are the bind params contained in the query
|
||||
*/
|
||||
protected function storePgtSql()
|
||||
{
|
||||
return 'INSERT INTO ' . $this->_getTable()
|
||||
. ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';
|
||||
return 'INSERT INTO ' . $this->_getTable() . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the query used to retrieve a pgt. the first column
|
||||
* of the first row should contain the pgt
|
||||
* This method returns the query used to retrieve a pgt. the first column of the first row should contain the pgt
|
||||
*
|
||||
* @return the retrieve PGT SQL, :pgt_iou is the only bind param contained
|
||||
* in the query
|
||||
* @return the retrieve PGT SQL, :pgt_iou is the only bind param contained in the query
|
||||
*/
|
||||
protected function retrievePgtSql()
|
||||
{
|
||||
@@ -283,8 +273,7 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
/**
|
||||
* This method returns the query used to delete a pgt.
|
||||
*
|
||||
* @return the delete PGT SQL, :pgt_iou is the only bind param contained in
|
||||
* the query
|
||||
* @return the delete PGT SQL, :pgt_iou is the only bind param contained in the query
|
||||
*/
|
||||
protected function deletePgtSql()
|
||||
{
|
||||
|
||||
@@ -55,20 +55,15 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
*
|
||||
* @return void
|
||||
* @throws InvalidArgumentException If the $proxyTicket is invalid.
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has
|
||||
* already been initialized/set.
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has already been initialized/set.
|
||||
*/
|
||||
public function setProxyTicket ($proxyTicket)
|
||||
{
|
||||
if (empty($proxyTicket)) {
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'Trying to initialize with an empty proxy ticket.'
|
||||
);
|
||||
throw new CAS_InvalidArgumentException("Trying to initialize with an empty proxy ticket.");
|
||||
}
|
||||
if (!empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Already initialized, cannot change the proxy ticket.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Already initialized, cannot change the proxy ticket.');
|
||||
}
|
||||
$this->_proxyTicket = $proxyTicket;
|
||||
}
|
||||
@@ -83,9 +78,7 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
protected function getProxyTicket ()
|
||||
{
|
||||
if (empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.');
|
||||
}
|
||||
|
||||
return $this->_proxyTicket;
|
||||
@@ -112,9 +105,7 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
public function setCasClient (CAS_Client $casClient)
|
||||
{
|
||||
if (!empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Already initialized, cannot change the CAS_Client.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Already initialized, cannot change the CAS_Client.');
|
||||
}
|
||||
|
||||
$this->_casClient = $casClient;
|
||||
@@ -133,9 +124,7 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
protected function initializeProxyTicket()
|
||||
{
|
||||
if (!empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Already initialized, cannot initialize again.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Already initialized, cannot initialize again.');
|
||||
}
|
||||
// Allow usage of a particular CAS_Client for unit testing.
|
||||
if (empty($this->_casClient)) {
|
||||
|
||||
@@ -38,8 +38,9 @@
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
abstract class CAS_ProxiedService_Http_Abstract extends
|
||||
CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
abstract class CAS_ProxiedService_Http_Abstract
|
||||
extends CAS_ProxiedService_Abstract
|
||||
implements CAS_ProxiedService_Http
|
||||
{
|
||||
/**
|
||||
* The HTTP request mechanism talking to the target service.
|
||||
@@ -63,9 +64,8 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(CAS_Request_RequestInterface $requestHandler,
|
||||
CAS_CookieJar $cookieJar
|
||||
) {
|
||||
public function __construct (CAS_Request_RequestInterface $requestHandler, CAS_CookieJar $cookieJar)
|
||||
{
|
||||
$this->requestHandler = $requestHandler;
|
||||
$this->_cookieJar = $cookieJar;
|
||||
}
|
||||
@@ -82,12 +82,10 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @return string
|
||||
* @throws Exception If no service url is available.
|
||||
*/
|
||||
public function getServiceUrl()
|
||||
public function getServiceUrl ()
|
||||
{
|
||||
if (empty($this->_url)) {
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
'No URL set via ' . get_class($this) . '->setUrl($url).'
|
||||
);
|
||||
throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->setUrl($url).');
|
||||
}
|
||||
|
||||
return $this->_url;
|
||||
@@ -95,7 +93,7 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
|
||||
/*********************************************************
|
||||
* Configure the Request
|
||||
*********************************************************/
|
||||
*********************************************************/
|
||||
|
||||
/**
|
||||
* Set the URL of the Request
|
||||
@@ -105,12 +103,10 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @return void
|
||||
* @throws CAS_OutOfSequenceException If called after the Request has been sent.
|
||||
*/
|
||||
public function setUrl($url)
|
||||
public function setUrl ($url)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the URL, request already sent.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot set the URL, request already sent.');
|
||||
}
|
||||
if (!is_string($url)) {
|
||||
throw new CAS_InvalidArgumentException('$url must be a string.');
|
||||
@@ -121,7 +117,7 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
|
||||
/*********************************************************
|
||||
* 2. Send the Request
|
||||
*********************************************************/
|
||||
*********************************************************/
|
||||
|
||||
/**
|
||||
* Perform the request.
|
||||
@@ -136,12 +132,10 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the
|
||||
* request to the target service.
|
||||
*/
|
||||
public function send()
|
||||
public function send ()
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot send, request already sent.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot send, request already sent.');
|
||||
}
|
||||
|
||||
phpCAS::traceBegin();
|
||||
@@ -150,9 +144,9 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
$this->initializeProxyTicket();
|
||||
$url = $this->getServiceUrl();
|
||||
if (strstr($url, '?') === false) {
|
||||
$url = $url . '?ticket=' . $this->getProxyTicket();
|
||||
$url = $url.'?ticket='.$this->getProxyTicket();
|
||||
} else {
|
||||
$url = $url . '&ticket=' . $this->getProxyTicket();
|
||||
$url = $url.'&ticket='.$this->getProxyTicket();
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -205,7 +199,7 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the
|
||||
* request to the target service.
|
||||
*/
|
||||
protected function makeRequest($url)
|
||||
protected function makeRequest ($url)
|
||||
{
|
||||
// Verify that we are not in a redirect loop
|
||||
$this->_numRequests++;
|
||||
@@ -226,10 +220,9 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
$this->populateRequest($request);
|
||||
|
||||
// Perform the request.
|
||||
phpCAS::trace('Performing proxied service request to \'' . $url . '\'');
|
||||
phpCAS::trace('Performing proxied service request to \''.$url.'\'');
|
||||
if (!$request->send()) {
|
||||
$message = 'Could not perform proxied service request to URL`'
|
||||
. $url . '\'. ' . $request->getErrorMessage();
|
||||
$message = 'Could not perform proxied service request to URL`'.$url.'\'. '.$request->getErrorMessage();
|
||||
phpCAS::trace($message);
|
||||
throw new CAS_ProxiedService_Exception($message);
|
||||
}
|
||||
@@ -238,9 +231,8 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
$this->_cookieJar->storeCookies($url, $request->getResponseHeaders());
|
||||
|
||||
// Follow any redirects
|
||||
if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())
|
||||
) {
|
||||
phpCAS::trace('Found redirect:' . $redirectUrl);
|
||||
if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())) {
|
||||
phpCAS :: trace('Found redirect:'.$redirectUrl);
|
||||
$this->makeRequest($redirectUrl);
|
||||
} else {
|
||||
|
||||
@@ -257,9 +249,7 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function populateRequest(
|
||||
CAS_Request_RequestInterface $request
|
||||
);
|
||||
abstract protected function populateRequest (CAS_Request_RequestInterface $request);
|
||||
|
||||
/**
|
||||
* Answer a redirect URL if a redirect header is found, otherwise null.
|
||||
@@ -268,12 +258,11 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return string or null
|
||||
*/
|
||||
protected function getRedirectUrl(array $responseHeaders)
|
||||
protected function getRedirectUrl (array $responseHeaders)
|
||||
{
|
||||
// Check for the redirect after authentication
|
||||
foreach ($responseHeaders as $header) {
|
||||
if ( preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)
|
||||
) {
|
||||
if (preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)) {
|
||||
return trim(array_pop($matches));
|
||||
}
|
||||
}
|
||||
@@ -282,14 +271,14 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
|
||||
/*********************************************************
|
||||
* 3. Access the response
|
||||
*********************************************************/
|
||||
*********************************************************/
|
||||
|
||||
/**
|
||||
* Answer true if our request has been sent yet.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasBeenSent()
|
||||
protected function hasBeenSent ()
|
||||
{
|
||||
return ($this->_numRequests > 0);
|
||||
}
|
||||
@@ -300,12 +289,10 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @return array An array of header strings.
|
||||
* @throws CAS_OutOfSequenceException If called before the Request has been sent.
|
||||
*/
|
||||
public function getResponseHeaders()
|
||||
public function getResponseHeaders ()
|
||||
{
|
||||
if (!$this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access response, request not sent yet.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
|
||||
}
|
||||
|
||||
return $this->_responseHeaders;
|
||||
@@ -317,12 +304,10 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @return int
|
||||
* @throws CAS_OutOfSequenceException If called before the Request has been sent.
|
||||
*/
|
||||
public function getResponseStatusCode()
|
||||
public function getResponseStatusCode ()
|
||||
{
|
||||
if (!$this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access response, request not sent yet.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
|
||||
}
|
||||
|
||||
return $this->_responseStatusCode;
|
||||
@@ -334,12 +319,10 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
* @return string
|
||||
* @throws CAS_OutOfSequenceException If called before the Request has been sent.
|
||||
*/
|
||||
public function getResponseBody()
|
||||
public function getResponseBody ()
|
||||
{
|
||||
if (!$this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access response, request not sent yet.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
|
||||
}
|
||||
|
||||
return $this->_responseBody;
|
||||
@@ -351,7 +334,7 @@ CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return array An array containing cookies. E.g. array('name' => 'val');
|
||||
*/
|
||||
public function getCookies()
|
||||
public function getCookies ()
|
||||
{
|
||||
return $this->_cookieJar->getCookies($this->getServiceUrl());
|
||||
}
|
||||
|
||||
@@ -32,31 +32,30 @@
|
||||
*
|
||||
* Usage Example:
|
||||
*
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
*
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format
|
||||
* // (shouldn't happen) or CAS server failure (unlikely)
|
||||
* // so lets just stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format (shouldn't happen)
|
||||
* // or CAS server failure (unlikely) so lets just stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
*
|
||||
* @class CAS_ProxiedService_Http_Get
|
||||
* @category Authentication
|
||||
|
||||
@@ -32,33 +32,32 @@
|
||||
*
|
||||
* Usage Example:
|
||||
*
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->setContentType('text/xml');
|
||||
* $service->setBody('<?xml version="1.0"?'.'><methodCall><methodName>example.search</methodName></methodCall>');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->setContentType('text/xml');
|
||||
* $service->setBody(''<?xml version="1.0"?'.'><methodCall><methodName>example.search</methodName></methodCall>');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
*
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format
|
||||
* // (shouldn't happen) or CAS server failure (unlikely) so lets just
|
||||
* // stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format (shouldn't happen)
|
||||
* // or CAS server failure (unlikely) so lets just stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
*
|
||||
* @class CAS_ProxiedService_Http_Post
|
||||
* @category Authentication
|
||||
@@ -96,9 +95,7 @@ extends CAS_ProxiedService_Http_Abstract
|
||||
public function setContentType ($contentType)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the content type, request already sent.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot set the content type, request already sent.');
|
||||
}
|
||||
|
||||
$this->_contentType = $contentType;
|
||||
@@ -115,9 +112,7 @@ extends CAS_ProxiedService_Http_Abstract
|
||||
public function setBody ($body)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the body, request already sent.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot set the body, request already sent.');
|
||||
}
|
||||
|
||||
$this->_body = $body;
|
||||
@@ -133,10 +128,7 @@ extends CAS_ProxiedService_Http_Abstract
|
||||
protected function populateRequest (CAS_Request_RequestInterface $request)
|
||||
{
|
||||
if (empty($this->_contentType) && !empty($this->_body)) {
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
"If you pass a POST body, you must specify a content type via "
|
||||
.get_class($this).'->setContentType($contentType).'
|
||||
);
|
||||
throw new CAS_ProxiedService_Exception("If you pass a POST body, you must specify a content type via ".get_class($this).'->setContentType($contentType).');
|
||||
}
|
||||
|
||||
$request->makePost();
|
||||
|
||||
@@ -79,9 +79,7 @@ extends CAS_ProxiedService_Abstract
|
||||
public function getServiceUrl ()
|
||||
{
|
||||
if (empty($this->_url)) {
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
'No URL set via '.get_class($this).'->getServiceUrl($url).'
|
||||
);
|
||||
throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->getServiceUrl($url).');
|
||||
}
|
||||
|
||||
return $this->_url;
|
||||
@@ -102,9 +100,7 @@ extends CAS_ProxiedService_Abstract
|
||||
public function setServiceUrl ($url)
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the URL, stream already opened.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot set the URL, stream already opened.');
|
||||
}
|
||||
if (!is_string($url) || !strlen($url)) {
|
||||
throw new CAS_InvalidArgumentException('Invalid url.');
|
||||
@@ -131,9 +127,7 @@ extends CAS_ProxiedService_Abstract
|
||||
public function setMailbox ($mailbox)
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the mailbox, stream already opened.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot set the mailbox, stream already opened.');
|
||||
}
|
||||
if (!is_string($mailbox) || !strlen($mailbox)) {
|
||||
throw new CAS_InvalidArgumentException('Invalid mailbox.');
|
||||
@@ -161,9 +155,7 @@ extends CAS_ProxiedService_Abstract
|
||||
public function setOptions ($options)
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set options, stream already opened.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot set options, stream already opened.');
|
||||
}
|
||||
if (!is_int($options)) {
|
||||
throw new CAS_InvalidArgumentException('Invalid options.');
|
||||
@@ -186,19 +178,14 @@ extends CAS_ProxiedService_Abstract
|
||||
* PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
|
||||
* PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
|
||||
* PHPCAS_SERVICE_PT_FAILURE
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the
|
||||
* request to the target service.
|
||||
*/
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the request to the target service. */
|
||||
public function open ()
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Stream already opened.');
|
||||
}
|
||||
if (empty($this->_mailbox)) {
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
'You must specify a mailbox via '.get_class($this)
|
||||
.'->setMailbox($mailbox)'
|
||||
);
|
||||
throw new CAS_ProxiedService_Exception('You must specify a mailbox via '.get_class($this).'->setMailbox($mailbox)');
|
||||
}
|
||||
|
||||
phpCAS::traceBegin();
|
||||
@@ -206,16 +193,13 @@ extends CAS_ProxiedService_Abstract
|
||||
// Get our proxy ticket and append it to our URL.
|
||||
$this->initializeProxyTicket();
|
||||
phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\'...');
|
||||
$this->_stream = @imap_open(
|
||||
$this->_mailbox, $this->_username, $this->getProxyTicket(),
|
||||
$this->_options
|
||||
);
|
||||
$this->_stream = @imap_open($this->_mailbox, $this->_username, $this->getProxyTicket(), $this->_options);
|
||||
if ($this->_stream) {
|
||||
phpCAS::trace('ok');
|
||||
} else {
|
||||
phpCAS::trace('could not open mailbox');
|
||||
// @todo add localization integration.
|
||||
$message = 'IMAP Error: '.$this->_url.' '. var_export(imap_errors(), true);
|
||||
$message = 'IMAP Error: '.$url.' '. var_export(imap_errors(), true);
|
||||
phpCAS::trace($message);
|
||||
throw new CAS_ProxiedService_Exception($message);
|
||||
}
|
||||
@@ -252,9 +236,7 @@ extends CAS_ProxiedService_Abstract
|
||||
public function getStream ()
|
||||
{
|
||||
if (!$this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access stream, not opened yet.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot access stream, not opened yet.');
|
||||
}
|
||||
return $this->_stream;
|
||||
}
|
||||
@@ -270,9 +252,7 @@ extends CAS_ProxiedService_Abstract
|
||||
public function getImapProxyTicket ()
|
||||
{
|
||||
if (!$this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access errors, stream not opened yet.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot access errors, stream not opened yet.');
|
||||
}
|
||||
return $this->getProxyTicket();
|
||||
}
|
||||
|
||||
@@ -31,9 +31,8 @@
|
||||
* This interface defines methods that allow proxy-authenticated service handlers
|
||||
* to be tested in unit tests.
|
||||
*
|
||||
* Classes implementing this interface SHOULD store the CAS_Client passed and
|
||||
* initialize themselves with that client rather than via the static phpCAS
|
||||
* method. For example:
|
||||
* Classes implementing this interface SHOULD store the CAS_Client passed and initialize
|
||||
* themselves with that client rather than via the static phpCAS method. For example:
|
||||
*
|
||||
* / **
|
||||
* * Fetch our proxy ticket.
|
||||
@@ -66,8 +65,7 @@ interface CAS_ProxiedService_Testable
|
||||
* @param CAS_Client $casClient Cas client object
|
||||
*
|
||||
* @return void
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has
|
||||
* already been initialized/set.
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has already been initialized/set.
|
||||
*/
|
||||
public function setCasClient (CAS_Client $casClient);
|
||||
|
||||
|
||||
@@ -59,8 +59,7 @@ implements CAS_ProxyChain_Interface
|
||||
*/
|
||||
public function __construct(array $chain)
|
||||
{
|
||||
// Ensure that we have an indexed array
|
||||
$this->chain = array_values($chain);
|
||||
$this->chain = array_values($chain); // Ensure that we have an indexed array
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,25 +78,17 @@ implements CAS_ProxyChain_Interface
|
||||
$proxy_url = $list[$i];
|
||||
if (preg_match('/^\/.*\/[ixASUXu]*$/s', $search)) {
|
||||
if (preg_match($search, $proxy_url)) {
|
||||
phpCAS::trace(
|
||||
"Found regexp " . $search . " matching " . $proxy_url
|
||||
);
|
||||
phpCAS::trace("Found regexp " . $search . " matching " . $proxy_url);
|
||||
} else {
|
||||
phpCAS::trace(
|
||||
"No regexp match " . $search . " != " . $proxy_url
|
||||
);
|
||||
phpCAS::trace("No regexp match " . $search . " != " . $proxy_url);
|
||||
$mismatch = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (strncasecmp($search, $proxy_url, strlen($search)) == 0) {
|
||||
phpCAS::trace(
|
||||
"Found string " . $search . " matching " . $proxy_url
|
||||
);
|
||||
phpCAS::trace("Found string " . $search . " matching " . $proxy_url);
|
||||
} else {
|
||||
phpCAS::trace(
|
||||
"No match " . $search . " != " . $proxy_url
|
||||
);
|
||||
phpCAS::trace("No match " . $search . " != " . $proxy_url);
|
||||
$mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -60,10 +60,7 @@ implements CAS_Exception
|
||||
PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
|
||||
);
|
||||
if (!in_array($code, $ptCodes)) {
|
||||
trigger_error(
|
||||
'Invalid code '.$code
|
||||
.' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.'
|
||||
);
|
||||
trigger_error('Invalid code '.$code.' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.');
|
||||
}
|
||||
|
||||
parent::__construct($message, $code);
|
||||
|
||||
@@ -68,9 +68,7 @@ implements CAS_Request_RequestInterface
|
||||
public function setUrl ($url)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
$this->url = $url;
|
||||
@@ -88,9 +86,7 @@ implements CAS_Request_RequestInterface
|
||||
public function addCookie ($name, $value)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
$this->cookies[$name] = $value;
|
||||
@@ -109,9 +105,7 @@ implements CAS_Request_RequestInterface
|
||||
public function addCookies (array $cookies)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
$this->cookies = array_merge($this->cookies, $cookies);
|
||||
@@ -128,9 +122,7 @@ implements CAS_Request_RequestInterface
|
||||
public function addHeader ($header)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
$this->headers[] = $header;
|
||||
@@ -147,9 +139,7 @@ implements CAS_Request_RequestInterface
|
||||
public function addHeaders (array $headers)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
$this->headers = array_merge($this->headers, $headers);
|
||||
@@ -164,9 +154,7 @@ implements CAS_Request_RequestInterface
|
||||
public function makePost ()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
$this->isPost = true;
|
||||
@@ -183,14 +171,10 @@ implements CAS_Request_RequestInterface
|
||||
public function setPostBody ($body)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
if (!$this->isPost) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot add a POST body to a GET request, use makePost() first.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Cannot add a POST body to a GET request, use makePost() first.');
|
||||
}
|
||||
|
||||
$this->postBody = $body;
|
||||
@@ -208,9 +192,7 @@ implements CAS_Request_RequestInterface
|
||||
public function setSslCaCert ($caCertPath,$validate_cn=true)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
$this->caCertPath = $caCertPath;
|
||||
$this->validateCN = $validate_cn;
|
||||
@@ -229,14 +211,10 @@ implements CAS_Request_RequestInterface
|
||||
public function send ()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot send again.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.');
|
||||
}
|
||||
if (is_null($this->url) || !$this->url) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'A url must be specified via setUrl() before the request can be sent.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('A url must be specified via setUrl() before the request can be sent.');
|
||||
}
|
||||
$this->_sent = true;
|
||||
return $this->sendRequest();
|
||||
@@ -310,9 +288,7 @@ implements CAS_Request_RequestInterface
|
||||
public function getResponseHeaders ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
}
|
||||
return $this->_responseHeaders;
|
||||
}
|
||||
@@ -326,19 +302,11 @@ implements CAS_Request_RequestInterface
|
||||
public function getResponseStatusCode ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
if (!preg_match(
|
||||
'/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/',
|
||||
$this->_responseHeaders[0], $matches
|
||||
)
|
||||
) {
|
||||
throw new CAS_Request_Exception(
|
||||
'Bad response, no status code was found in the first line.'
|
||||
);
|
||||
if (!preg_match('/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/', $this->_responseHeaders[0], $matches)) {
|
||||
throw new CAS_Request_Exception("Bad response, no status code was found in the first line.");
|
||||
}
|
||||
|
||||
return intval($matches[1]);
|
||||
@@ -353,9 +321,7 @@ implements CAS_Request_RequestInterface
|
||||
public function getResponseBody ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
}
|
||||
|
||||
return $this->_responseBody;
|
||||
@@ -370,9 +336,7 @@ implements CAS_Request_RequestInterface
|
||||
public function getErrorMessage ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
}
|
||||
return $this->_errorMessage;
|
||||
}
|
||||
|
||||
@@ -64,14 +64,10 @@ implements CAS_Request_MultiRequestInterface
|
||||
public function addRequest (CAS_Request_RequestInterface $request)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
if (!$request instanceof CAS_Request_CurlRequest) {
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.'
|
||||
);
|
||||
throw new CAS_InvalidArgumentException('As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.');
|
||||
}
|
||||
|
||||
$this->_requests[] = $request;
|
||||
@@ -85,9 +81,7 @@ implements CAS_Request_MultiRequestInterface
|
||||
public function getNumRequests()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
}
|
||||
return count($this->_requests);
|
||||
}
|
||||
@@ -106,14 +100,10 @@ implements CAS_Request_MultiRequestInterface
|
||||
public function send ()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot send again.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.');
|
||||
}
|
||||
if (!count($this->_requests)) {
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'At least one request must be added via addRequest() before the multi-request can be sent.'
|
||||
);
|
||||
throw new CAS_OutOfSequenceException('At least one request must be added via addRequest() before the multi-request can be sent.');
|
||||
}
|
||||
|
||||
$this->_sent = true;
|
||||
|
||||
@@ -75,9 +75,7 @@ implements CAS_Request_RequestInterface
|
||||
$buf = curl_exec($ch);
|
||||
if ( $buf === false ) {
|
||||
phpCAS::trace('curl_exec() failed');
|
||||
$this->storeErrorMessage(
|
||||
'CURL error #'.curl_errno($ch).': '.curl_error($ch)
|
||||
);
|
||||
$this->storeErrorMessage('CURL error #'.curl_errno($ch).': '.curl_error($ch));
|
||||
$res = false;
|
||||
} else {
|
||||
$this->storeResponseBody($buf);
|
||||
@@ -122,7 +120,7 @@ implements CAS_Request_RequestInterface
|
||||
if ($this->validateCN) {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_setopt($ch, CURLOPT_CAINFO, $this->caCertPath);
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/InvalidArgumentException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Adam Franco <afranco@middlebury.edu>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Exception that denotes invalid arguments were passed.
|
||||
*
|
||||
* @class CAS_InvalidArgumentException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Adam Franco <afranco@middlebury.edu>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_TypeMismatchException
|
||||
extends CAS_InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* Constructor, provides a nice message.
|
||||
*
|
||||
* @param mixed $argument Argument
|
||||
* @param string $argumentName Argument Name
|
||||
* @param string $type Type
|
||||
* @param string $message Error Message
|
||||
* @param integer $code Code
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct (
|
||||
$argument, $argumentName, $type, $message = '', $code = 0
|
||||
) {
|
||||
if (is_object($argument)) {
|
||||
$foundType = get_class($argument).' object';
|
||||
} else {
|
||||
$foundType = gettype($argument);
|
||||
}
|
||||
|
||||
parent::__construct(
|
||||
'type mismatched for parameter '
|
||||
. $argumentName . ' (should be \'' . $type .' \'), '
|
||||
. $foundType . ' given. ' . $message, $code
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,5 +1,5 @@
|
||||
Description of phpCAS 1.3.3 library import
|
||||
Description of phpCAS 1.3.2 library import
|
||||
|
||||
* downloaded from http://downloads.jasig.org/cas-clients/php/current/
|
||||
|
||||
merrill
|
||||
iarenaza
|
||||
|
||||
+49
-38
@@ -111,26 +111,6 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the multi-authentication setting is used, check for the param before connecting to CAS.
|
||||
if ($this->config->multiauth) {
|
||||
$authCAS = optional_param('authCAS', '', PARAM_RAW);
|
||||
if ($authCAS == 'NOCAS') {
|
||||
return;
|
||||
}
|
||||
// Show authentication form for multi-authentication.
|
||||
// Test pgtIou parameter for proxy mode (https connection in background from CAS server to the php server).
|
||||
if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
|
||||
$PAGE->set_url('/login/index.php');
|
||||
$PAGE->navbar->add($CASform);
|
||||
$PAGE->set_title("$site->fullname: $CASform");
|
||||
$PAGE->set_heading($site->fullname);
|
||||
echo $OUTPUT->header();
|
||||
include($CFG->dirroot.'/auth/cas/cas_form.html');
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Connection to CAS server
|
||||
$this->connectCAS();
|
||||
|
||||
@@ -154,6 +134,27 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->config->multiauth) {
|
||||
$authCAS = optional_param('authCAS', '', PARAM_RAW);
|
||||
if ($authCAS == 'NOCAS') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show authentication form for multi-authentication
|
||||
// test pgtIou parameter for proxy mode (https connection
|
||||
// in background from CAS server to the php server)
|
||||
if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
|
||||
$PAGE->set_url('/login/index.php');
|
||||
$PAGE->navbar->add($CASform);
|
||||
$PAGE->set_title("$site->fullname: $CASform");
|
||||
$PAGE->set_heading($site->fullname);
|
||||
echo $OUTPUT->header();
|
||||
include($CFG->dirroot.'/auth/cas/cas_form.html');
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Force CAS authentication (if needed).
|
||||
if (!phpCAS::isAuthenticated()) {
|
||||
phpCAS::setLang($this->config->language);
|
||||
@@ -161,6 +162,34 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout from the CAS
|
||||
*
|
||||
*/
|
||||
function prelogout_hook() {
|
||||
global $CFG, $USER, $DB;
|
||||
|
||||
if (!empty($this->config->logoutcas) && $USER->auth == $this->authtype) {
|
||||
$backurl = $CFG->wwwroot;
|
||||
$this->connectCAS();
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the CAS (clientcas connection or proxycas connection)
|
||||
@@ -496,22 +525,4 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post logout hook.
|
||||
*
|
||||
* Note: this method replace the prelogout_hook method to avoid redirect to CAS logout
|
||||
* before the event userlogout being triggered.
|
||||
*
|
||||
* @param stdClass $user clone of USER object object before the user session was terminated
|
||||
*/
|
||||
public function postlogout_hook($user) {
|
||||
global $CFG;
|
||||
// Only redirect to CAS logout if the user is logged as a CAS user.
|
||||
if (!empty($this->config->logoutcas) && $user->auth == $this->authtype) {
|
||||
$backurl = !empty($this->config->logout_return_url) ? $this->config->logout_return_url : $CFG->wwwroot;
|
||||
$this->connectCAS();
|
||||
phpCAS::logoutWithRedirectService($backurl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<location>CAS</location>
|
||||
<name>CAS</name>
|
||||
<license>BSD</license>
|
||||
<version>1.3.3</version>
|
||||
<version>1.3.2</version>
|
||||
<licenseversion></licenseversion>
|
||||
</library>
|
||||
</libraries>
|
||||
|
||||
+26
-19
@@ -260,8 +260,6 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
function sync_users(progress_trace $trace, $do_updates=false) {
|
||||
global $CFG, $DB;
|
||||
|
||||
require_once($CFG->dirroot . '/user/lib.php');
|
||||
|
||||
// List external users.
|
||||
$userlist = $this->get_userlist();
|
||||
|
||||
@@ -291,6 +289,7 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
$remove_users = $DB->get_records_sql($sql, $params);
|
||||
|
||||
if (!empty($remove_users)) {
|
||||
require_once($CFG->dirroot.'/user/lib.php');
|
||||
$trace->output(get_string('auth_dbuserstoremove','auth_db', count($remove_users)));
|
||||
|
||||
foreach ($remove_users as $user) {
|
||||
@@ -382,14 +381,13 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
foreach($add_users as $user) {
|
||||
$username = $user;
|
||||
if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) {
|
||||
if ($olduser = $DB->get_record('user', array('username' => $username, 'deleted' => 0, 'suspended' => 1,
|
||||
'mnethostid' => $CFG->mnet_localhost_id, 'auth' => $this->authtype))) {
|
||||
$updateuser = new stdClass();
|
||||
$updateuser->id = $olduser->id;
|
||||
$updateuser->suspended = 0;
|
||||
user_update_user($updateuser);
|
||||
$trace->output(get_string('auth_dbreviveduser', 'auth_db', array('name' => $username,
|
||||
'id' => $olduser->id)), 1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -405,12 +403,21 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
if (empty($user->lang)) {
|
||||
$user->lang = $CFG->lang;
|
||||
}
|
||||
if (empty($user->calendartype)) {
|
||||
$user->calendartype = $CFG->calendartype;
|
||||
}
|
||||
$user->timecreated = time();
|
||||
$user->timemodified = $user->timecreated;
|
||||
if ($collision = $DB->get_record_select('user', "username = :username AND mnethostid = :mnethostid AND auth <> :auth", array('username'=>$user->username, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype), 'id,username,auth')) {
|
||||
$trace->output(get_string('auth_dbinsertuserduplicate', 'auth_db', array('username'=>$user->username, 'auth'=>$collision->auth)), 1);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$id = user_create_user($user, false); // It is truly a new user.
|
||||
$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);
|
||||
@@ -522,10 +529,8 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
|
||||
// Ensure userid is not overwritten.
|
||||
$userid = $user->id;
|
||||
$needsupdate = false;
|
||||
$updated = false;
|
||||
|
||||
$updateuser = new stdClass();
|
||||
$updateuser->id = $userid;
|
||||
if ($newinfo = $this->get_userinfo($username)) {
|
||||
$newinfo = truncate_userinfo($newinfo);
|
||||
|
||||
@@ -542,15 +547,17 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
|
||||
if (!empty($this->config->{'field_updatelocal_' . $key})) {
|
||||
if (isset($user->{$key}) and $user->{$key} != $value) { // Only update if it's changed.
|
||||
$needsupdate = true;
|
||||
$updateuser->$key = $value;
|
||||
$DB->set_field('user', $key, $value, array('id'=>$userid));
|
||||
$updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($needsupdate) {
|
||||
require_once($CFG->dirroot . '/user/lib.php');
|
||||
user_update_user($updateuser);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -737,7 +737,6 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
do {
|
||||
$value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute);
|
||||
$value = core_text::convert($value[0], $this->config->ldapencoding, 'utf-8');
|
||||
$value = trim($value);
|
||||
$this->ldap_bulk_insert($value);
|
||||
} while ($entry = ldap_next_entry($ldapconnection, $entry));
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ $string['notcalledfromserver'] = 'Should not be called from the web server!';
|
||||
$string['noupdatestobedone'] = "No updates to be done\n";
|
||||
$string['nouserentriestoremove'] = "No user entries to be removed\n";
|
||||
$string['nouserentriestorevive'] = "No user entries to be revived\n";
|
||||
$string['nouserstobeadded'] = 'No user entries to be added';
|
||||
$string['nouserstobeadded'] = "No users to be added\n";
|
||||
$string['ntlmsso_attempting'] = 'Attempting Single Sign On via NTLM...';
|
||||
$string['ntlmsso_failed'] = 'Auto-login failed, try the normal login page...';
|
||||
$string['ntlmsso_isdisabled'] = 'NTLM SSO is disabled.';
|
||||
|
||||
+110
-3
@@ -764,6 +764,74 @@ class auth_plugin_mnet extends auth_plugin_base {
|
||||
join("\n", $mnet_request->error));
|
||||
break;
|
||||
}
|
||||
$mnethostlogssql = "
|
||||
SELECT
|
||||
l.id as remoteid, l.time, l.userid, l.ip, l.course, l.module, l.cmid,
|
||||
l.action, l.url, l.info, u.username
|
||||
FROM
|
||||
{user} u
|
||||
INNER JOIN {log} l on l.userid = u.id
|
||||
WHERE
|
||||
u.mnethostid = ?
|
||||
AND l.id > ?
|
||||
AND l.course IS NOT NULL
|
||||
ORDER by l.id ASC";
|
||||
|
||||
$mnethostlogs = $DB->get_records_sql($mnethostlogssql, array($mnethostid, $mnet_request->response['last log id']), 0, 500);
|
||||
|
||||
if ($mnethostlogs == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$processedlogs = array();
|
||||
|
||||
foreach($mnethostlogs as $hostlog) {
|
||||
try {
|
||||
// Get impersonalised course information. If it is cached there will be no DB queries.
|
||||
$modinfo = get_fast_modinfo($hostlog->course, -1);
|
||||
$hostlog->coursename = $modinfo->get_course()->fullname;
|
||||
if (!empty($hostlog->cmid) && isset($modinfo->cms[$hostlog->cmid])) {
|
||||
$hostlog->resource_name = $modinfo->cms[$hostlog->cmid]->name;
|
||||
} else {
|
||||
$hostlog->resource_name = '';
|
||||
}
|
||||
} catch (moodle_exception $e) {
|
||||
// Course not found
|
||||
continue;
|
||||
}
|
||||
|
||||
$processedlogs[] = array (
|
||||
'remoteid' => $hostlog->remoteid,
|
||||
'time' => $hostlog->time,
|
||||
'userid' => $hostlog->userid,
|
||||
'ip' => $hostlog->ip,
|
||||
'course' => $hostlog->course,
|
||||
'coursename' => $hostlog->coursename,
|
||||
'module' => $hostlog->module,
|
||||
'cmid' => $hostlog->cmid,
|
||||
'action' => $hostlog->action,
|
||||
'url' => $hostlog->url,
|
||||
'info' => $hostlog->info,
|
||||
'resource_name' => $hostlog->resource_name,
|
||||
'username' => $hostlog->username
|
||||
);
|
||||
}
|
||||
|
||||
unset($hostlog);
|
||||
|
||||
$mnet_request = new mnet_xmlrpc_client();
|
||||
$mnet_request->set_method('auth/mnet/auth.php/refresh_log');
|
||||
|
||||
// set $token and $useragent parameters
|
||||
$mnet_request->add_param($processedlogs);
|
||||
|
||||
if ($mnet_request->send($mnet_peer) === true) {
|
||||
if ($mnet_request->response['code'] > 0) {
|
||||
debugging($mnet_request->response['message']);
|
||||
}
|
||||
} else {
|
||||
debugging("Server side error has occured on host $mnet_peer->ip: " .join("\n", $mnet_request->error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,13 +839,52 @@ class auth_plugin_mnet extends auth_plugin_base {
|
||||
* Receives an array of log entries from an SP and adds them to the mnet_log
|
||||
* table
|
||||
*
|
||||
* @deprecated since Moodle 2.8 Please don't use this function for recording mnet logs.
|
||||
* @param array $array An array of usernames
|
||||
* @return string "All ok" or an error message
|
||||
*/
|
||||
function refresh_log($array) {
|
||||
debugging('refresh_log() is deprecated, The transfer of logs through mnet are no longer recorded.', DEBUG_DEVELOPER);
|
||||
return array('code' => 0, 'message' => 'All ok');
|
||||
global $CFG, $DB;
|
||||
$remoteclient = get_mnet_remote_client();
|
||||
|
||||
// We don't want to output anything to the client machine
|
||||
$start = ob_start();
|
||||
|
||||
$returnString = '';
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$useridarray = array();
|
||||
|
||||
foreach($array as $logEntry) {
|
||||
$logEntryObj = (object)$logEntry;
|
||||
$logEntryObj->hostid = $remoteclient->id;
|
||||
|
||||
if (isset($useridarray[$logEntryObj->username])) {
|
||||
$logEntryObj->userid = $useridarray[$logEntryObj->username];
|
||||
} else {
|
||||
$logEntryObj->userid = $DB->get_field('user', 'id', array('username'=>$logEntryObj->username, 'mnethostid'=>(int)$logEntryObj->hostid));
|
||||
if ($logEntryObj->userid == false) {
|
||||
$logEntryObj->userid = 0;
|
||||
}
|
||||
$useridarray[$logEntryObj->username] = $logEntryObj->userid;
|
||||
}
|
||||
|
||||
unset($logEntryObj->username);
|
||||
|
||||
$logEntryObj = $this->trim_logline($logEntryObj);
|
||||
$insertok = $DB->insert_record('mnet_log', $logEntryObj, false);
|
||||
|
||||
if ($insertok) {
|
||||
$remoteclient->last_log_id = $logEntryObj->remoteid;
|
||||
} else {
|
||||
$returnString .= 'Record with id '.$logEntryObj->remoteid." failed to insert.\n";
|
||||
}
|
||||
}
|
||||
$remoteclient->commit();
|
||||
$transaction->allow_commit();
|
||||
|
||||
$end = ob_end_clean();
|
||||
|
||||
if (empty($returnString)) return array('code' => 0, 'message' => 'All ok');
|
||||
return array('code' => 1, 'message' => $returnString);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -203,7 +203,7 @@ can directly edit the object $result.
|
||||
Example file:
|
||||
|
||||
--
|
||||
<?php
|
||||
<?PHP
|
||||
|
||||
// Set the zip code and the adress
|
||||
if ($_SERVER[$this->config->field_map_address] != '')
|
||||
|
||||
@@ -11,7 +11,7 @@ require_once($CFG->dirroot."/auth/shibboleth/auth.php");
|
||||
|
||||
// Find out whether host supports https
|
||||
$protocol = 'http://';
|
||||
if (is_https()) {
|
||||
if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'){
|
||||
$protocol = 'https://';
|
||||
}
|
||||
|
||||
|
||||
@@ -91,13 +91,10 @@ class behat_auth extends behat_base {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
// There is no longer any need to worry about whether the navigation
|
||||
// bar needs to be expanded; user_menu now lives outside the
|
||||
// hamburger.
|
||||
|
||||
// However, the user menu *always* needs to be expanded.
|
||||
$xpath ="//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
|
||||
array_unshift($steps, new When('I click on "'.$xpath.'" "xpath_element"'));
|
||||
// If it is needed, it expands the navigation bar with the 'Log out' link.
|
||||
if ($clicknavbar = $this->get_expand_navbar_step()) {
|
||||
array_unshift($steps, $clicknavbar);
|
||||
}
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
This files describes API changes in /auth/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 2.8 ===
|
||||
|
||||
* \core\session\manager::session_exists() now verifies the session is active
|
||||
instead of only checking the session data is present in low level session handler
|
||||
|
||||
* MNet is no longer sending logs between the client and parent sites. auth_plugin_mnet::refresh_log() is now deprecated. There is
|
||||
no alternative. Please don't use this function.
|
||||
|
||||
=== 2.7 ===
|
||||
|
||||
* If you are returning a url in method change_password_url() from config, please make sure it is set before trying to use it.
|
||||
|
||||
@@ -49,9 +49,6 @@ abstract class info {
|
||||
/** @var tree Availability configuration, decoded from JSON; null if unset */
|
||||
protected $availabilitytree;
|
||||
|
||||
/** @var array|null Array of information about current restore if any */
|
||||
protected static $restoreinfo = null;
|
||||
|
||||
/**
|
||||
* Constructs with item details.
|
||||
*
|
||||
@@ -310,12 +307,9 @@ abstract class info {
|
||||
* @param string $restoreid Restore identifier
|
||||
* @param int $courseid Target course id
|
||||
* @param \base_logger $logger Logger for any warnings
|
||||
* @param int $dateoffset Date offset to be added to any dates (0 = none)
|
||||
*/
|
||||
public function update_after_restore($restoreid, $courseid, \base_logger $logger, $dateoffset) {
|
||||
public function update_after_restore($restoreid, $courseid, \base_logger $logger) {
|
||||
$tree = $this->get_availability_tree();
|
||||
// Set static data for use by get_restore_date_offset function.
|
||||
self::$restoreinfo = array('restoreid' => $restoreid, 'dateoffset' => $dateoffset);
|
||||
$changed = $tree->update_after_restore($restoreid, $courseid, $logger,
|
||||
$this->get_thing_name());
|
||||
if ($changed) {
|
||||
@@ -325,24 +319,6 @@ abstract class info {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date offset (amount by which any date values should be
|
||||
* adjusted) for the current restore.
|
||||
*
|
||||
* @param string $restoreid Restore identifier
|
||||
* @return int Date offset (0 if none)
|
||||
* @throws coding_exception If not in a restore (or not in that restore)
|
||||
*/
|
||||
public static function get_restore_date_offset($restoreid) {
|
||||
if (!self::$restoreinfo) {
|
||||
throw new coding_exception('Only valid during restore');
|
||||
}
|
||||
if (self::$restoreinfo['restoreid'] !== $restoreid) {
|
||||
throw new coding_exception('Data not available for that restore id');
|
||||
}
|
||||
return self::$restoreinfo['dateoffset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the name of the item (cm_info or section_info, at present) that
|
||||
* this is controlling availability of. Name should be formatted ready
|
||||
@@ -427,19 +403,19 @@ abstract class info {
|
||||
* Supported fields: availablefrom, availableuntil, showavailability
|
||||
* (and groupingid for sections).
|
||||
*
|
||||
* It also supports the groupmembersonly field for modules. This part was
|
||||
* optional in 2.7 but now always runs (because groupmembersonly has been
|
||||
* removed).
|
||||
* If you enable $modgroupmembersonly, then it also supports the
|
||||
* 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 bool $section True if this is a section
|
||||
* @param bool $modgroupmembersonlyignored Ignored option, previously used
|
||||
* @param bool $modgroupmembersonly True if groupmembersonly is converted for mods
|
||||
* @return string|null New availability value or null if none
|
||||
*/
|
||||
public static function convert_legacy_fields($rec, $section, $modgroupmembersonlyignored = false) {
|
||||
public static function convert_legacy_fields($rec, $section, $modgroupmembersonly = false) {
|
||||
// Do nothing if the fields are not set.
|
||||
if (empty($rec->availablefrom) && empty($rec->availableuntil) &&
|
||||
(empty($rec->groupmembersonly)) &&
|
||||
(!$modgroupmembersonly || empty($rec->groupmembersonly)) &&
|
||||
(!$section || empty($rec->groupingid))) {
|
||||
return null;
|
||||
}
|
||||
@@ -450,7 +426,7 @@ abstract class info {
|
||||
|
||||
// Groupmembersonly condition (if enabled) for modules, groupingid for
|
||||
// sections.
|
||||
if (!empty($rec->groupmembersonly) ||
|
||||
if (($modgroupmembersonly && !empty($rec->groupmembersonly)) ||
|
||||
(!empty($rec->groupingid) && $section)) {
|
||||
if (!empty($rec->groupingid)) {
|
||||
$conditions[] = '{"type":"grouping"' .
|
||||
@@ -614,36 +590,6 @@ abstract class info {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains SQL that returns a list of enrolled users that has been filtered
|
||||
* by the conditions applied in the availability API, similar to calling
|
||||
* get_enrolled_users and then filter_user_list. As for filter_user_list,
|
||||
* this ONLY filteres out users with conditions that are marked as applying
|
||||
* to user lists. For example, group conditions are included but date
|
||||
* conditions are not included.
|
||||
*
|
||||
* The returned SQL is a query that returns a list of user IDs. It does not
|
||||
* include brackets, so you neeed to add these to make it into a subquery.
|
||||
* You would normally use it in an SQL phrase like "WHERE u.id IN ($sql)".
|
||||
*
|
||||
* The function returns an array with '' and an empty array, if there are
|
||||
* no restrictions on users from these conditions.
|
||||
*
|
||||
* The SQL will be complex and may be slow. It uses named parameters (sorry,
|
||||
* I know they are annoying, but it was unavoidable here).
|
||||
*
|
||||
* @param bool $onlyactive True if including only active enrolments
|
||||
* @return array Array of SQL code (may be empty) and params
|
||||
*/
|
||||
public function get_user_list_sql($onlyactive) {
|
||||
global $CFG;
|
||||
if (is_null($this->availability) || !$CFG->enableavailability) {
|
||||
return array('', array());
|
||||
}
|
||||
$tree = $this->get_availability_tree();
|
||||
return $tree->get_user_list_sql(false, $this, $onlyactive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the $cm->availableinfo string for display. This includes
|
||||
* filling in the names of any course-modules that might be mentioned.
|
||||
@@ -667,12 +613,7 @@ abstract class info {
|
||||
$info = preg_replace_callback('~<AVAILABILITY_CMNAME_([0-9]+)/>~',
|
||||
function($matches) use($modinfo, $context) {
|
||||
$cm = $modinfo->get_cm($matches[1]);
|
||||
if ($cm->has_view() and $cm->uservisible) {
|
||||
// Help student by providing a link to the module which is preventing availability.
|
||||
return \html_writer::link($cm->url, format_string($cm->name, true, array('context' => $context)));
|
||||
} else {
|
||||
return format_string($cm->name, true, array('context' => $context));
|
||||
}
|
||||
return format_string($cm->name, true, array('context' => $context));
|
||||
}, $info);
|
||||
|
||||
return $info;
|
||||
|
||||
@@ -109,35 +109,12 @@ class info_module extends info {
|
||||
return parent::filter_user_list($filtered);
|
||||
}
|
||||
|
||||
public function get_user_list_sql($onlyactive = true) {
|
||||
global $CFG, $DB;
|
||||
if (!$CFG->enableavailability) {
|
||||
return array('', array());
|
||||
}
|
||||
|
||||
// Get query for section (if any) and module.
|
||||
$section = $this->cm->get_modinfo()->get_section_info(
|
||||
$this->cm->sectionnum, MUST_EXIST);
|
||||
$sectioninfo = new info_section($section);
|
||||
$sectionresult = $sectioninfo->get_user_list_sql($onlyactive);
|
||||
$moduleresult = parent::get_user_list_sql($onlyactive);
|
||||
|
||||
if (!$sectionresult[0]) {
|
||||
return $moduleresult;
|
||||
}
|
||||
if (!$moduleresult[0]) {
|
||||
return $sectionresult;
|
||||
}
|
||||
|
||||
return array($DB->sql_intersect(array($sectionresult[0], $moduleresult[0]), 'id'),
|
||||
array_merge($sectionresult[1], $moduleresult[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an activity is visible to the given user.
|
||||
*
|
||||
* Unlike other checks in the availability system, this check includes the
|
||||
* $cm->visible flag. It is equivalent to $cm->uservisible.
|
||||
* $cm->visible flag and also (if enabled) the groupmembersonly feature.
|
||||
* It is equivalent to $cm->uservisible.
|
||||
*
|
||||
* If you have already checked (or do not care whether) the user has access
|
||||
* to the course, you can set $checkcourse to false to save it checking
|
||||
@@ -183,6 +160,11 @@ class info_module extends info {
|
||||
$cm = $DB->get_record('course_modules', array('id' => $cmorid), '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
// Check the groupmembersonly feature.
|
||||
if (!groups_course_module_visible($cm, $userid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If requested, check user can access the course.
|
||||
if ($checkcourse) {
|
||||
$coursecontext = \context_course::instance($cm->course);
|
||||
@@ -205,13 +187,6 @@ class info_module extends info {
|
||||
// As a result we cannot take short cuts any longer and must get
|
||||
// standard modinfo.
|
||||
$modinfo = get_fast_modinfo($cm->course, $userid);
|
||||
$cms = $modinfo->get_cms();
|
||||
if (!isset($cms[$cm->id])) {
|
||||
// In some cases this might get called with a cmid that is no longer
|
||||
// available, for example when a module is hidden at system level.
|
||||
debugging('info_module::is_user_visible called with invalid cmid ' . $cm->id, DEBUG_DEVELOPER);
|
||||
return false;
|
||||
}
|
||||
return $cms[$cm->id]->uservisible;
|
||||
return $modinfo->get_cm($cm->id)->uservisible;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,52 +350,6 @@ class tree extends tree_node {
|
||||
}
|
||||
}
|
||||
|
||||
public function get_user_list_sql($not, info $info, $onlyactive) {
|
||||
global $DB;
|
||||
// Get logic flags from operator.
|
||||
list($innernot, $andoperator) = $this->get_logic_flags($not);
|
||||
|
||||
// Loop through all valid children, getting SQL for each.
|
||||
$childresults = array();
|
||||
foreach ($this->children as $index => $child) {
|
||||
if (!$child->is_applied_to_user_lists()) {
|
||||
continue;
|
||||
}
|
||||
$childresult = $child->get_user_list_sql($innernot, $info, $onlyactive);
|
||||
if ($childresult[0]) {
|
||||
$childresults[] = $childresult;
|
||||
} else if (!$andoperator) {
|
||||
// When using OR operator, if any part doesn't have restrictions,
|
||||
// then nor does the whole thing.
|
||||
return array('', array());
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no conditions, return null.
|
||||
if (!$childresults) {
|
||||
return array('', array());
|
||||
}
|
||||
// If there is a single condition, return it.
|
||||
if (count($childresults) === 1) {
|
||||
return $childresults[0];
|
||||
}
|
||||
|
||||
// Combine results using INTERSECT or UNION.
|
||||
$outsql = null;
|
||||
$subsql = array();
|
||||
$outparams = array();
|
||||
foreach ($childresults as $childresult) {
|
||||
$subsql[] = $childresult[0];
|
||||
$outparams = array_merge($outparams, $childresult[1]);
|
||||
}
|
||||
if ($andoperator) {
|
||||
$outsql = $DB->sql_intersect($subsql, 'id');
|
||||
} else {
|
||||
$outsql = '(' . join(') UNION (', $subsql) . ')';
|
||||
}
|
||||
return array($outsql, $outparams);
|
||||
}
|
||||
|
||||
public function is_available_for_all($not = false) {
|
||||
// Get logic flags.
|
||||
list($innernot, $andoperator) = $this->get_logic_flags($not);
|
||||
@@ -606,13 +560,10 @@ class tree extends tree_node {
|
||||
public function save() {
|
||||
$result = new \stdClass();
|
||||
$result->op = $this->op;
|
||||
// Only root tree has the 'show' options.
|
||||
if ($this->root) {
|
||||
if ($this->op === self::OP_AND || $this->op === self::OP_NOT_OR) {
|
||||
$result->showc = $this->showchildren;
|
||||
} else {
|
||||
$result->show = $this->show;
|
||||
}
|
||||
if ($this->op === self::OP_AND || $this->op === self::OP_NOT_OR) {
|
||||
$result->showc = $this->showchildren;
|
||||
} else {
|
||||
$result->show = $this->show;
|
||||
}
|
||||
$result->c = array();
|
||||
foreach ($this->children as $child) {
|
||||
@@ -621,15 +572,6 @@ class tree extends tree_node {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this tree is empty (contains no children).
|
||||
*
|
||||
* @return boolean True if empty
|
||||
*/
|
||||
public function is_empty() {
|
||||
return count($this->children) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively gets all children of a particular class (you can use a base
|
||||
* class to get all conditions, or a specific class).
|
||||
@@ -679,99 +621,4 @@ class tree extends tree_node {
|
||||
}
|
||||
return $changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object which corresponds to a tree.
|
||||
*
|
||||
* Intended for unit testing, as normally the JSON values are constructed
|
||||
* by JavaScript code.
|
||||
*
|
||||
* This function generates 'nested' (i.e. not root-level) trees.
|
||||
*
|
||||
* @param array $children Array of JSON objects from component children
|
||||
* @param string $op Operator (tree::OP_xx)
|
||||
* @return stdClass JSON object
|
||||
* @throws coding_exception If you get parameters wrong
|
||||
*/
|
||||
public static function get_nested_json(array $children, $op = self::OP_AND) {
|
||||
|
||||
// Check $op and work out its type.
|
||||
switch($op) {
|
||||
case self::OP_AND:
|
||||
case self::OP_NOT_OR:
|
||||
case self::OP_OR:
|
||||
case self::OP_NOT_AND:
|
||||
break;
|
||||
default:
|
||||
throw new \coding_exception('Invalid $op');
|
||||
}
|
||||
|
||||
// Do simple tree.
|
||||
$result = new \stdClass();
|
||||
$result->op = $op;
|
||||
$result->c = $children;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object which corresponds to a tree at root level.
|
||||
*
|
||||
* Intended for unit testing, as normally the JSON values are constructed
|
||||
* by JavaScript code.
|
||||
*
|
||||
* The $show parameter can be a boolean for all OP_xx options. For OP_AND
|
||||
* and OP_NOT_OR where you have individual show options, you can specify
|
||||
* a boolean (same for all) or an array.
|
||||
*
|
||||
* @param array $children Array of JSON objects from component children
|
||||
* @param string $op Operator (tree::OP_xx)
|
||||
* @param bool|array $show Whether 'show' option is turned on (see above)
|
||||
* @return stdClass JSON object ready for encoding
|
||||
* @throws coding_exception If you get parameters wrong
|
||||
*/
|
||||
public static function get_root_json(array $children, $op = self::OP_AND, $show = true) {
|
||||
|
||||
// Get the basic object.
|
||||
$result = self::get_nested_json($children, $op);
|
||||
|
||||
// Check $op type.
|
||||
switch($op) {
|
||||
case self::OP_AND:
|
||||
case self::OP_NOT_OR:
|
||||
$multishow = true;
|
||||
break;
|
||||
case self::OP_OR:
|
||||
case self::OP_NOT_AND:
|
||||
$multishow = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Add show options depending on operator.
|
||||
if ($multishow) {
|
||||
if (is_bool($show)) {
|
||||
$result->showc = array_pad(array(), count($result->c), $show);
|
||||
} else if (is_array($show)) {
|
||||
// The JSON will break if anything isn't an actual bool, so check.
|
||||
foreach ($show as $item) {
|
||||
if (!is_bool($item)) {
|
||||
throw new \coding_exception('$show array members must be bool');
|
||||
}
|
||||
}
|
||||
// Check the size matches.
|
||||
if (count($show) != count($result->c)) {
|
||||
throw new \coding_exception('$show array size does not match $children');
|
||||
}
|
||||
$result->showc = $show;
|
||||
} else {
|
||||
throw new \coding_exception('$show must be bool or array');
|
||||
}
|
||||
} else {
|
||||
if (!is_bool($show)) {
|
||||
throw new \coding_exception('For this operator, $show must be bool');
|
||||
}
|
||||
$result->show = $show;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,9 +87,6 @@ abstract class tree_node {
|
||||
* The default behaviour is simply to return false. If there is a problem
|
||||
* with the update, $logger can be used to output a warning.
|
||||
*
|
||||
* Note: If you need information about the date offset, call
|
||||
* \core_availability\info::get_restore_date_offset($restoreid).
|
||||
*
|
||||
* @param string $restoreid Restore ID
|
||||
* @param int $courseid ID of target course
|
||||
* @param \base_logger $logger Logger for any warnings
|
||||
@@ -162,60 +159,4 @@ abstract class tree_node {
|
||||
throw new \coding_exception('Not implemented (do not call unless '.
|
||||
'is_applied_to_user_lists is true)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains SQL that returns a list of enrolled users that has been filtered
|
||||
* by the conditions applied in the availability API, similar to calling
|
||||
* get_enrolled_users and then filter_user_list. As for filter_user_list,
|
||||
* this ONLY filteres out users with conditions that are marked as applying
|
||||
* to user lists. For example, group conditions are included but date
|
||||
* conditions are not included.
|
||||
*
|
||||
* The returned SQL is a query that returns a list of user IDs. It does not
|
||||
* include brackets, so you neeed to add these to make it into a subquery.
|
||||
* You would normally use it in an SQL phrase like "WHERE u.id IN ($sql)".
|
||||
*
|
||||
* The SQL will be complex and may be slow. It uses named parameters (sorry,
|
||||
* I know they are annoying, but it was unavoidable here).
|
||||
*
|
||||
* If there are no conditions, the returned result is array('', array()).
|
||||
*
|
||||
* @param bool $not True if this condition is applying in negative mode
|
||||
* @param \core_availability\info $info Item we're checking
|
||||
* @param bool $onlyactive If true, only returns active enrolments
|
||||
* @return array Array with two elements: SQL subquery and parameters array
|
||||
* @throws \coding_exception If called on a condition that doesn't apply to user lists
|
||||
*/
|
||||
public function get_user_list_sql($not, \core_availability\info $info, $onlyactive) {
|
||||
if (!$this->is_applied_to_user_lists()) {
|
||||
throw new \coding_exception('Not implemented (do not call unless '.
|
||||
'is_applied_to_user_lists is true)');
|
||||
}
|
||||
|
||||
// Handle situation where plugin does not implement this, by returning a
|
||||
// default (all enrolled users). This ensures compatibility with 2.7
|
||||
// plugins and behaviour. Plugins should be updated to support this
|
||||
// new function (if they return true to is_applied_to_user_lists).
|
||||
debugging('Availability plugins that return true to is_applied_to_user_lists ' .
|
||||
'should also now implement get_user_list_sql: ' . get_class($this),
|
||||
DEBUG_DEVELOPER);
|
||||
return get_enrolled_sql($info->get_context(), '', 0, $onlyactive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for generating SQL parameters (because we can't use ?
|
||||
* parameters because get_enrolled_sql has infected us with horrible named
|
||||
* parameters).
|
||||
*
|
||||
* @param array $params Params array (value will be added to this array)
|
||||
* @param string|int $value Value
|
||||
* @return SQL code for the parameter, e.g. ':pr1234'
|
||||
*/
|
||||
protected static function unique_sql_parameter(array &$params, $value) {
|
||||
static $count = 1;
|
||||
$unique = 'usp' . $count;
|
||||
$params[$unique] = $value;
|
||||
$count++;
|
||||
return ':' . $unique;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,21 +74,6 @@ class condition extends \core_availability\condition {
|
||||
'cm' => $this->cmid, 'e' => $this->expectedcompletion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object which corresponds to a condition of this type.
|
||||
*
|
||||
* Intended for unit testing, as normally the JSON values are constructed
|
||||
* by JavaScript code.
|
||||
*
|
||||
* @param int $cmid Course-module id of other activity
|
||||
* @param int $expectedcompletion Expected completion value (COMPLETION_xx)
|
||||
* @return stdClass Object representing condition
|
||||
*/
|
||||
public static function get_json($cmid, $expectedcompletion) {
|
||||
return (object)array('type' => 'completion', 'cm' => (int)$cmid,
|
||||
'e' => (int)$expectedcompletion);
|
||||
}
|
||||
|
||||
public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
|
||||
$modinfo = $info->get_modinfo();
|
||||
$completion = new \completion_info($modinfo->get_course());
|
||||
|
||||
+2
-2
@@ -47,10 +47,10 @@ M.availability_completion.form.getNode = function(json) {
|
||||
// Set initial values.
|
||||
if (json.cm !== undefined &&
|
||||
node.one('select[name=cm] > option[value=' + json.cm + ']')) {
|
||||
node.one('select[name=cm]').set('value', '' + json.cm);
|
||||
node.one('select[name=cm]').set('value', json.cm);
|
||||
}
|
||||
if (json.e !== undefined) {
|
||||
node.one('select[name=e]').set('value', '' + json.e);
|
||||
node.one('select[name=e]').set('value', json.e);
|
||||
}
|
||||
|
||||
// Add event handlers (first time only).
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-availability_completion-form",function(e,t){M.availability_completion=M.availability_completion||{},M.availability_completion.form=e.Object(M.core_availability.plugin),M.availability_completion.form.initInner=function(e){this.cms=e},M.availability_completion.form.getNode=function(t){var n=M.str.availability_completion,r=n.title+' <span class="availability-group"><label>'+'<span class="accesshide">'+n.label_cm+" </span>"+'<select name="cm" title="'+n.label_cm+'">'+'<option value="0">'+M.str.moodle.choosedots+"</option>";for(var i=0;i<this.cms.length;i++){var s=this.cms[i];r+='<option value="'+s.id+'">'+s.name+"</option>"}r+='</select></label> <label><span class="accesshide">'+n.label_completion+' </span><select name="e" title="'+n.label_completion+'">'+'<option value="1">'+n.option_complete+"</option>"+'<option value="0">'+n.option_incomplete+"</option>"+'<option value="2">'+n.option_pass+"</option>"+'<option value="3">'+n.option_fail+"</option>"+"</select></label></span>";var o=e.Node.create("<span>"+r+"</span>");t.cm!==undefined&&o.one("select[name=cm] > option[value="+t.cm+"]")&&o.one("select[name=cm]").set("value",""+t.cm),t.e!==undefined&&o.one("select[name=e]").set("value",""+t.e);if(!M.availability_completion.form.addedEvents){M.availability_completion.form.addedEvents=!0;var u=e.one("#fitem_id_availabilityconditionsjson");u.delegate("change",function(){M.core_availability.form.update()},".availability_completion select")}return o},M.availability_completion.form.fillValue=function(e,t){e.cm=parseInt(t.one("select[name=cm]").get("value"),10),e.e=parseInt(t.one("select[name=e]").get("value"),10)},M.availability_completion.form.fillErrors=function(e,t){var n=parseInt(t.one("select[name=cm]").get("value"),10);n===0&&e.push("availability_completion:error_selectcmid")}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]});
|
||||
YUI.add("moodle-availability_completion-form",function(e,t){M.availability_completion=M.availability_completion||{},M.availability_completion.form=e.Object(M.core_availability.plugin),M.availability_completion.form.initInner=function(e){this.cms=e},M.availability_completion.form.getNode=function(t){var n=M.str.availability_completion,r=n.title+' <span class="availability-group"><label>'+'<span class="accesshide">'+n.label_cm+" </span>"+'<select name="cm" title="'+n.label_cm+'">'+'<option value="0">'+M.str.moodle.choosedots+"</option>";for(var i=0;i<this.cms.length;i++){var s=this.cms[i];r+='<option value="'+s.id+'">'+s.name+"</option>"}r+='</select></label> <label><span class="accesshide">'+n.label_completion+' </span><select name="e" title="'+n.label_completion+'">'+'<option value="1">'+n.option_complete+"</option>"+'<option value="0">'+n.option_incomplete+"</option>"+'<option value="2">'+n.option_pass+"</option>"+'<option value="3">'+n.option_fail+"</option>"+"</select></label></span>";var o=e.Node.create("<span>"+r+"</span>");t.cm!==undefined&&o.one("select[name=cm] > option[value="+t.cm+"]")&&o.one("select[name=cm]").set("value",t.cm),t.e!==undefined&&o.one("select[name=e]").set("value",t.e);if(!M.availability_completion.form.addedEvents){M.availability_completion.form.addedEvents=!0;var u=e.one("#fitem_id_availabilityconditionsjson");u.delegate("change",function(){M.core_availability.form.update()},".availability_completion select")}return o},M.availability_completion.form.fillValue=function(e,t){e.cm=parseInt(t.one("select[name=cm]").get("value"),10),e.e=parseInt(t.one("select[name=e]").get("value"),10)},M.availability_completion.form.fillErrors=function(e,t){var n=parseInt(t.one("select[name=cm]").get("value"),10);n===0&&e.push("availability_completion:error_selectcmid")}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]});
|
||||
|
||||
+2
-2
@@ -47,10 +47,10 @@ M.availability_completion.form.getNode = function(json) {
|
||||
// Set initial values.
|
||||
if (json.cm !== undefined &&
|
||||
node.one('select[name=cm] > option[value=' + json.cm + ']')) {
|
||||
node.one('select[name=cm]').set('value', '' + json.cm);
|
||||
node.one('select[name=cm]').set('value', json.cm);
|
||||
}
|
||||
if (json.e !== undefined) {
|
||||
node.one('select[name=e]').set('value', '' + json.e);
|
||||
node.one('select[name=e]').set('value', json.e);
|
||||
}
|
||||
|
||||
// Add event handlers (first time only).
|
||||
|
||||
@@ -45,10 +45,10 @@ M.availability_completion.form.getNode = function(json) {
|
||||
// Set initial values.
|
||||
if (json.cm !== undefined &&
|
||||
node.one('select[name=cm] > option[value=' + json.cm + ']')) {
|
||||
node.one('select[name=cm]').set('value', '' + json.cm);
|
||||
node.one('select[name=cm]').set('value', json.cm);
|
||||
}
|
||||
if (json.e !== undefined) {
|
||||
node.one('select[name=e]').set('value', '' + json.e);
|
||||
node.one('select[name=e]').set('value', json.e);
|
||||
}
|
||||
|
||||
// Add event handlers (first time only).
|
||||
|
||||
@@ -77,20 +77,6 @@ class condition extends \core_availability\condition {
|
||||
'd' => $this->direction, 't' => $this->time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object which corresponds to a condition of this type.
|
||||
*
|
||||
* Intended for unit testing, as normally the JSON values are constructed
|
||||
* by JavaScript code.
|
||||
*
|
||||
* @param string $direction DIRECTION_xx constant
|
||||
* @param int $time Time in epoch seconds
|
||||
* @return stdClass Object representing condition
|
||||
*/
|
||||
public static function get_json($direction, $time) {
|
||||
return (object)array('type' => 'date', 'd' => $direction, 't' => (int)$time);
|
||||
}
|
||||
|
||||
public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
|
||||
return $this->is_available_for_all($not);
|
||||
}
|
||||
@@ -223,15 +209,4 @@ class condition extends \core_availability\condition {
|
||||
protected static function is_midnight($time) {
|
||||
return usergetmidnight($time) == $time;
|
||||
}
|
||||
|
||||
public function update_after_restore(
|
||||
$restoreid, $courseid, \base_logger $logger, $name) {
|
||||
// Update the date, if restoring with changed date.
|
||||
$dateoffset = \core_availability\info::get_restore_date_offset($restoreid);
|
||||
if ($dateoffset) {
|
||||
$this->time += $dateoffset;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ M.availability_date.form.getNode = function(json) {
|
||||
var fields = Y.JSON.parse(response.responseText);
|
||||
for (var field in fields) {
|
||||
var select = node.one('select[name=x\\[' + field + '\\]]');
|
||||
select.set('value', '' + fields[field]);
|
||||
select.set('value', fields[field]);
|
||||
select.set('disabled', false);
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-availability_date-form",function(e,t){M.availability_date=M.availability_date||{},M.availability_date.form=e.Object(M.core_availability.plugin),M.availability_date.form.initInner=function(e,t){this.html=e,this.defaultTime=t},M.availability_date.form.getNode=function(t){var n=M.str.availability_date,r=n.direction_before+' <span class="availability-group">'+'<label><span class="accesshide">'+n.direction_label+" </span>"+'<select name="direction">'+'<option value=">=">'+n.direction_from+"</option>"+'<option value="<">'+n.direction_until+"</option>"+"</select></label></span> "+this.html,i=e.Node.create("<span>"+r+"</span>");if(t.t!==undefined){i.setData("time",t.t),i.all("select:not([name=direction])").each(function(e){e.set("disabled",!0)});var s=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=fromtime"+"&time="+t.t;e.io(s,{on:{success:function(t,n){var r=e.JSON.parse(n.responseText);for(var s in r){var o=i.one("select[name=x\\["+s+"\\]]");o.set("value",""+r[s]),o.set("disabled",!1)}},failure:function(){window.alert(M.str.availability_date.ajaxerror)}}})}else i.setData("time",this.defaultTime);t.d!==undefined&&i.one("select[name=direction]").set("value",t.d);if(!M.availability_date.form.addedEvents){M.availability_date.form.addedEvents=!0;var o=e.one("#fitem_id_availabilityconditionsjson");o.delegate("change",function(){M.core_availability.form.update()},".availability_date select[name=direction]"),o.delegate("change",function(){M.availability_date.form.updateTime(this.ancestor("span.availability_date"))},".availability_date select:not([name=direction])")}if(i.one("a[href=#]")){M.form.dateselector.init_single_date_selector(i);var u=i.one("select[name=x\\[year\\]]"),a=u.set;u.set=function(e,t){a.call(u,e,t),e==="selectedIndex"&&setTimeout(function(){M.availability_date.form.updateTime(i)},0)}}return i},M.availability_date.form.updateTime=function(t){var n=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=totime"+"&year="+t.one("select[name=x\\[year\\]]").get("value")+"&month="+t.one("select[name=x\\[month\\]]").get("value")+"&day="+t.one("select[name=x\\[day\\]]").get("value")+"&hour="+t.one("select[name=x\\[hour\\]]").get("value")+"&minute="+t.one("select[name=x\\[minute\\]]").get("value");e.io(n,{on:{success:function(e,n){t.setData("time",n.responseText),M.core_availability.form.update()},failure:function(){window.alert(M.str.availability_date.ajaxerror)}}})},M.availability_date.form.fillValue=function(e,t){e.d=t.one("select[name=direction]").get("value"),e.t=parseInt(t.getData("time"),10)}},"@VERSION@",{requires:["base","node","event","io","moodle-core_availability-form"]});
|
||||
YUI.add("moodle-availability_date-form",function(e,t){M.availability_date=M.availability_date||{},M.availability_date.form=e.Object(M.core_availability.plugin),M.availability_date.form.initInner=function(e,t){this.html=e,this.defaultTime=t},M.availability_date.form.getNode=function(t){var n=M.str.availability_date,r=n.direction_before+' <span class="availability-group">'+'<label><span class="accesshide">'+n.direction_label+" </span>"+'<select name="direction">'+'<option value=">=">'+n.direction_from+"</option>"+'<option value="<">'+n.direction_until+"</option>"+"</select></label></span> "+this.html,i=e.Node.create("<span>"+r+"</span>");if(t.t!==undefined){i.setData("time",t.t),i.all("select:not([name=direction])").each(function(e){e.set("disabled",!0)});var s=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=fromtime"+"&time="+t.t;e.io(s,{on:{success:function(t,n){var r=e.JSON.parse(n.responseText);for(var s in r){var o=i.one("select[name=x\\["+s+"\\]]");o.set("value",r[s]),o.set("disabled",!1)}},failure:function(){window.alert(M.str.availability_date.ajaxerror)}}})}else i.setData("time",this.defaultTime);t.d!==undefined&&i.one("select[name=direction]").set("value",t.d);if(!M.availability_date.form.addedEvents){M.availability_date.form.addedEvents=!0;var o=e.one("#fitem_id_availabilityconditionsjson");o.delegate("change",function(){M.core_availability.form.update()},".availability_date select[name=direction]"),o.delegate("change",function(){M.availability_date.form.updateTime(this.ancestor("span.availability_date"))},".availability_date select:not([name=direction])")}if(i.one("a[href=#]")){M.form.dateselector.init_single_date_selector(i);var u=i.one("select[name=x\\[year\\]]"),a=u.set;u.set=function(e,t){a.call(u,e,t),e==="selectedIndex"&&setTimeout(function(){M.availability_date.form.updateTime(i)},0)}}return i},M.availability_date.form.updateTime=function(t){var n=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=totime"+"&year="+t.one("select[name=x\\[year\\]]").get("value")+"&month="+t.one("select[name=x\\[month\\]]").get("value")+"&day="+t.one("select[name=x\\[day\\]]").get("value")+"&hour="+t.one("select[name=x\\[hour\\]]").get("value")+"&minute="+t.one("select[name=x\\[minute\\]]").get("value");e.io(n,{on:{success:function(e,n){t.setData("time",n.responseText),M.core_availability.form.update()},failure:function(){window.alert(M.str.availability_date.ajaxerror)}}})},M.availability_date.form.fillValue=function(e,t){e.d=t.one("select[name=direction]").get("value"),e.t=parseInt(t.getData("time"),10)}},"@VERSION@",{requires:["base","node","event","io","moodle-core_availability-form"]});
|
||||
|
||||
availability/condition/date/yui/build/moodle-availability_date-form/moodle-availability_date-form.js
Vendored
+1
-1
@@ -53,7 +53,7 @@ M.availability_date.form.getNode = function(json) {
|
||||
var fields = Y.JSON.parse(response.responseText);
|
||||
for (var field in fields) {
|
||||
var select = node.one('select[name=x\\[' + field + '\\]]');
|
||||
select.set('value', '' + fields[field]);
|
||||
select.set('value', fields[field]);
|
||||
select.set('disabled', false);
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ M.availability_date.form.getNode = function(json) {
|
||||
var fields = Y.JSON.parse(response.responseText);
|
||||
for (var field in fields) {
|
||||
var select = node.one('select[name=x\\[' + field + '\\]]');
|
||||
select.set('value', '' + fields[field]);
|
||||
select.set('value', fields[field]);
|
||||
select.set('disabled', false);
|
||||
}
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user