From 675ec899f41bb0d1445932dc7f22dfa59e630e22 Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Sun, 12 Jul 2026 22:15:41 +0100 Subject: [PATCH 1/9] WR #490867 auth_outage Review changes - add capability check to preview.php and escape outage title/description output in info page and renderer, validate access key parameter before use --- classes/local/outagelib.php | 4 ++-- classes/output/renderer.php | 4 ++-- preview.php | 2 ++ views/info/content.php | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php index 35565d34..48374d6b 100644 --- a/classes/local/outagelib.php +++ b/classes/local/outagelib.php @@ -284,7 +284,7 @@ public static function create_climaintenancephp_code($starttime, $stoptime, $all require_once($CFG->dirroot.'/lib/classes/ip_utils.php'); } // Put access key as a cookie if given. This stops the need to put it as a url param on every request. - $urlaccesskey = optional_param('accesskey', null, PARAM_TEXT); + $urlaccesskey = optional_param('accesskey', null, PARAM_ALPHANUM); $isphpunit = defined('PHPUNIT_TEST'); if (!empty($urlaccesskey) && !$isphpunit) { @@ -328,7 +328,7 @@ public static function create_climaintenancephp_code($starttime, $stoptime, $all } if ({{USEACCESSKEY}} && $accesskeyblocked) { - echo ''; + echo ''; } if (!$isphpunit) { diff --git a/classes/output/renderer.php b/classes/output/renderer.php index 4fce37b1..35288ca4 100644 --- a/classes/output/renderer.php +++ b/classes/output/renderer.php @@ -187,8 +187,8 @@ private function renderoutage(outage $outage, $buttons) { $outagehtml = html_writer::div( html_writer::tag( 'blockquote', - html_writer::div(html_writer::tag('b', $outage->get_title(), ['data-id' => $outage->id])) . - html_writer::div(html_writer::tag('i', $outage->get_description())) . + html_writer::div(html_writer::tag('b', format_string($outage->get_title()), ['data-id' => $outage->id])) . + html_writer::div(html_writer::tag('i', format_text($outage->get_description(), FORMAT_HTML))) . html_writer::div( html_writer::tag('b', get_string('tableheaderwarnbefore', 'auth_outage') . ': ') . format_time($outage->get_warning_duration()) diff --git a/preview.php b/preview.php index f2c2508c..5627e1f3 100644 --- a/preview.php +++ b/preview.php @@ -31,6 +31,8 @@ // @codingStandardsIgnoreStart require_once(__DIR__.'/../../config.php'); // @codingStandardsIgnoreEnd +require_once($CFG->libdir . '/adminlib.php'); +admin_externalpage_setup('auth_outage_manage'); $id = optional_param('id', null, PARAM_INT); $outage = is_null($id) ? outagedb::get_next_starting() : outagedb::get_by_id($id); if (is_null($outage)) { diff --git a/views/info/content.php b/views/info/content.php index 0f44cce1..fafdf383 100644 --- a/views/info/content.php +++ b/views/info/content.php @@ -39,7 +39,7 @@ stoptime, get_string('datetimeformat', 'auth_outage')); ?> -
get_description(); ?>
+
get_description(), FORMAT_HTML); ?>
Date: Sun, 12 Jul 2026 22:15:41 +0100 Subject: [PATCH 2/9] WR #490867 auth_outage Review changes - sanitise header metadata and file request parameters, restrict served mime types, guard warning bar css output, move svgicons config change out of constructor, add missing form field types --- classes/form/outage/edit.php | 2 ++ classes/local/controllers/infopage.php | 13 ++++++----- .../controllers/maintenance_static_page.php | 3 ++- file.php | 23 ++++++++++++++++--- views/warningbar/warningbar.php | 2 +- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/classes/form/outage/edit.php b/classes/form/outage/edit.php index 20be069d..d54a9df5 100644 --- a/classes/form/outage/edit.php +++ b/classes/form/outage/edit.php @@ -67,6 +67,7 @@ public function definition() { $mform->addHelpButton('title', 'title', 'auth_outage'); $mform->addElement('editor', 'description', get_string('description', 'auth_outage')); + $mform->setType('description[text]', PARAM_RAW); $mform->addHelpButton('description', 'description', 'auth_outage'); $mform->addElement('static', 'usagehints', '', get_string('textplaceholdershint', 'auth_outage')); @@ -79,6 +80,7 @@ public function definition() { get_string('useaccesskey:desc', 'auth_outage'), 0 ); + $mform->setType('useaccesskey', PARAM_BOOL); $mform->addElement('text', 'accesskey', get_string('accesskey', 'auth_outage')); $mform->setType('accesskey', PARAM_TEXT); diff --git a/classes/local/controllers/infopage.php b/classes/local/controllers/infopage.php index acfe1266..7800ecf1 100644 --- a/classes/local/controllers/infopage.php +++ b/classes/local/controllers/infopage.php @@ -47,11 +47,6 @@ class infopage { * @param array|null $params Parameters to use or null to get from Moodle API (request). */ public function __construct(?array $params = null) { - global $CFG; - // Enable SVG support here to make sure all SVG files - // used in the current theme are served properly. - $CFG->svgicons = true; - if (is_null($params)) { $params = [ 'id' => optional_param('id', null, PARAM_INT), @@ -92,6 +87,10 @@ public function get_output() { */ public function output() { global $PAGE, $CFG, $OUTPUT; + // Enable SVG support here to make sure all SVG files + // used in the current theme are served properly. + $previoussvg = $CFG->svgicons ?? null; + $CFG->svgicons = true; if (is_null($this->outage)) { redirect(new moodle_url('/')); @@ -111,7 +110,8 @@ public function output() { // Inject metadata into the header before output. if (!empty($this->outage->metadata)) { - header('X-Outage-Metadata: ' . $this->outage->metadata); + $safemeta = str_replace(["\r", "\n"], '', $this->outage->metadata); + header('X-Outage-Metadata: ' . $safemeta); header('X-Outage-StartTime: ' . $this->outage->starttime); header('X-Outage-EndTime: ' . $this->outage->stoptime); } @@ -127,6 +127,7 @@ public function output() { if (!($CFG->branch == '27' && CLI_SCRIPT)) { echo $OUTPUT->footer(); } + $CFG->svgicons = $previoussvg; } /** diff --git a/classes/local/controllers/maintenance_static_page.php b/classes/local/controllers/maintenance_static_page.php index 4a6896dc..8536771b 100644 --- a/classes/local/controllers/maintenance_static_page.php +++ b/classes/local/controllers/maintenance_static_page.php @@ -51,7 +51,8 @@ public static function create_from_outage($outage) { } else { // Inject metadata into the header before output. if (!empty($outage->metadata)) { - header('X-Outage-Metadata: ' . $outage->metadata); + $safemeta = str_replace(["\r", "\n"], '', $outage->metadata); + header('X-Outage-Metadata: ' . $safemeta); header('X-Outage-StartTime: ' . $outage->starttime); header('X-Outage-EndTime: ' . $outage->stoptime); } diff --git a/file.php b/file.php index 0281e98c..396e5a84 100644 --- a/file.php +++ b/file.php @@ -37,14 +37,31 @@ die('Missing file parameter.'); } -$parts = explode('.', $_GET['file']); +$rawfile = $_GET['file']; +if (!preg_match('/^[a-zA-Z0-9_\-\.\/]+$/', $rawfile)) { + http_response_code(400); + die('Invalid file parameter.'); +} + +$parts = explode('.', $rawfile); if (count($parts) != 2) { http_response_code(400); die('Invalid file requested.'); } -$mime = base64_decode($parts[1]); +$extension = strtolower(pathinfo($parts[0], PATHINFO_EXTENSION)); +$allowedmimes = [ + 'css' => 'text/css', + 'png' => 'image/png', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'gif' => 'image/gif', +]; +if (!array_key_exists($extension, $allowedmimes)) { + http_response_code(400); + die('Unsupported file type.'); +} +$mime = $allowedmimes[$extension]; -// Detect type, we only support css or PNG images. header('Content-Type: ' . $mime); // Use cache. diff --git a/views/warningbar/warningbar.php b/views/warningbar/warningbar.php index c6ea9ea3..edaecc0d 100644 --- a/views/warningbar/warningbar.php +++ b/views/warningbar/warningbar.php @@ -68,7 +68,7 @@ From 1b2979f8e622d736e44351e3e5ff94a844de2555 Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Sun, 12 Jul 2026 22:15:41 +0100 Subject: [PATCH 3/9] WR #490867 auth_outage Review changes - code cleanup: fix exception chaining, remove dead code, code style fixes, initialise variable, add missing PHPDoc, add database indexes --- bootstrap.php | 1 + classes/calendar/calendar.php | 9 +++++--- classes/dml/outagedb.php | 3 ++- classes/local/cli/cli_exception.php | 2 +- classes/local/cli/clibase.php | 1 - classes/local/cli/create.php | 31 ++------------------------ classes/local/cli/finish.php | 1 + classes/local/cli/waitforit.php | 1 + classes/local/controllers/infopage.php | 5 +---- classes/local/outagelib.php | 3 +++ classes/task/update_static_page.php | 5 ++++- db/install.xml | 5 +++++ 12 files changed, 27 insertions(+), 40 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 324f6d6d..13ad68de 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -69,6 +69,7 @@ } // 3) Check for allowed scripts or IPs during outages. +$outageinfo = false; if (!empty($_SERVER['REQUEST_URI'])) { $rooturl = parse_url($CFG->wwwroot); $path = ''; diff --git a/classes/calendar/calendar.php b/classes/calendar/calendar.php index 3cea7a08..941df2cb 100644 --- a/classes/calendar/calendar.php +++ b/classes/calendar/calendar.php @@ -40,16 +40,18 @@ private function __construct() { /** * Create an event on the calendar for this outage. * @param outage $outage Outage to be added to the calendar. + * @return void */ - public static function create(outage $outage) { + public static function create(outage $outage): void { calendar_event::create(self::create_data($outage)); } /** * Updates an event on the calendar based on this outage. * @param outage $outage Outage to be updated in the calendar. + * @return void */ - public static function update(outage $outage) { + public static function update(outage $outage): void { $event = self::load($outage->id); if (is_null($event)) { @@ -63,8 +65,9 @@ public static function update(outage $outage) { /** * Removes an event from the calendar related to this outage. * @param int $outageid Id of outage to be deleted from the calendar. + * @return void */ - public static function delete($outageid) { + public static function delete(int $outageid): void { $event = self::load($outageid); // If not found (was not created before) ignore it. diff --git a/classes/dml/outagedb.php b/classes/dml/outagedb.php index 91d7943f..3e39238a 100644 --- a/classes/dml/outagedb.php +++ b/classes/dml/outagedb.php @@ -48,6 +48,7 @@ private function __construct() { /** * Gets all outage entries. + * @return outage[] */ public static function get_all() { global $DB; @@ -361,7 +362,7 @@ public static function get_ongoing($time = null) { $data = $DB->get_records_select( 'auth_outage', 'starttime <= :datetime1 AND :datetime2 <= stoptime AND finished IS NULL', - ['datetime1' => $time, 'datetime2' => $time, 'datetime3' => $time], + ['datetime1' => $time, 'datetime2' => $time], 'starttime ASC, stoptime DESC, title ASC', '*', 0, diff --git a/classes/local/cli/cli_exception.php b/classes/local/cli/cli_exception.php index ee871d03..4b9769e0 100644 --- a/classes/local/cli/cli_exception.php +++ b/classes/local/cli/cli_exception.php @@ -79,6 +79,6 @@ class cli_exception extends Exception { * @param Exception|null $previous Another exception as reference or null. */ public function __construct($message, $code = 1, ?Exception $previous = null) { - parent::__construct('*ERROR* ' . $message, $code, $previous = null); + parent::__construct('*ERROR* ' . $message, $code, $previous); } } diff --git a/classes/local/cli/clibase.php b/classes/local/cli/clibase.php index a1cbc3a0..b3f4e458 100644 --- a/classes/local/cli/clibase.php +++ b/classes/local/cli/clibase.php @@ -114,7 +114,6 @@ abstract public function execute(); * Change session to admin user. */ protected function become_admin_user() { - global $DB; $user = get_admin(); unset($user->description); unset($user->access); diff --git a/classes/local/cli/create.php b/classes/local/cli/create.php index 3d1588c8..bb4bd505 100644 --- a/classes/local/cli/create.php +++ b/classes/local/cli/create.php @@ -28,8 +28,7 @@ * @copyright 2016 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class create extends clibase -{ +class create extends clibase { /** * @var mixed[] Defaults to use if given option is null. */ @@ -99,6 +98,7 @@ public function set_defaults(array $defaults) { /** * Executes the CLI. + * @throws cli_exception */ public function execute() { // Help always overrides any other parameter. @@ -270,31 +270,4 @@ private function merge_options_check_parameters_string_nonempty($option, $param) return $option; } - /** - * Ensures the given option is or can be converted to a bool. - * @param mixed $option The parameter to check. - * @param string $param Name of that parameter. - * @return bool The converted parameter. - * @throws cli_exception - */ - private function merge_options_check_parameters_bool($option, $param) { - if (is_bool($option)) { - return $option; - } - - if (is_string($option)) { - $option = strtoupper($option); - if (in_array($option, ['0', 'FALSE', 'NO', 'N'])) { - return false; - } - if (in_array($option, ['1', 'TRUE', 'YES', 'Y'])) { - return true; - } - } - - throw new cli_exception( - get_string('clierrorinvalidvaluenotbool', 'auth_outage', ['param' => $param]), - cli_exception::ERROR_PARAMETER_INVALID - ); - } } diff --git a/classes/local/cli/finish.php b/classes/local/cli/finish.php index cc4a9a83..fa7fdee8 100644 --- a/classes/local/cli/finish.php +++ b/classes/local/cli/finish.php @@ -56,6 +56,7 @@ public function generate_shortcuts() { /** * Executes the CLI. + * @throws cli_exception */ public function execute() { // Help always overrides any other parameter. diff --git a/classes/local/cli/waitforit.php b/classes/local/cli/waitforit.php index dd951038..555831d3 100644 --- a/classes/local/cli/waitforit.php +++ b/classes/local/cli/waitforit.php @@ -101,6 +101,7 @@ public function execute() { $outage = $this->get_outage(); while ($sleep = $this->wait_for_outage_to_start($outage)) { + $sleep = max(1, $sleep); if (is_null($this->sleepcallback)) { $this->verbose('Sleeping for ' . $sleep . ' second(s).'); sleep($sleep); diff --git a/classes/local/controllers/infopage.php b/classes/local/controllers/infopage.php index 7800ecf1..b4d9548f 100644 --- a/classes/local/controllers/infopage.php +++ b/classes/local/controllers/infopage.php @@ -123,10 +123,7 @@ public function output() { ]; require($CFG->dirroot . '/auth/outage/views/info/content.php'); - // Moodle 2.7 did not check for CLI mode, which was fixed later. - if (!($CFG->branch == '27' && CLI_SCRIPT)) { - echo $OUTPUT->footer(); - } + echo $OUTPUT->footer(); $CFG->svgicons = $previoussvg; } diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php index 48374d6b..00a7bdfa 100644 --- a/classes/local/outagelib.php +++ b/classes/local/outagelib.php @@ -51,6 +51,7 @@ class outagelib { /** * Fetches page. * @param string $file file to be fetched + * @return array{contents: string|false, mime: string} */ public static function fetch_page($file) { global $CFG; @@ -69,6 +70,7 @@ public static function fetch_page($file) { /** * Resets inject called to allow the code to be regenerated. + * @return void */ public static function reset_injectcalled() { self::$injectcalled = false; @@ -77,6 +79,7 @@ public static function reset_injectcalled() { /** * Given a time, usually now, when is the next outage window? * @param int $time time for next window + * @return int */ public static function get_next_window($time = null) { diff --git a/classes/task/update_static_page.php b/classes/task/update_static_page.php index 2aeff3eb..10163538 100644 --- a/classes/task/update_static_page.php +++ b/classes/task/update_static_page.php @@ -37,7 +37,10 @@ public function get_name() { } /** - * Executes the event. + * Executes the task: regenerates the maintenance static page for the next scheduled outage. + * + * @throws \coding_exception + * @throws \file_exception */ public function execute() { outagelib::prepare_next_outage(); diff --git a/db/install.xml b/db/install.xml index 1dcc2a1e..4f11b419 100644 --- a/db/install.xml +++ b/db/install.xml @@ -21,9 +21,14 @@ + + + + + From a6e465b7a36e9ccadfda6aed9ff59a111bcb28fb Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Sun, 12 Jul 2026 23:45:42 +0100 Subject: [PATCH 4/9] WR #490867 auth_outage Review changes - avoid mutating svgicons before a redirect and update tests for the access key and svgicons changes --- classes/local/controllers/infopage.php | 10 ++++++---- tests/local/controllers/infopage_test.php | 16 ++++++++++++---- tests/local/outagelib_test.php | 8 ++++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/classes/local/controllers/infopage.php b/classes/local/controllers/infopage.php index b4d9548f..0e7cdedd 100644 --- a/classes/local/controllers/infopage.php +++ b/classes/local/controllers/infopage.php @@ -87,10 +87,6 @@ public function get_output() { */ public function output() { global $PAGE, $CFG, $OUTPUT; - // Enable SVG support here to make sure all SVG files - // used in the current theme are served properly. - $previoussvg = $CFG->svgicons ?? null; - $CFG->svgicons = true; if (is_null($this->outage)) { redirect(new moodle_url('/')); @@ -100,6 +96,12 @@ public function output() { if (!$this->static && !has_capability('auth/outage:viewinfo', context_system::instance())) { redirect(new moodle_url('/')); } + + // Enable SVG support here to make sure all SVG files + // used in the current theme are served properly. + $previoussvg = $CFG->svgicons ?? null; + $CFG->svgicons = true; + $PAGE->set_context(context_system::instance()); $PAGE->set_title($this->outage->get_title()); $PAGE->set_heading($this->outage->get_title()); diff --git a/tests/local/controllers/infopage_test.php b/tests/local/controllers/infopage_test.php index badb315c..31e0d2a3 100644 --- a/tests/local/controllers/infopage_test.php +++ b/tests/local/controllers/infopage_test.php @@ -154,15 +154,23 @@ public function test_output_with_forcelogin_if_static(): void { } /** - * Tests the constructor enables SVG support. + * Tests that rendering the page enables SVG support and restores the previous value afterwards. */ - public function test_svgicons_is_true(): void { + public function test_svgicons_is_restored_after_output(): void { global $CFG; $this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance())); + $outage = $this->get_dummy_outage(); $CFG->svgicons = false; - new infopage(); - self::assertTrue($CFG->svgicons); + + $info = new infopage(['outage' => $outage, 'static' => false]); + // Constructing the page should not touch $CFG->svgicons. + self::assertFalse($CFG->svgicons); + + $info->get_output(); + + // Svgicons should be restored to its original value once rendering has finished. + self::assertFalse($CFG->svgicons); } } diff --git a/tests/local/outagelib_test.php b/tests/local/outagelib_test.php index 49e38a6d..c45a95ce 100644 --- a/tests/local/outagelib_test.php +++ b/tests/local/outagelib_test.php @@ -272,7 +272,7 @@ public function test_createmaintenancephpcode(): void { require_once($CFG->dirroot.'/lib/classes/ip_utils.php'); } // Put access key as a cookie if given. This stops the need to put it as a url param on every request. - $urlaccesskey = optional_param('accesskey', null, PARAM_TEXT); + $urlaccesskey = optional_param('accesskey', null, PARAM_ALPHANUM); $isphpunit = defined('PHPUNIT_TEST'); if (!empty($urlaccesskey) && !$isphpunit) { @@ -318,7 +318,7 @@ public function test_createmaintenancephpcode(): void { } if (true && $accesskeyblocked) { - echo ''; + echo ''; } if (!$isphpunit) { @@ -358,7 +358,7 @@ public function test_createmaintenancephpcode_withoutage($configkey): void { require_once($CFG->dirroot.'/lib/classes/ip_utils.php'); } // Put access key as a cookie if given. This stops the need to put it as a url param on every request. - $urlaccesskey = optional_param('accesskey', null, PARAM_TEXT); + $urlaccesskey = optional_param('accesskey', null, PARAM_ALPHANUM); $isphpunit = defined('PHPUNIT_TEST'); if (!empty($urlaccesskey) && !$isphpunit) { @@ -402,7 +402,7 @@ public function test_createmaintenancephpcode_withoutage($configkey): void { } if (true && $accesskeyblocked) { - echo ''; + echo ''; } if (!$isphpunit) { From 789a1c116338d4980cde5ade70f72b52ec477528 Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Mon, 13 Jul 2026 09:47:24 +0100 Subject: [PATCH 5/9] Fix CI codechecker: wrap long line, fix class closing brace placement, update matching test expectations --- classes/local/cli/create.php | 1 - classes/local/outagelib.php | 3 ++- tests/local/outagelib_test.php | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/classes/local/cli/create.php b/classes/local/cli/create.php index bb4bd505..3d14fefd 100644 --- a/classes/local/cli/create.php +++ b/classes/local/cli/create.php @@ -269,5 +269,4 @@ private function merge_options_check_parameters_string_nonempty($option, $param) } return $option; } - } diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php index 00a7bdfa..c7aa4c80 100644 --- a/classes/local/outagelib.php +++ b/classes/local/outagelib.php @@ -331,7 +331,8 @@ public static function create_climaintenancephp_code($starttime, $stoptime, $all } if ({{USEACCESSKEY}} && $accesskeyblocked) { - echo ''; + $safeaccesskey = htmlspecialchars($useraccesskey ?? '', ENT_QUOTES | ENT_HTML5, 'UTF-8'); + echo ''; } if (!$isphpunit) { diff --git a/tests/local/outagelib_test.php b/tests/local/outagelib_test.php index c45a95ce..fabbc291 100644 --- a/tests/local/outagelib_test.php +++ b/tests/local/outagelib_test.php @@ -318,7 +318,8 @@ public function test_createmaintenancephpcode(): void { } if (true && $accesskeyblocked) { - echo ''; + $safeaccesskey = htmlspecialchars($useraccesskey ?? '', ENT_QUOTES | ENT_HTML5, 'UTF-8'); + echo ''; } if (!$isphpunit) { @@ -402,7 +403,8 @@ public function test_createmaintenancephpcode_withoutage($configkey): void { } if (true && $accesskeyblocked) { - echo ''; + $safeaccesskey = htmlspecialchars($useraccesskey ?? '', ENT_QUOTES | ENT_HTML5, 'UTF-8'); + echo ''; } if (!$isphpunit) { From 4976c5c3b652077bc770a13a5acedcb1a0f02432 Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Mon, 13 Jul 2026 09:50:24 +0100 Subject: [PATCH 6/9] Add missing default_metadata key to get_config_defaults() to avoid undefined property when creating a new outage --- classes/local/outagelib.php | 1 + 1 file changed, 1 insertion(+) diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php index c7aa4c80..c13a2163 100644 --- a/classes/local/outagelib.php +++ b/classes/local/outagelib.php @@ -180,6 +180,7 @@ public static function get_config_defaults() { 'default_warning_duration' => (string)(60 * 60), 'default_title' => get_string('defaulttitlevalue', 'auth_outage'), 'default_description' => get_string('defaultdescriptionvalue', 'auth_outage'), + 'default_metadata' => '', 'remove_selectors' => ".usermenu\n.logininfo\n.homelink", ]; } From f785693d06baa9abce38f0e8eb8205452a96ccbc Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Mon, 13 Jul 2026 09:50:31 +0100 Subject: [PATCH 7/9] Set outage metadata headers before echoing injected warning-bar code to avoid headers-already-sent --- classes/local/controllers/infopage.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/classes/local/controllers/infopage.php b/classes/local/controllers/infopage.php index 0e7cdedd..3f64ff44 100644 --- a/classes/local/controllers/infopage.php +++ b/classes/local/controllers/infopage.php @@ -107,10 +107,8 @@ public function output() { $PAGE->set_heading($this->outage->get_title()); $PAGE->set_url(new moodle_url('/auth/outage/info.php')); - // No hooks injecting into this page, do it manually. - echo outagelib::get_inject_code(); - - // Inject metadata into the header before output. + // Inject metadata into the header before any output starts, otherwise header() will + // fail once outagelib::get_inject_code() below has echoed anything. if (!empty($this->outage->metadata)) { $safemeta = str_replace(["\r", "\n"], '', $this->outage->metadata); header('X-Outage-Metadata: ' . $safemeta); @@ -118,6 +116,9 @@ public function output() { header('X-Outage-EndTime: ' . $this->outage->stoptime); } + // No hooks injecting into this page, do it manually. + echo outagelib::get_inject_code(); + echo $OUTPUT->header(); $viewbag = [ 'admin' => is_siteadmin(), From 2f5bb06e3ce702ac8536f6348d07a92cfecb3565 Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Mon, 13 Jul 2026 10:03:43 +0100 Subject: [PATCH 8/9] Bump plugin version --- version.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.php b/version.php index 3e06da07..0083dd3b 100644 --- a/version.php +++ b/version.php @@ -28,8 +28,8 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = "auth_outage"; -$plugin->version = 2026011304; // The current plugin version (Date: YYYYMMDDXX). -$plugin->release = 2026011304; // Human-readable release information. +$plugin->version = 2026071300; // The current plugin version (Date: YYYYMMDDXX). +$plugin->release = 2026071300; // Human-readable release information. $plugin->requires = 2025100600; // Moodle 5.1. $plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments! $plugin->supported = [501, 501]; // A range of branch numbers of supported moodle versions. From 6ccefa9eda466402ae0d2627e9b37932511770b1 Mon Sep 17 00:00:00 2001 From: Waleed Hassan Date: Mon, 13 Jul 2026 13:23:50 +0100 Subject: [PATCH 9/9] Reduce version bump to +1 to satisfy CI's version-bump-size check --- version.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.php b/version.php index 0083dd3b..cfb30fb5 100644 --- a/version.php +++ b/version.php @@ -28,8 +28,8 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = "auth_outage"; -$plugin->version = 2026071300; // The current plugin version (Date: YYYYMMDDXX). -$plugin->release = 2026071300; // Human-readable release information. +$plugin->version = 2026011305; // The current plugin version (Date: YYYYMMDDXX). +$plugin->release = 2026011305; // Human-readable release information. $plugin->requires = 2025100600; // Moodle 5.1. $plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments! $plugin->supported = [501, 501]; // A range of branch numbers of supported moodle versions.