Issue 387: Add metadata header to outage pages

This commit is contained in:
Peter Burnett
2025-12-31 10:31:30 +10:00
parent b63af0465e
commit 425ef963fb
12 changed files with 79 additions and 9 deletions

View File

@@ -90,6 +90,10 @@ class edit extends moodleform {
$mform->disabledIf('accesskey', 'useaccesskey');
$mform->addHelpButton('accesskey', 'accesskey', 'auth_outage');
$mform->addElement('text', 'metadata', get_string('metadata', 'auth_outage'));
$mform->setType('metadata', PARAM_TEXT);
$mform->addHelpButton('metadata', 'metadata', 'auth_outage');
$this->add_action_buttons();
}
@@ -144,6 +148,7 @@ class edit extends moodleform {
'title' => $data->title,
'description' => $data->description['text'],
'accesskey' => $data->useaccesskey ? $data->accesskey : null,
'metadata' => $data->metadata ?? null,
];
return new outage($outagedata);
}
@@ -169,6 +174,7 @@ class edit extends moodleform {
'description' => ['text' => $outage->description, 'format' => '1'],
'accesskey' => $outage->accesskey,
'useaccesskey' => !empty($outage->accesskey),
'metadata' => $outage->metadata,
]);
// If the default_autostart is configured in config, then force autostart to be the default value.

View File

