MDL-87648 router: Add check report data for router configuration

This commit is contained in:
Andrew Nicols
2026-01-22 11:26:06 +08:00
parent ba68156c83
commit 55ab5d6758
10 changed files with 349 additions and 2 deletions
+2
View File
@@ -58,6 +58,8 @@ $CFG->pathtophp = getenv('pathtophp');
$CFG->phpunit_dataroot = realpath(dirname(__DIR__)) . '/phpunitdata';
$CFG->phpunit_prefix = 't_';
$CFG->routerconfigured = true;
define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080');
define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080');
+2 -2
View File
@@ -142,7 +142,8 @@ foreach ($checks as $check) {
);
$summary = str_replace("\n", "\n" . $prefix . ' ', $summary);
$output .= sprintf( $format, '', ' ' . $summary);
$output .= sprintf($format, '', ' ' . $summary);
$output .= sprintf($format, '', ' ' . html_to_text($result->get_details(), width: 0, dolinks: false));
if ($options['verbose']) {
$actionlink = $check->get_action_link();
@@ -168,4 +169,3 @@ if ($output) {
// NRPE shell exit code.
exit($exitcode);
+1
View File
@@ -5233,6 +5233,7 @@
<CUSTOM_CHECK function="\core\environment::check_composer_dependencies_installed" level="optional" />
<CUSTOM_CHECK function="\core\environment::check_composer_developer_dependencies_not_installed" level="optional" />
<CUSTOM_CHECK function="\core\environment::check_composer_dependencies_optimised" level="optional" />
<CUSTOM_CHECK function="\core\environment::check_router_configuration" level="optional" />
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
+16
View File
@@ -126,6 +126,7 @@ $string['cannotuninstall'] = '{$a} can not be uninstalled.';
$string['categoryemail'] = 'Email';
$string['cfgwwwrootslashwarning'] = '$CFG->wwwroot is defined incorrectly in the config.php file. It includes a \'/\' character at the end which must be removed.';
$string['cfgwwwrootwarning'] = '$CFG->wwwroot is defined incorrectly in the config.php file. It should match the URL you are using to access this page.';
$string['check_router'] = 'Router configuration';
$string['checkupgradepending'] = 'Upgrade';
$string['cleanup'] = 'Cleanup';
$string['clianswerno'] = 'n';
@@ -1171,6 +1172,21 @@ $string['requiremodintro'] = 'Require activity description';
$string['requiremodintro_desc'] = 'If enabled, users will be forced to enter a description for each activity.';
$string['required'] = 'Required';
$string['requires'] = 'Requires';
$string['routerconfigurationset'] = 'Moodle has been informed that the web server is correctly configured.';
$string['routerconfigureddetails'] = 'The router correctly serves <a href="{$a->docs}" target="_blank">{$a->url}</a> with a {$a->expectedstatuscode} ("{$a->expectedstatuscodetitle}") response.';
$string['routerconfiguredok'] = 'The router appears to be configured correctly.';
$string['routerconfiguredwithissues'] = 'The router is not correctly configured.';
$string['routerconfiguredwithissuesdetail'] = 'The router is not correctly configured - Issues were detected in {$a->count} checks.';
$string['routerdocs'] = 'Router documentation';
$string['routerexpectedgot'] = 'Expected {$a->expectedstatuscode} ("{$a->expectedstatuscodetitle}") and received {$a->statuscode} ("{$a->statuscodetitle}").';
$string['routerfailapipage'] = 'An <a href="{$a->url}" target="_blank">API route</a> did not respond with the expected response.';
$string['routerfailmissingpage'] = 'The missing page handler did not respond to the <a href="{$a->url}" target="_blank">test URL</a> correctly.';
$string['routerfailpage'] = 'A <a href="{$a->url}" target="_blank">standard page</a> controller could not be loaded correctly. The router may not be configured properly.';
$string['routerfailroutershim'] = 'A <a href="{$a->url}" target="_blank">routed page whose path ends in ".php"</a> did not response correctly.';
$string['routerfailshim'] = 'A <a href="{$a->url}" target="_blank">shimmed page</a> did not response correctly.';
$string['routernotconfigured'] = 'The router is not configured.';
$string['routernotconfigureddetail'] = 'The router has not been configured correctly. Please see the <a href="{$a->docs}">documentation</a> for more information on how to configure it correctly.';
$string['routernotconfigureddetailwithurl'] = 'The following URL did not return the expected status code: <a href="{$a->url}" target="_blank">{$a->url}</a>.';
$string['purgecaches'] = 'Purge all caches';
$string['purgecachesconfirm'] = 'Moodle can cache themes, JavaScript, language strings, filtered text, RSS feeds and other pieces of calculated data. Purging caches will delete data from the server and force browsers to re-fetch data, so you can be sure you are seeing the most up-to-date values produced by the current code. There is no danger in purging caches, but your site may appear slower for a while until the server and clients calculate new information and cache it.';
$string['purgecachesfinished'] = 'All caches were purged.';
@@ -0,0 +1,158 @@
<?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/>.
namespace core\check\environment;
use core\check\check;
use core\check\result;
use core\output\action_link;
use GuzzleHttp\HandlerStack;
/**
* Checks status of router by making test requests to shimmed and API pages.
*
* @package core
* @category check
* @copyright Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class router extends check {
#[\Override]
public function get_name(): string {
return get_string('check_router', 'admin');
}
/**
* Get the list of tests
*
* @return \Generator
*/
protected function get_tests(): \Generator {
yield [
'url' => '/core/check/controller/test',
'expectedcode' => 200,
'expectedcodetitle' => "OK",
'failfeedbackstr' => 'routerfailpage',
'bookmarkanchor' => 'routerfailpage',
];
yield [
'url' => '/api/rest/v2/openapi.json',
'expectedcode' => 200,
'expectedcodetitle' => "OK",
'failfeedbackstr' => 'routerfailapipage',
'bookmarkanchor' => 'routerfailapipage',
];
yield [
'url' => '/not/a/valid/request',
'expectedcode' => 404,
'expectedcodetitle' => "Not Found",
'failfeedbackstr' => 'routerfailmissingpage',
'bookmarkanchor' => 'routerfailmissingpage',
];
yield [
'url' => \core\router\util::get_path_for_callable([\core\route\shim\test_controller::class, 'real_file_shim']),
'expectedcode' => 302,
'expectedcodetitle' => "Found",
'failfeedbackstr' => 'routerfailshim',
'bookmarkanchor' => 'routerfailshim',
];
yield [
'url' => \core\router\util::get_path_for_callable([\core\route\shim\test_controller::class, 'nofile_shim']),
'expectedcode' => 302,
'expectedcodetitle' => "Found",
'failfeedbackstr' => 'routerfailroutershim',
'bookmarkanchor' => 'routerfailroutershim',
];
}
#[\Override]
public function get_result(): result {
global $CFG;
if (empty($CFG->routerconfigured)) {
$result = new result(
result::ERROR,
get_string('routernotconfigured', 'admin'),
get_string('routernotconfigureddetail', 'admin', [
'docs' => get_docs_url("Configuring_the_Router#routernotconfigured"),
]),
);
return $result;
}
// The router is marked as configured. Check if it actually works though.
$client = \core\di::get(\core\http_client::class);
$clientoptions = [
'http_errors' => false,
'allow_redirects' => false,
// Override the Handler Stack to ensure that no caching is used, an that the security helper is not applied.
'handler' => HandlerStack::create(),
];
foreach ($this->get_tests() as $test) {
if ($test['url'] instanceof \core\url) {
$fullurl = $test['url']->out(false);
} else {
$fullurl = $CFG->wwwroot . $test['url'];
}
try {
$response = $client->get($fullurl, $clientoptions);
$code = $response->getStatusCode();
$codetitle = $response->getReasonPhrase();
} catch (\GuzzleHttp\Exception\GuzzleException $e) {
$code = $e->getCode();
$codetitle = $e->getMessage();
}
$resultprops = [
'url' => $fullurl,
'docs' => get_docs_url("Configuring_the_Router#{$test['bookmarkanchor']}"),
'expectedstatuscode' => $test['expectedcode'],
'expectedstatuscodetitle' => $test['expectedcodetitle'],
'statuscode' => $code,
'statuscodetitle' => $codetitle,
];
if ($code !== $test['expectedcode']) {
$expectedgot = get_string('routerexpectedgot', 'admin', $resultprops);
return new result(
result::ERROR,
get_string($test['failfeedbackstr'], 'admin', $resultprops),
get_string('routernotconfigureddetailwithurl', 'admin', $resultprops) . " {$expectedgot}",
new action_link(
new \core\url(get_docs_url("Configuring_the_Router#{$test['bookmarkanchor']}")),
get_string('routerdocs', 'admin'),
),
);
}
}
return new result(
result::OK,
get_string('routerconfiguredok', 'admin'),
);
}
#[\Override]
public function get_action_link(): ?action_link {
return new action_link(
new \core\url(get_docs_url('Configuring_the_Router')),
get_string('routerdocs', 'admin'),
);
}
}
+1
View File
@@ -97,6 +97,7 @@ class manager {
new environment\environment(),
new environment\upgradecheck(),
new environment\antivirus(),
new environment\router(),
];
// Any plugin can add status checks to this report by implementing a callback
+19
View File
@@ -160,4 +160,23 @@ class environment {
return !empty($CFG->debugdeveloper);
}
/**
* Ensure that the Router is correctly configured.
*
* @param \environment_results $result
* @return \environment_results|null
*/
public static function check_router_configuration(\environment_results $result): ?\environment_results {
global $CFG;
if (empty($CFG->routerconfigured)) {
// The router has not been marked as configured.
$result->setInfo('Router not configured');
$result->setFeedbackStr('routernotconfigured');
return $result;
}
return null;
}
}
@@ -0,0 +1,45 @@
<?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/>.
namespace core\route\controller;
use Psr\Http\Message\ResponseInterface;
/**
* Test controller to provide a route for testing purposes.
*
* This set of routes is primarily intended for use with the Environment Checks
* to help administrators ensure that the Routing system is correctly configured.
*
* @package core
* @copyright Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_controller {
/**
* Test controller route.
*
* @param ResponseInterface $response
* @return ResponseInterface
*/
#[\core\router\route(
path: '/check/controller/test',
)]
public function test_action(ResponseInterface $response): ResponseInterface {
$response->getBody()->write('Test controller response');
return $response;
}
}
@@ -0,0 +1,75 @@
<?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/>.
namespace core\route\shim;
use core\router\route_controller;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* An example shim route to use for testing.
*
* This set of routes is primarily intended for use with the Environment Checks
* to help administrators ensure that the Routing system is correctly configured.
*
* @package core
* @copyright Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_controller {
use route_controller;
/**
* An example shim route action for a file which manually shims the request.
*
* @param ResponseInterface $response
* @return ResponseInterface
*/
#[\core\router\route(
path: '/lib/exampleshimroute.php',
)]
public function real_file_shim(
RequestInterface $request,
ResponseInterface $response,
): ResponseInterface {
return self::redirect_to_callable(
$request,
$response,
[\core\route\controller\test_controller::class, 'test_action'],
);
}
/**
* An example shim route action for a file which no longer exists.
*
* @param ResponseInterface $response
* @return ResponseInterface
*/
#[\core\router\route(
path: '/lib/exampleshimroute2.php',
)]
public function nofile_shim(
RequestInterface $request,
ResponseInterface $response,
): ResponseInterface {
return self::redirect_to_callable(
$request,
$response,
[\core\route\controller\test_controller::class, 'test_action'],
);
}
}
+30
View File
@@ -0,0 +1,30 @@
<?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/>.
/**
* An example shim route to use for testing.
*
* This page is primarily intended for use with the Environment Checks
* to help administrators ensure that the Routing system is correctly configured.
*
* This file simulates a legacy file which has not yet been removed, but which exists in the Routing configuration.
*
* @package core
* @copyright Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once("../r.php");