Merge branch 'MDL-87648-main' of https://github.com/andrewnicols/moodle
This commit is contained in:
@@ -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');
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
issueNumber: MDL-87648
|
||||
notes:
|
||||
core:
|
||||
- message: >
|
||||
The Checks API now supports multiple results being returned for a single
|
||||
instance of `\core\check\check`.
|
||||
|
||||
|
||||
To support this a new `get_results(): array;` method has been created
|
||||
which returns an array of `\core\check\result` objects.
|
||||
type: improved
|
||||
+34
-32
@@ -110,46 +110,49 @@ $exitcode = $exitcodes[result::OK];
|
||||
|
||||
foreach ($checks as $check) {
|
||||
$ref = $check->get_ref();
|
||||
$result = $check->get_result();
|
||||
|
||||
$status = $result->get_status();
|
||||
$checkexitcode = $exitcodes[$status];
|
||||
foreach ($check->get_results() as $result) {
|
||||
$status = $result->get_status();
|
||||
$checkexitcode = $exitcodes[$status];
|
||||
|
||||
// Summary is treated as html.
|
||||
$summary = $result->get_summary();
|
||||
$summary = html_to_text($summary, 60, false);
|
||||
// Summary is treated as html.
|
||||
$summary = $result->get_summary();
|
||||
$summary = html_to_text($summary, 60, false);
|
||||
|
||||
if ($checkexitcode > $exitcode) {
|
||||
$exitcode = $checkexitcode;
|
||||
$header = $exitlabel[$status] . ': ' . $check->get_name() . " (" . $check->get_ref() . ")\n";
|
||||
}
|
||||
if ($checkexitcode > $exitcode) {
|
||||
$exitcode = $checkexitcode;
|
||||
$header = $exitlabel[$status] . ': ' . $check->get_name() . " (" . $check->get_ref() . ")\n";
|
||||
}
|
||||
|
||||
if (empty($messages[$status])) {
|
||||
$messages[$status] = $result;
|
||||
}
|
||||
if (empty($messages[$status])) {
|
||||
$messages[$status] = $result;
|
||||
}
|
||||
|
||||
$len = strlen(get_string('status' . $status));
|
||||
$len = strlen(get_string('status' . $status));
|
||||
|
||||
if ($options['verbose'] ||
|
||||
$status == result::WARNING ||
|
||||
$status == result::CRITICAL ||
|
||||
$status == result::ERROR) {
|
||||
if (
|
||||
$options['verbose']
|
||||
|| $status == result::WARNING
|
||||
|| $status == result::CRITICAL
|
||||
|| $status == result::ERROR
|
||||
) {
|
||||
$output .= sprintf(
|
||||
$format,
|
||||
$OUTPUT->check_result($result),
|
||||
sprintf('%s (%s)', $check->get_name(), $ref),
|
||||
);
|
||||
|
||||
$output .= sprintf(
|
||||
$format,
|
||||
$OUTPUT->check_result($result),
|
||||
sprintf('%s (%s)', $check->get_name(), $ref)
|
||||
);
|
||||
$summary = str_replace("\n", "\n" . $prefix . ' ', $summary);
|
||||
$output .= sprintf($format, '', ' ' . $summary);
|
||||
$output .= sprintf($format, '', ' ' . html_to_text($result->get_details(), width: 0, dolinks: false));
|
||||
|
||||
$summary = str_replace("\n", "\n" . $prefix . ' ', $summary);
|
||||
$output .= sprintf( $format, '', ' ' . $summary);
|
||||
|
||||
if ($options['verbose']) {
|
||||
$actionlink = $check->get_action_link();
|
||||
if ($actionlink) {
|
||||
$output .= sprintf( $format, '', ' ' . $actionlink->url);
|
||||
if ($options['verbose']) {
|
||||
$actionlink = $check->get_action_link();
|
||||
if ($actionlink) {
|
||||
$output .= sprintf($format, '', ' ' . $actionlink->url);
|
||||
}
|
||||
$output .= sprintf($format, '', '');
|
||||
}
|
||||
$output .= sprintf( $format, '', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,4 +171,3 @@ if ($output) {
|
||||
|
||||
// NRPE shell exit code.
|
||||
exit($exitcode);
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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.';
|
||||
|
||||
@@ -128,5 +128,12 @@ abstract class check {
|
||||
*/
|
||||
abstract public function get_result(): result;
|
||||
|
||||
/**
|
||||
* Return all results for this check
|
||||
*
|
||||
* @return result[]
|
||||
*/
|
||||
public function get_results(): array {
|
||||
return [$this->get_result()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
<?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_results(): array {
|
||||
global $CFG;
|
||||
|
||||
$results = [];
|
||||
|
||||
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];
|
||||
} else {
|
||||
$results[] = new result(
|
||||
result::OK,
|
||||
get_string('routerconfigurationset', 'admin'),
|
||||
);
|
||||
}
|
||||
|
||||
// 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']) {
|
||||
$results[] = new result(
|
||||
result::OK,
|
||||
get_string('routerconfigureddetails', 'admin', $resultprops),
|
||||
);
|
||||
} else {
|
||||
$expectedgot = get_string('routerexpectedgot', 'admin', $resultprops);
|
||||
$results[] = 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 $results;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function get_result(): result {
|
||||
// Aggregate the results.
|
||||
$failed = array_filter(
|
||||
$this->get_results(),
|
||||
fn ($result) => $result->get_status() !== result::OK,
|
||||
);
|
||||
|
||||
if (empty($failed)) {
|
||||
// Nothing failed. Return the OK result.
|
||||
return new result(
|
||||
result::OK,
|
||||
get_string('routerconfiguredok', 'admin'),
|
||||
);
|
||||
}
|
||||
|
||||
// Some form of failure. Return the generic failure result.
|
||||
return new result(
|
||||
result::ERROR,
|
||||
get_string('routerconfiguredwithissues', 'admin'),
|
||||
get_string('routerconfiguredwithissuesdetail', 'admin', ['count' => count($failed)]),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
namespace core\check;
|
||||
|
||||
use core\output\action_link;
|
||||
|
||||
/**
|
||||
* A check object returns a result object
|
||||
*
|
||||
@@ -29,7 +31,6 @@ namespace core\check;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class result implements \renderable {
|
||||
|
||||
/**
|
||||
* This is used to notify if a check does not apply.
|
||||
*
|
||||
@@ -99,7 +100,14 @@ class result implements \renderable {
|
||||
* This may be a large amount of preformatted html text, possibly describing all the
|
||||
* different states and actions to address them.
|
||||
*/
|
||||
protected $details = '';
|
||||
protected string $details = '';
|
||||
|
||||
/**
|
||||
* @var null|action_link An action link which is more specific than the general check link, if relvant
|
||||
*
|
||||
* If no specific check link is specified, then the check link will be used.
|
||||
*/
|
||||
protected ?action_link $actionlink = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -107,11 +115,18 @@ class result implements \renderable {
|
||||
* @param string $status code
|
||||
* @param string $summary a 1 liner summary
|
||||
* @param string $details as a html chunk
|
||||
* @param ?action_link $details An action link which is more specific than the general check link, if relevant
|
||||
*/
|
||||
public function __construct($status, $summary, $details = '') {
|
||||
public function __construct(
|
||||
string $status,
|
||||
string $summary,
|
||||
string $details = '',
|
||||
?action_link $actionlink = null,
|
||||
) {
|
||||
$this->status = $status;
|
||||
$this->summary = $summary;
|
||||
$this->details = $details;
|
||||
$this->actionlink = $actionlink;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,5 +181,13 @@ class result implements \renderable {
|
||||
public function get_template_name(): string {
|
||||
return 'core/check/result';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an action link if a more specific one was specified.
|
||||
*
|
||||
* @return null|action_link
|
||||
*/
|
||||
public function get_action_link(): ?action_link {
|
||||
return $this->actionlink;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,26 +14,19 @@
|
||||
// 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;
|
||||
|
||||
use core\output\html_writer;
|
||||
|
||||
/**
|
||||
* A table of check results
|
||||
* A table of check results.
|
||||
*
|
||||
* @package core
|
||||
* @category check
|
||||
* @copyright 2020 Brendan Heywood <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core\check;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A table of check results
|
||||
*
|
||||
* @copyright 2020 Brendan Heywood <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class table implements \renderable {
|
||||
|
||||
class table implements \core\output\renderable {
|
||||
/**
|
||||
* @var \moodle_url $url
|
||||
*/
|
||||
@@ -49,6 +42,13 @@ class table implements \renderable {
|
||||
*/
|
||||
public $detail = '';
|
||||
|
||||
/**
|
||||
* The name of the check that was requested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $checkname = '';
|
||||
|
||||
/**
|
||||
* @var array $checks shown in this table
|
||||
*/
|
||||
@@ -62,7 +62,6 @@ class table implements \renderable {
|
||||
* @param string $detail check to focus on
|
||||
*/
|
||||
public function __construct($type, $url, $detail = '') {
|
||||
|
||||
// We may need a bit more memory and this may take a long time to process.
|
||||
\raise_memory_limit(MEMORY_EXTRA);
|
||||
\core_php_time_limit::raise();
|
||||
@@ -70,6 +69,7 @@ class table implements \renderable {
|
||||
$this->type = $type;
|
||||
$this->url = $url;
|
||||
$this->checks = \core\check\manager::get_checks($type);
|
||||
$this->checkname = $detail;
|
||||
|
||||
if ($detail) {
|
||||
$this->checks = array_filter($this->checks, function($check) use ($detail) {
|
||||
@@ -84,63 +84,91 @@ class table implements \renderable {
|
||||
/**
|
||||
* Render a table of checks
|
||||
*
|
||||
* @param renderer $output to use
|
||||
* @param \core\output\renderer $output to use
|
||||
* @return string html output
|
||||
*/
|
||||
public function render($output) {
|
||||
$html = '';
|
||||
|
||||
$table = new \html_table();
|
||||
$table = new \core_table\output\html_table();
|
||||
$table->data = [];
|
||||
$table->head = [
|
||||
get_string('status'),
|
||||
get_string('check'),
|
||||
get_string('summary'),
|
||||
get_string('action'),
|
||||
];
|
||||
$table->colclasses = [
|
||||
'rightalign status',
|
||||
'leftalign check',
|
||||
'leftalign summary',
|
||||
'leftalign action',
|
||||
];
|
||||
$table->head = [get_string('status')];
|
||||
$table->colclasses = ['rightalign status'];
|
||||
|
||||
if (empty($this->checkname)) {
|
||||
$table->head[] = get_string('check');
|
||||
$table->colclasses[] = 'leftalign check';
|
||||
} else {
|
||||
$html .= html_writer::tag('h3', $this->detail->get_name());
|
||||
}
|
||||
|
||||
$table->head[] = get_string('summary');
|
||||
$table->colclasses[] = 'leftalign summary';
|
||||
$table->head[] = get_string('action');
|
||||
$table->colclasses[] = 'leftalign action';
|
||||
|
||||
$table->id = $this->type . 'reporttable';
|
||||
$table->attributes = ['class' => 'admintable ' . $this->type . 'report table generaltable'];
|
||||
|
||||
$fails = [];
|
||||
foreach ($this->checks as $check) {
|
||||
$ref = $check->get_ref();
|
||||
$result = $check->get_result();
|
||||
$component = $check->get_component();
|
||||
$actionlink = $check->get_action_link();
|
||||
|
||||
$link = new \moodle_url($this->url, ['detail' => $ref]);
|
||||
|
||||
$row = [];
|
||||
$row[] = $output->check_result($result);
|
||||
$row[] = $output->action_link($link, $check->get_name());
|
||||
$results = empty($this->checkname)
|
||||
? [$check->get_result()]
|
||||
: $check->get_results();
|
||||
|
||||
$row[] = $result->get_summary()
|
||||
. '<br>'
|
||||
. \html_writer::start_tag('small')
|
||||
. $output->action_link($link, get_string('moreinfo'))
|
||||
. \html_writer::end_tag('small');
|
||||
if ($actionlink) {
|
||||
$row[] = $output->render($actionlink);
|
||||
} else {
|
||||
$row[] = '';
|
||||
foreach ($results as $result) {
|
||||
$row = [];
|
||||
if ($result->get_status() !== result::OK) {
|
||||
$fails[] = $result;
|
||||
}
|
||||
$row[] = $output->check_result($result);
|
||||
|
||||
if (empty($this->checkname)) {
|
||||
$row[] = $output->action_link($link, $check->get_name());
|
||||
}
|
||||
|
||||
$row[] = $result->get_summary()
|
||||
. '<br>'
|
||||
. \html_writer::start_tag('small')
|
||||
. $output->action_link($link, get_string('moreinfo'))
|
||||
. \html_writer::end_tag('small');
|
||||
|
||||
$actionlink = $result->get_action_link() ?? $check->get_action_link();
|
||||
if ($actionlink) {
|
||||
$row[] = $output->render($actionlink);
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
$table->data[] = $row;
|
||||
}
|
||||
|
||||
$table->data[] = $row;
|
||||
}
|
||||
$html = \html_writer::table($table);
|
||||
$html .= \html_writer::table($table);
|
||||
|
||||
if ($this->detail && $result) {
|
||||
$details = $result->get_details();
|
||||
$details = array_filter(array_map(
|
||||
fn ($result) => $result->get_details(),
|
||||
$fails,
|
||||
));
|
||||
if (count($details) > 0) {
|
||||
$html .= $output->heading(get_string('details'), 3);
|
||||
|
||||
if (!empty($details)) {
|
||||
$html .= $output->heading(get_string('details'), 3);
|
||||
$html .= $output->box($details, 'generalbox boxwidthnormal boxaligncenter');
|
||||
if (count($details) === 1) {
|
||||
$result = reset($fails);
|
||||
$html .= $output->box($result->get_details(), 'generalbox boxwidthnormal boxaligncenter');
|
||||
} else {
|
||||
$html .= html_writer::start_tag('ul');
|
||||
foreach ($details as $detail) {
|
||||
$html .= html_writer::tag('li', $detail);
|
||||
}
|
||||
$html .= html_writer::end_tag('ul');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->detail) {
|
||||
$html .= $output->continue_button($this->url);
|
||||
}
|
||||
|
||||
|
||||
@@ -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'],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
@@ -201,6 +201,7 @@ $allowed = ['wwwroot', 'dataroot', 'dirroot', 'admin', 'directorypermissions', '
|
||||
'proxyhost', 'proxyport', 'proxytype', 'proxyuser', 'proxypassword', 'proxybypass',
|
||||
'altcacheconfigpath', 'pathtogs', 'pathtophp', 'pathtodu', 'aspellpath', 'pathtodot',
|
||||
'pathtounoconv', 'alternative_file_system_class', 'pathtopython',
|
||||
'routerconfigured',
|
||||
];
|
||||
$productioncfg = (array) $CFG;
|
||||
$CFG = new stdClass();
|
||||
|
||||
@@ -93,12 +93,14 @@ final class router_test extends route_testcase {
|
||||
*/
|
||||
public function test_basepath(
|
||||
string $wwwroot,
|
||||
bool $configured,
|
||||
string $expected,
|
||||
): void {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$CFG->wwwroot = $wwwroot;
|
||||
$CFG->routerconfigured = $configured;
|
||||
|
||||
$router = di::get(router::class);
|
||||
|
||||
@@ -106,8 +108,10 @@ final class router_test extends route_testcase {
|
||||
}
|
||||
|
||||
public static function basepath_provider(): \Iterator {
|
||||
yield 'Domain' => ['http://example.com', '/r.php'];
|
||||
yield 'Subdirectory' => ['http://example.com/moodle', '/moodle/r.php'];
|
||||
yield 'Domain Router not configured' => ['http://example.com', false, '/r.php'];
|
||||
yield 'Domain Router configured' => ['http://example.com', true, ''];
|
||||
yield 'Subdirectory Router not configured' => ['http://example.com/moodle', false, '/moodle/r.php'];
|
||||
yield 'Subdirectory Router configured' => ['http://example.com/moodle', true, '/moodle'];
|
||||
}
|
||||
|
||||
public function test_basepath_guessed_rphp(): void {
|
||||
|
||||
Reference in New Issue
Block a user