@@ -109,6 +109,13 @@ class infopage {
// No hooks injecting into this page, do it manually.
echo outagelib::get_inject_code();
// Inject metadata into the header before output.
if (!empty($this->outage->metadata)) {
header('X-Outage-Metadata: ' . $this->outage->metadata);
header('X-Outage-StartTime: ' . $this->outage->starttime);
header('X-Outage-EndTime: ' . $this->outage->stoptime);
}
echo $OUTPUT->header();
$viewbag = [
'admin' => is_siteadmin(),

View File

@@ -49,6 +49,12 @@ class maintenance_static_page {
} else if (PHPUNIT_TEST || defined('BEHAT_SITE_RUNNING')) {
$html = '<html></html>';
} else {
// Inject metadata into the header before output.
if (!empty($outage->metadata)) {
header('X-Outage-Metadata: ' . $outage->metadata);
header('X-Outage-StartTime: ' . $outage->starttime);
header('X-Outage-EndTime: ' . $outage->stoptime);
}
$data = maintenance_static_page_io::file_get_data(
$CFG->wwwroot . '/auth/outage/info.php?auth_outage_hide_warning=1&static=1&id=' . $outage->id
);

View File

@@ -113,6 +113,11 @@ class outage {
*/
public $accesskey = null;
/**
* @var string|null metadata string, or null if not enabled.
*/
public $metadata = null;
/**
* outage constructor.
* @param stdClass|array|null $data The data for the outage.

View File

@@ -283,7 +283,7 @@ class outagelib {
* @return string
* @throws invalid_parameter_exception
*/
public static function create_climaintenancephp_code($starttime, $stoptime, $allowedips, $accesskey = null) {
public static function create_climaintenancephp_code($starttime, $stoptime, $allowedips, $accesskey = null, $metadata = null) {
global $CFG;
if (!is_int($starttime) || !is_int($stoptime)) {
throw new invalid_parameter_exception('Make sure $startime and $stoptime are integers.');
@@ -337,6 +337,11 @@ if ((time() >= {{STARTTIME}}) && (time() < {{STOPTIME}})) {
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Accept-Ranges: none');
header('X-Moodle-Maintenance: manager');
if (!empty({{METADATA}})) {
header('X-Outage-Metadata: ' . {{METADATA}});
}
header('X-Outage-StartTime: ' . '{{STARTTIME}}');
header('X-Outage-EndTime: ' . '{{STOPTIME}}');
}
if (!$isphpunit && ((defined('AJAX_SCRIPT') && AJAX_SCRIPT) || (defined('WS_SERVER') && WS_SERVER))) {
@@ -363,10 +368,10 @@ if ((time() >= {{STARTTIME}}) && (time() < {{STOPTIME}})) {
}
EOT;
$search = ['{{STARTTIME}}', '{{STOPTIME}}', '{{USEALLOWEDIPS}}', '{{ALLOWEDIPS}}', '{{USEACCESSKEY}}', '{{ACCESSKEY}}',
'{{YOURIP}}', '{{COOKIESECURE}}', '{{COOKIEHTTPONLY}}'];
'{{YOURIP}}', '{{COOKIESECURE}}', '{{COOKIEHTTPONLY}}', '{{METADATA}}'];
// Note that var_export is required because (string) false == '', not 'false'.
$replace = [$starttime, $stoptime, var_export(!empty($allowedips), true), $allowedips, var_export(!empty($accesskey), true),
$accesskey, getremoteaddr('n/a'), var_export($cookiesecure, true), var_export($cookiehttponly, true)];
$accesskey, getremoteaddr('n/a'), var_export($cookiesecure, true), var_export($cookiehttponly, true), var_export($metadata, true)];
return str_replace($search, $replace, $code);
}
@@ -389,6 +394,7 @@ EOT;
$config = self::get_config();
$allowedips = trim($config->allowedips);
$accesskey = $outage->accesskey ?? null;
$metadata = $outage->metadata ?? null;
// If no outage, or allowed ips is null and access key is null (i.e. no blocking required).
if (is_null($outage) || ($allowedips == '' && empty($accesskey))) {
@@ -396,7 +402,7 @@ EOT;
unlink($file);
}
} else {
$code = self::create_climaintenancephp_code($outage->starttime, $outage->stoptime, $allowedips, $accesskey);
$code = self::create_climaintenancephp_code($outage->starttime, $outage->stoptime, $allowedips, $accesskey, $metadata);
$dir = dirname($file);
if (!file_exists($dir) || !is_dir($dir)) {

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="auth/outage/db" VERSION="20160922" COMMENT="XMLDB file for Moodle auth/outage"
<XMLDB PATH="auth/outage/db" VERSION="20260114" COMMENT="XMLDB file for Moodle auth/outage"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@@ -18,6 +18,7 @@
<FIELD NAME="lastmodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="When was this entry last modified."/>
<FIELD NAME="finished" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Timestamp of when the outage really finished."/>
<FIELD NAME="accesskey" TYPE="char" LENGTH="16" NOTNULL="false" SEQUENCE="false" COMMENT="Unique key used to access during outage"/>
<FIELD NAME="metadata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="metadata to be exposed in outage page headers"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

View File

@@ -61,5 +61,20 @@ function xmldb_auth_outage_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2024081900, 'auth', 'outage');
}
if ($oldversion < 2026011301) {
// Define field metadata to be added to auth_outage.
$table = new xmldb_table('auth_outage');
$field = new xmldb_field('metadata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'accesskey');
// Conditionally launch add field metadata.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Outage savepoint reached.
upgrade_plugin_savepoint(true, 2026011301, 'auth', 'outage');
}
return true;
}

View File

@@ -27,7 +27,6 @@ use auth_outage\dml\outagedb;
use auth_outage\form\outage\edit;
use auth_outage\local\outage;
use auth_outage\local\outagelib;
use auth_outage\output\renderer;
require_once(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/adminlib.php');
@@ -90,6 +89,7 @@ if ($clone) {
'warntime' => $time - $config->default_warning_duration,
'title' => $config->default_title,
'description' => $config->default_description,
'metadata' => $config->default_metadata,
]);
$action = 'outagecreate';
}

View File

@@ -88,6 +88,8 @@ $string['defaultdescriptiondescription'] = 'Default warning message for outages.
$string['defaultdescriptionvalue'] = 'There is maintenance scheduled from {{start}} to {{stop}} and our system will not be available during that time.';
$string['defaultlayoutcss'] = 'Layout CSS';
$string['defaultlayoutcssdescription'] = 'This CSS code can be used to override the Outage Warning Bar CSS.';
$string['defaultmetadata'] = 'Default metadata';
$string['defaultmetadatadescription'] = 'The default metadata to include in the outage settings, to be used as a template for new outages. E.g. JIRA-{ticketno}.';
$string['defaultoutageautostart'] = 'Outage auto start';
$string['defaultoutageautostartdescription'] = 'If the outage should automatically trigger maintenance mode once it starts, locking down the whole site.';
$string['defaultoutageduration'] = 'Outage duration';
@@ -120,6 +122,8 @@ $string['messageoutagebackonline'] = 'We are back online!';
$string['messageoutagebackonlinedescription'] = 'You may resume browsing safely.';
$string['messageoutageongoing'] = 'Back online at {$a->stop}.';
$string['messageoutagewarning'] = 'Shutting down in {{countdown}}';
$string['metadata'] = 'Outage metadata';
$string['metadata_help'] = 'Data here will be output in the outage page as a meta tag in the header of the outage page.';
$string['na'] = 'n/a';
$string['notfound'] = 'No outages found.';
$string['outage:updatenotify'] = '';

View File

@@ -83,6 +83,16 @@ if ($hassiteconfig) {
$defaults['default_title'],
PARAM_TEXT
));
$settings->add(
new admin_setting_configtext(
'auth_outage/default_metadata',
get_string('defaultmetadata', 'auth_outage'),
get_string('defaultmetadatadescription', 'auth_outage'),
'',
PARAM_TEXT
)
);
$settings->add(new admin_setting_configtextarea(
'auth_outage/default_description',
get_string('defaultdescription', 'auth_outage'),

View File

@@ -352,6 +352,11 @@ e.e.e.e/20');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Accept-Ranges: none');
header('X-Moodle-Maintenance: manager');
if (!empty('testmeta')) {
header('X-Outage-Metadata: ' . 'testmeta');
}
header('X-Outage-StartTime: ' . '123');
header('X-Outage-EndTime: ' . '456');
}
if (!$isphpunit && ((defined('AJAX_SCRIPT') && AJAX_SCRIPT) || (defined('WS_SERVER') && WS_SERVER))) {
@@ -377,7 +382,7 @@ e.e.e.e/20');
}
}
EOT;
$found = outagelib::create_climaintenancephp_code(123, 456, "hey'\"you\na.b.c.d\ne.e.e.e/20", '12345');
$found = outagelib::create_climaintenancephp_code(123, 456, "hey'\"you\na.b.c.d\ne.e.e.e/20", '12345', 'testmeta');
self::assertSame($expected, $found);
}
@@ -431,6 +436,11 @@ if ((time() >= 123) && (time() < 456)) {
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Accept-Ranges: none');
header('X-Moodle-Maintenance: manager');
if (!empty(NULL)) {
header('X-Outage-Metadata: ' . NULL);
}
header('X-Outage-StartTime: ' . '123');
header('X-Outage-EndTime: ' . '456');
}
if (!$isphpunit && ((defined('AJAX_SCRIPT') && AJAX_SCRIPT) || (defined('WS_SERVER') && WS_SERVER))) {

View File

@@ -28,8 +28,8 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = "auth_outage";
$plugin->version = 2026011300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2026011300; // Human-readable release information.
$plugin->version = 2026011301; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2026011301; // 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.