Compare commits

..

28 Commits

Author SHA1 Message Date
Tomo Tsuyuki 9bab491666 Revert "Fix URL is blocked message when not behind a proxy/load balancer"
This reverts commit 51db933862.
2026-06-18 12:00:26 +10:00
Tomo Tsuyuki 20fef09b03 issue #405: fix unit test failure 2026-06-18 10:01:42 +10:00
Benjamin Walker f2b7d1c7dd Display creation info on manage outage page 2026-01-25 13:41:57 +11:00
abhinavgandham f0f3112ea1 Fixed PHPdoc. 2026-01-22 22:15:35 +11:00
abhinavgandham 0ac6b14ed1 Fixed examples table syntax in default settings behat file. 2026-01-22 22:15:35 +11:00
abhinavgandham b2c3fbd7b2 Removed more tests that are not needed. 2026-01-22 22:15:35 +11:00
abhinavgandham 840d2c39d9 Removed maintanance mode tests. 2026-01-22 22:15:35 +11:00
abhinavgandham ddd56cd93f Removed maintenance later code in outagelib so that site does not go into hard cli mode when outage starts. 2026-01-22 22:15:35 +11:00
abhinavgandham 7d779f8fe9 Fixed PHPUnit test errors and failures. 2026-01-22 22:15:35 +11:00
abhinavgandham ac29a02402 Modified unit tests to remove autostart, and quickstart guide and readme. 2026-01-22 22:15:35 +11:00
abhinavgandham ffda33329c Codechecker fixes and removed other comments. 2026-01-22 22:15:35 +11:00
abhinavgandham 0bff6f5145 Issue #390: Reverted new 'Force off' option and dropdown conversion. 2026-01-22 22:15:35 +11:00
Matthew Hilton bffd5f39f9 Merge pull request #388 from catalyst/issue-387
Issue 387: Add metadata header to outage pages
2026-01-19 12:47:02 +10:00
Peter Burnett fcb2a681e7 Issue 387: Add metadata header to outage pages 2026-01-19 12:19:21 +10:00
abhinavgandham 59a62c4aa4 micro-bumped version in version.php. 2026-01-16 12:52:05 +11:00
abhinavgandham 073a682b01 CI codesniffer fixes. 2026-01-16 12:52:05 +11:00
abhinavgandham da18e31dab Fixed default parameter in configselect and updated 'Force off' lang string. 2026-01-16 12:52:05 +11:00
abhinavgandham 1ef47a6233 Included logic for 'Force off' setting. 2026-01-16 12:52:05 +11:00
abhinavgandham 551a97142c Issue #390: Changed outage auto-start default parameter from checkbox to dropdown with option to fully disable. 2026-01-16 12:52:05 +11:00
Brendan Heywood ceee32d889 Merge pull request #397 from catalyst/MOODLE_39_branchtable_unsupportedversion_fix
#Issue 390: Fixed branch table in readme and added version 501 as incompatible.
2026-01-13 16:51:12 +11:00
abhinavgandham 149223d10f #Issue 390: Fixed branch table in readme and added version 501 as incompatible. 2026-01-13 14:51:54 +10:00
Brendan Heywood 42b6ec3c87 Fix code standards 2026-01-13 14:50:05 +11:00
Brendan Heywood 6792b03ab0 Merge pull request #394 from catalyst/MOODLE_39_codecleanup
Issue #390: Code cleanup to fix code standards codesniffer errors.
2026-01-12 18:34:15 +11:00
abhinavgandham 7f968b2365 Issue #390: Code cleanup to fix code standards codesniffer errors. 2026-01-12 17:18:47 +10:00
Guillaume 42dbec5b4d Fix #314: Switch optional_param starttime to optional_param_array (#383)
* Fix #314: Switch optional_param starttime to optional_param_array

* convert default startime to timestamp

* fix error debug warning
2025-12-03 17:39:53 +11:00
Brendan Heywood 5d064a0bec Merge pull request #353 from catalyst/fix-define
Fix bootstrap define #352
2025-11-29 16:46:21 +11:00
Brendan Heywood d16ae47a5f Fix bootstrap define #352 2025-11-29 15:51:50 +11:00
Brendan Heywood 1e3572be9f Improve comments when blocked 2025-10-22 16:09:21 +11:00
15 changed files with 35 additions and 260 deletions
+4 -5
View File
@@ -1,4 +1,4 @@
[![ci](https://github.com/catalyst/moodle-auth_outage/actions/workflows/ci.yml/badge.svg?branch=MOODLE_501_STABLE)](https://github.com/catalyst/moodle-auth_outage/actions/workflows/ci.yml?branch=MOODLE_501_STABLE)
[![ci](https://github.com/catalyst/moodle-auth_outage/actions/workflows/ci.yml/badge.svg?branch=MOODLE_39_STABLE)](https://github.com/catalyst/moodle-auth_outage/actions/workflows/ci.yml?branch=MOODLE_39_STABLE)
# Moodle Outage manager plugin
- [Moodle Outage manager plugin](#moodle-outage-manager-plugin)
@@ -42,10 +42,9 @@ need to manually add one extra plugin, please check:
Moodle supported branches
--------
| Version | Branch | PHP |
|----------------|---------------------|------|
| Moodle 5.1 | MOODLE_501_STABLE | 8.2 |
| Moodle 3.9-5.0 | MOODLE_39_STABLE | 7.2+ |
| Version | Branch | PHP |
|-------------|-------------------|------|
| Moodle 3.9+ | MOODLE_39_STABLE | 7.2+ |
Totara supported branches
--------
-79
View File
@@ -84,82 +84,6 @@ class outagedb {
return new outage($outage);
}
/**
* Also sends all admins the event as a message
*
* @param $outage
* @param $event
*/
private static function notify($outage, $event) {
$admins = get_admins();
foreach ($admins as $admin) {
self::notify_user($outage, $event, $admin);
}
}
/**
* Send outage info to one user
*
* @param $outage outage
* @param $event event
* @param $to user object
*/
private static function notify_user($outage, $event, $to) {
global $SITE, $CFG;
$from = \core_user::get_user($event->userid);
if (!$from) {
return;
}
$fields = [
'site_shortname' => $SITE->shortname,
'site_fullname' => $SITE->fullname,
'site_wwwroot' => $CFG->wwwroot,
'outage_id' => $outage->id,
'outage_title' => $outage->get_title(),
'outage_desc' => clean_text($outage->get_description(), FORMAT_HTML),
'outage_start' => userdate($outage->starttime, get_string('datetimeformat', 'auth_outage')),
'outage_stop' => userdate($outage->stoptime, get_string('datetimeformat', 'auth_outage')),
'outage_duration' => format_time($outage->get_duration_planned()),
'event_name' => $event->get_name(),
'event_desc' => $event->get_description(),
'event_link' => $event->get_url()->out(),
'from_name' => fullname($from),
'to_name' => fullname($to),
'prefs_link' => (new \moodle_url('/message/notificationpreferences.php'))->out(),
];
$message = new \core\message\message();
$message->component = 'auth_outage';
$message->name = 'updatenotify';
$message->userto = $to;
$message->subject = get_string('messagesubject', 'auth_outage', $fields);
$message->fullmessage = get_string('messagetext', 'auth_outage', $fields);
$message->fullmessagehtml = get_string('messagehtml', 'auth_outage', $fields);
$message->fullmessageformat = FORMAT_HTML;
$threadid = generate_email_messageid('outage' . $outage->id);
$message->userfrom = $from;
$message->userfrom->customheaders = [
"In-Reply-To: $threadid",
"References: $threadid",
"Thread-Topic: " . $message->subject,
"Thread-Index: $threadid",
];
$message->notification = 1;
message_send($message);
}
/**
* Saves an outage to the database.
*
@@ -190,7 +114,6 @@ class outagedb {
]);
$event->add_record_snapshot('auth_outage', (object)(array) $outage);
$event->trigger();
self::notify($outage, $event);
// Create calendar entry.
calendar::create($outage);
@@ -204,7 +127,6 @@ class outagedb {
$event->add_record_snapshot('auth_outage', (object)(array) $outage);
$event->trigger();
self::notify($outage, $event);
// Remove the createdby field so it does not get updated.
unset($outage->createdby);
@@ -248,7 +170,6 @@ class outagedb {
$event->add_record_snapshot('auth_outage', $previous);
$event->trigger();
self::notify($outage, $event);
// Delete it and remove from calendar.
$DB->delete_records('auth_outage', ['id' => $id]);
+1 -11
View File
@@ -28,23 +28,13 @@ use moodle_url;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class outage_created extends base {
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventoutagecreated', 'auth_outage');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with the id '{$this->userid}' scheduled outage {$this->other['id']} '{$this->other['title']}'";
return "The user with the id '{$this->userid}' created outage {$this->other['id']} '{$this->other['title']}'";
}
/**
-10
View File
@@ -28,16 +28,6 @@ use moodle_url;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class outage_deleted extends base {
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventoutagedeleted', 'auth_outage');
}
/**
* Returns non-localised event description with id's for admin use only.
*
-10
View File
@@ -28,16 +28,6 @@ use moodle_url;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class outage_updated extends base {
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventoutageupdated', 'auth_outage');
}
/**
* Returns non-localised event description with id's for admin use only.
*
+5 -13
View File
@@ -56,7 +56,7 @@ class outagelib {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$curl = new curl(['ignoresecurity' => true]);
$curl = new curl();
$contents = $curl->get($file);
$info = $curl->get_info();
if (!empty($info['content_type'])) {
@@ -253,7 +253,7 @@ class outagelib {
* @param int $stoptime Outage stop time.
* @param string $allowedips List of IPs allowed.
* @param string|null $accesskey access key, or null if no access key set.
* @param string|null $metadata Metadata to set in headers, or null if none.
* @param string|null $metadata metadata to be added to the outage headers, or null if none.
*
* @return string
* @throws invalid_parameter_exception
@@ -345,17 +345,9 @@ EOT;
$search = ['{{STARTTIME}}', '{{STOPTIME}}', '{{USEALLOWEDIPS}}', '{{ALLOWEDIPS}}', '{{USEACCESSKEY}}', '{{ACCESSKEY}}',
'{{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),
var_export($metadata, true)];
$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), var_export($metadata, true)];
return str_replace($search, $replace, $code);
}
-9
View File
@@ -34,13 +34,4 @@ $capabilities = [
'user' => CAP_ALLOW,
],
],
'auth/outage:updatenotify' => [
'captype' => 'write',
'riskbitmask' => RISK_XSS,
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => [
'manager' => CAP_ALLOW,
]
],
];
-32
View File
@@ -1,32 +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/>.
/**
* Defines message providers for outage
*
* @package auth_outage
* @copyright 2020 Brendan Heywood <brendan@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$messageproviders = [
'updatenotify' => [
'capability' => 'auth/outage:updatenotify',
]
];
+4 -4
View File
@@ -61,7 +61,7 @@ function xmldb_auth_outage_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2024081900, 'auth', 'outage');
}
if ($oldversion < 2026011301) {
if ($oldversion < 2024081901) {
// 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');
@@ -72,10 +72,10 @@ function xmldb_auth_outage_upgrade($oldversion) {
}
// Outage savepoint reached.
upgrade_plugin_savepoint(true, 2026011301, 'auth', 'outage');
upgrade_plugin_savepoint(true, 2024081901, 'auth', 'outage');
}
if ($oldversion < 2026011302) {
if ($oldversion < 2024081902) {
// Getting the table auth_outage and target field to remove from the table.
$table = new xmldb_table('auth_outage');
$field = new xmldb_field('autostart');
@@ -89,7 +89,7 @@ function xmldb_auth_outage_upgrade($oldversion) {
unset_config('default_autostart', 'auth_outage');
// Outage savepoint reached.
upgrade_plugin_savepoint(true, 2026011302, 'auth', 'outage');
upgrade_plugin_savepoint(true, 2024081902, 'auth', 'outage');
}
return true;
+1
View File
@@ -28,6 +28,7 @@ use auth_outage\form\outage\edit;
use auth_outage\local\outage;
use auth_outage\local\outagelib;
require_once(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->libdir . '/formslib.php');
+6 -44
View File
@@ -100,9 +100,6 @@ $string['defaultwarningduration'] = 'Warning duration';
$string['defaultwarningdurationdescription'] = 'Default warning time (in minutes) for outages.';
$string['description'] = 'Public Description';
$string['description_help'] = 'A full description of the outage, publicly visible by all users.';
$string['eventoutagecreated'] = 'Outage scheduled';
$string['eventoutagedeleted'] = 'Outage cancelled';
$string['eventoutageupdated'] = 'Outage updated';
$string['finish'] = 'Finish';
$string['info15secondsbefore'] = '15 seconds before';
$string['infoendofoutage'] = 'end of outage';
@@ -124,48 +121,9 @@ $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['messageprovider:updatenotify'] = 'Changes to planned outages';
$string['messagesubject'] = '[{$a->site_shortname}] {$a->event_name} #{$a->outage_id}: {$a->outage_start}';
$string['messagetext'] = '{$a->event_name}
{$a->site_fullname} ({$a->site_wwwroot})
{$a->event_link}
ID: {$a->outage_id}
NAME: {$a->outage_title}
START: {$a->outage_start}
DURATION: {$a->outage_duration}
DESCRIPTION:
{$a->outage_desc}
--
To unsubscribe visit:
{$a->prefs_link}';
$string['messagehtml'] = '
<h3>{$a->event_name}</h3>
<p>{$a->site_fullname} (<a href="{$a->site_wwwroot}">{$a->site_wwwroot}</a>)</p>
<p><a href="{$a->event_link}">{$a->event_link}</a></p>
<h4>Name:</h4>
<p>{$a->outage_title}</p>
<h4>Start:</h4>
<p>{$a->outage_start}</p>
<h4>Duration:</h4>
<p>{$a->outage_duration}</p>
<h4>Description:</h4>
<p>{$a->outage_desc}</p>
<hr>
<p>To unsubscribe visit:<br>
<a href="{$a->prefs_link}">{$a->prefs_link}</a></p>
';
$string['na'] = 'n/a';
$string['notfound'] = 'No outages found.';
$string['outage:updatenotify'] = 'Receive outage update notifications';
$string['outage:updatenotify'] = '';
$string['outage:viewinfo'] = 'View outage info';
$string['outageclone'] = 'Clone outage';
$string['outageclonecrumb'] = 'Clone';
@@ -183,7 +141,6 @@ $string['outagefinishwarning'] = 'You are about to mark this outage as finished.
$string['outageslistfuture'] = 'Planned outages';
$string['outageslistpast'] = 'Outage history';
$string['pluginname'] = 'Outage manager';
$string["privacy:no_data_reason"] = "The Outage authentication plugin does not store any personal data.";
$string['removeselectors'] = 'Remove selectors';
$string['removeselectorsdescription'] = 'CSS selectors to remove when rendering a static themed maintenance page. One selector per line.';
$string['settingssectiondefaults'] = 'Default Outage Parameters';
@@ -215,3 +172,8 @@ $string['warningduration'] = 'Warning duration';
$string['warningduration_help'] = 'How long before the start of the outage should the warning be displayed.';
$string['warningdurationerrorinvalid'] = 'Warning duration must be positive.';
$string['warningreenablemaintenancemode'] = 'Please note that saving this outage will re-enable maintenance mode.<br />Untick "Auto start maintenance mode" if you want to prevent this.';
/*
* Privacy provider (GDPR)
*/
$string["privacy:no_data_reason"] = "The Outage authentication plugin does not store any personal data.";
+2 -2
View File
@@ -158,7 +158,7 @@ final class waitforit_test extends cli_testcase {
/**
* Tests the countdown.
*/
public function test_countdown(): void {
public function test_countdown() {
self::setAdminUser();
$now = time();
outagedb::save(new outage([
@@ -186,7 +186,7 @@ final class waitforit_test extends cli_testcase {
/**
* Tests if the outage changed while waiting.
*/
public function test_outagechanged(): void {
public function test_outagechanged() {
self::setAdminUser();
$now = time();
$id = outagedb::save(new outage([
@@ -431,39 +431,6 @@ final class maintenance_static_page_test extends \auth_outage\base_testcase {
maintenance_static_page_io::file_get_data(200);
}
/**
* Test file_get_data with curlsecurityblockedhosts.
* We will use an external URL to test passing ignoresecurity inside of file_get_data works,
* ideally in real code we should only be calling file_get_data with internal URLs.
*/
public function test_file_get_data_curlsecurityblockedhosts(): void {
global $CFG, $USER;
$testhtml = $this->getExternalTestFileUrl('/test.html');
$url = new \moodle_url($testhtml);
$host = $url->get_host();
set_config('curlsecurityblockedhosts', $host); // Blocks $host.
// Test a regular curl with the default security enabled does in fact get blocked.
$curl = new \curl();
$contents = $curl->get($testhtml);
$expected = $curl->get_security()->get_blocked_url_string();
self::assertSame($expected, $contents);
self::assertSame(0, $curl->get_errno());
if ($CFG->branch >= 403) {
self::assertDebuggingCalled(
"Blocked $testhtml: The URL is blocked. [user {$USER->id}]",
DEBUG_NONE
);
}
// Test file_get_data does return the page and isn't blocked by security.
$found = maintenance_static_page_io::file_get_data($url->out());
$expected = '47250a973d1b88d9445f94db4ef2c97a';
self::assertSame($expected, md5($found['contents']));
self::assertSame('text/html', $found['mime']);
}
/**
* Test remove css selector.
*/
@@ -583,7 +550,7 @@ final class maintenance_static_page_test extends \auth_outage\base_testcase {
/**
* Test meta refresh maximum 5 minutes.
*/
public function test_meta_refresh_maximum_5seconds(): void {
public function test_meta_refresh_maximum_5seconds() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n" .
'<html><head><title>Title</title></head>' .
@@ -593,6 +560,7 @@ final class maintenance_static_page_test extends \auth_outage\base_testcase {
$page->set_max_refresh_time(5);
$page->generate();
$generated = trim(file_get_contents($page->get_io()->get_template_file()));
return $generated;
self::assertStringContainsString('<meta http-equiv="refresh" content="5">', $generated);
}
+6 -4
View File
@@ -28,7 +28,9 @@
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->requires = 2025100600; // Moodle 5.1.
$plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments!
$plugin->version = 2024081905; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2024081905; // Human-readable release information.
$plugin->requires = 2017111309; // 2017111309 = T13, but this really requires 3.9 and higher.
$plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments!
$plugin->supported = [39, 405]; // A range of branch numbers of supported moodle versions.
$plugin->incompatible = 501;
+4 -3
View File
@@ -44,13 +44,14 @@ defined('MOODLE_INTERNAL') || die();
<?php if ($viewbag['admin']) : ?>
<?php
$adminlinks = [];
$params = [
foreach (
[
'startofwarning' => -$viewbag['outage']->get_warning_duration(),
'15secondsbefore' => -15,
'start' => 0,
'endofoutage' => $viewbag['outage']->get_duration_planned() - 1,
];
foreach ($params as $title => $delta) {
] as $title => $delta
) {
$adminlinks[] = html_writer::link(
new moodle_url(
'/auth/outage/info.php',