diff --git a/README.md b/README.md
index 4687aa0..9463dae 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,17 @@ https://github.com/catalyst/moodle-auth_outage/issues
3. Go to `Dashboard ► Site administration ► Plugins ► Authentication ► Manage authentication`,
enable the `Outage manager` plugin and place it on the top.
+4. If you need to use the IP Blocking, please add the following lines into your `config.php`
+after your `$CFG->dataroot` is set:
+
+```
+if (file_exists("$CFG->dataroot/climaintenance.php")) {
+ $CFG->dirroot = __DIR__;
+ require("$CFG->dataroot/climaintenance.php");
+} else {
+ $CFG->auth_outage_check = 1;
+}
+```
How to use
----------
diff --git a/classes/dml/outagedb.php b/classes/dml/outagedb.php
index f785558..cad6f73 100644
--- a/classes/dml/outagedb.php
+++ b/classes/dml/outagedb.php
@@ -135,7 +135,7 @@ class outagedb {
}
// Trigger outages modified events.
- outagelib::outages_modified();
+ outagelib::prepare_next_outage();
// All done, return the id.
return $outage->id;
@@ -165,7 +165,7 @@ class outagedb {
calendar::delete($id);
// Trigger events.
- outagelib::outages_modified();
+ outagelib::prepare_next_outage();
}
/**
@@ -358,4 +358,35 @@ class outagedb {
// Allowing multiple records still raises an internal error.
return (count($data) == 0) ? null : new outage(array_shift($data));
}
+
+ /**
+ * Gets an ongoing outage (between start and stop time but not finished).
+ * @param int|null $time Timestamp considered to check for outages, null for current date/time.
+ * @return outage|null The outage or null if no active outages were found.
+ * @throws coding_exception
+ */
+ public static function get_ongoing($time = null) {
+ global $DB;
+
+ if ($time === null) {
+ $time = time();
+ }
+ if (!is_int($time) || ($time <= 0)) {
+ throw new coding_exception('$time must be null or a positive int.', $time);
+ }
+
+ $data = $DB->get_records_select(
+ 'auth_outage',
+ 'starttime <= :datetime1 AND :datetime2 <= stoptime AND finished IS NULL',
+ ['datetime1' => $time, 'datetime2' => $time, 'datetime3' => $time],
+ 'starttime ASC, stoptime DESC, title ASC',
+ '*',
+ 0,
+ 1
+ );
+
+ // Not using $DB->get_record_select instead because there is no 'limit' parameter.
+ // Allowing multiple records still raises an internal error.
+ return (count($data) == 0) ? null : new outage(array_shift($data));
+ }
}
diff --git a/classes/local/controllers/infopage.php b/classes/local/controllers/infopage.php
index d7c65cc..5b30c98 100644
--- a/classes/local/controllers/infopage.php
+++ b/classes/local/controllers/infopage.php
@@ -124,26 +124,25 @@ class infopage {
/**
* Updates the static info page by (re)creating or deleting it as needed.
+ * @param outage|null $outage Outage or null if no scheduled outage.
* @param string|null $file File to update. Null to use default.
* @throws coding_exception
* @throws file_exception
*/
- public static function update_static_page($file = null) {
+ public static function update_static_page($outage, $file = null) {
if (is_null($file)) {
$file = self::get_defaulttemplatefile();
}
if (!is_string($file)) {
throw new coding_exception('$file is not a string.', $file);
}
+ if (!is_null($outage) && !($outage instanceof outage)) {
+ throw new coding_exception('$outage must be null or an outage object.');
+ }
- $outage = outagedb::get_next_starting();
if (is_null($outage)) {
if (file_exists($file)) {
- if (is_file($file) && is_writable($file)) {
- unlink($file);
- } else {
- throw new file_exception('Cannot remove: '.$file);
- }
+ unlink($file);
}
} else {
self::save_static_page($outage, $file);
diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php
index 1aebd11..26d513e 100644
--- a/classes/local/outagelib.php
+++ b/classes/local/outagelib.php
@@ -30,6 +30,8 @@ use auth_outage\local\controllers\infopage;
use auth_outage\output\renderer;
use coding_exception;
use Exception;
+use file_exception;
+use invalid_parameter_exception;
use stdClass;
defined('MOODLE_INTERNAL') || die();
@@ -130,29 +132,36 @@ class outagelib {
*/
public static function get_config_defaults() {
return [
+ 'allowedips' => '',
+ 'css' => '',
'default_autostart' => '0',
'default_duration' => (string)(60 * 60),
'default_warning_duration' => (string)(60 * 60),
'default_title' => get_string('defaulttitlevalue', 'auth_outage'),
'default_description' => get_string('defaultdescriptionvalue', 'auth_outage'),
- 'css' => '',
];
}
/**
* Executed when outages are modified (created, updated or deleted).
*/
- public static function outages_modified() {
- infopage::update_static_page();
- self::update_maintenance_later();
+ public static function prepare_next_outage() {
+ // If there is an ongoing outage, prepare it instead.
+ $outage = outagedb::get_ongoing();
+ if (is_null($outage)) {
+ $outage = outagedb::get_next_starting();
+ }
+ infopage::update_static_page($outage);
+ self::update_climaintenance_code($outage);
+ self::update_maintenance_later($outage);
}
/**
* Calls Moodle API - set_maintenance_later() to set when the next outage starts.
+ * @param outage|null $outage Outage or null if no scheduled outage.
*/
- private static function update_maintenance_later() {
- $next = outagedb::get_next_autostarting();
- if (is_null($next)) {
+ private static function update_maintenance_later($outage) {
+ if (is_null($outage) || !$outage->autostart) {
unset_config('maintenance_later');
} else {
$message = get_config('moodle', 'maintenance_message');
@@ -162,7 +171,7 @@ class outagelib {
// We cannot do much if forced config, but the logs will show the error.
unset_config('maintenance_message');
}
- set_config('maintenance_later', $next->starttime);
+ set_config('maintenance_later', $outage->starttime);
}
}
@@ -187,4 +196,90 @@ class outagelib {
// Nothing preventing the injection.
return true;
}
+
+ /**
+ * Generates the code to put in sitedata/climaintenance.php when needed.
+ * @param int $starttime Outage start time.
+ * @param int $stoptime Outage stop time.
+ * @param string $allowedips List of IPs allowed.
+ * @return string
+ * @throws invalid_parameter_exception
+ */
+ public static function create_climaintenancephp_code($starttime, $stoptime, $allowedips) {
+ if (!is_int($starttime) || !is_int($stoptime)) {
+ throw new invalid_parameter_exception('Make sure $startime and $stoptime are integers.');
+ }
+ if (!is_string($allowedips) || (trim($allowedips) == '')) {
+ throw new invalid_parameter_exception('$allowedips must be a valid string.');
+ }
+ // I know Moodle validation would clean up this field, but just in case, let's ensure no
+ // single-quotes (and double for the sake of it) are present otherwise it would break the code.
+ $allowedips = str_replace('\'"', '', $allowedips);
+
+ $code = <<<'EOT'
+= {{STARTTIME}}) {
+ if (!defined('CLI_SCRIPT') || !CLI_SCRIPT) {
+ define('MOODLE_INTERNAL', true);
+ require_once($CFG->dirroot.'/lib/moodlelib.php');
+ if (!remoteip_in_list('{{ALLOWEDIPS}}')) {
+ header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance');
+ header('Status: 503 Moodle under maintenance');
+ header('Retry-After: 300');
+ header('Content-type: text/html; charset=utf-8');
+ header('X-UA-Compatible: IE=edge');
+ header('Cache-Control: no-store, no-cache, must-revalidate');
+ header('Cache-Control: post-check=0, pre-check=0', false);
+ header('Pragma: no-cache');
+ header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
+ header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+ header('Accept-Ranges: none');
+ echo '';
+ if (file_exists($CFG->dataroot.'/climaintenance.template.html')) {
+ require($CFG->dataroot.'/climaintenance.template.html');
+ exit(0);
+ }
+ // The file above should always exist, but just in case...
+ die('We are currently under maintentance, please try again later.');
+ }
+ }
+}
+$CFG->auth_outage_check = 1;
+EOT;
+ $search = ['{{STARTTIME}}', '{{ALLOWEDIPS}}', '{{YOURIP}}'];
+ $replace = [$starttime, $allowedips, getremoteaddr('n/a')];
+ return str_replace($search, $replace, $code);
+ }
+
+ /**
+ * Updates the static info page by (re)creating or deleting it as needed.
+ * @param outage|null $outage Outage or null if no scheduled outage.
+ * @throws coding_exception
+ * @throws file_exception
+ */
+ public static function update_climaintenance_code($outage) {
+ global $CFG;
+ $file = $CFG->dataroot.'/climaintenance.php';
+
+ if (!is_null($outage) && !($outage instanceof outage)) {
+ throw new coding_exception('$outage must be null or an outage object.');
+ }
+
+ $config = self::get_config();
+ $allowedips = trim($config->allowedips);
+
+ if (is_null($outage) || ($allowedips == '')) {
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ } else {
+ $code = self::create_climaintenancephp_code($outage->starttime, $outage->stoptime, $allowedips);
+
+ $dir = dirname($file);
+ if (!file_exists($dir) || !is_dir($dir)) {
+ throw new file_exception('Directory must exists: '.$dir);
+ }
+ file_put_contents($file, $code);
+ }
+ }
}
diff --git a/classes/task/update_static_page.php b/classes/task/update_static_page.php
index 561cb6d..bf67067 100644
--- a/classes/task/update_static_page.php
+++ b/classes/task/update_static_page.php
@@ -26,6 +26,7 @@
namespace auth_outage\task;
use auth_outage\local\controllers\infopage;
+use auth_outage\local\outagelib;
use core\task\scheduled_task;
defined('MOODLE_INTERNAL') || die();
@@ -51,6 +52,6 @@ class update_static_page extends scheduled_task {
* Executes the event.
*/
public function execute() {
- infopage::update_static_page();
+ outagelib::prepare_next_outage();
}
}
diff --git a/lang/en/auth_outage.php b/lang/en/auth_outage.php
index 6800303..0fd726d 100644
--- a/lang/en/auth_outage.php
+++ b/lang/en/auth_outage.php
@@ -84,6 +84,10 @@ $string['infountil'] = 'Until:';
$string['infostart'] = 'start';
$string['infostartofwarning'] = 'start of warning';
$string['infopagestaticgenerated'] = 'This warning was generated on {$a->time}.';
+$string['allowedipsempty'] = 'When the allowed IPs list is empty we will not block anyone. You can add your own IP address ({$a->ip}) and block all other IPs.';
+$string['allowedipshasmyip'] = 'Your IP ({$a->ip}) is in the list and you will not be blocked out during an Outage.';
+$string['allowedipshasntmyip'] = 'Your IP ({$a->ip}) is not in the list and you will be blocked out during an outage.';
+$string['allowedipsnoconfig'] = 'Your config.php does not have the extra setup to allow blocking via IP.
Please refer to our README.md file for more information.';
$string['menusettings'] = 'Settings';
$string['menumanage'] = 'Manage';
$string['messageoutagebackonline'] = 'We are back online!';
@@ -108,6 +112,10 @@ $string['outagefinishwarning'] = 'You are about to mark this outage as finished.
$string['outageslistfuture'] = 'Planned outages';
$string['outageslistpast'] = 'Outage history';
$string['pluginname'] = 'Outage manager';
+$string['settingssectiondefaults'] = 'Default Outage Parameters';
+$string['settingssectiondefaultsdescription'] = 'Configure the default values used when creating new outages.';
+$string['settingssectionplugin'] = 'Plugin Configuration';
+$string['settingssectionplugindescription'] = 'General outage management plugin settings.';
$string['starttime'] = 'Start date and time';
$string['starttime_help'] = 'At which date and time the outage starts, preventing general access to the system.';
$string['tableheaderduration'] = 'Duration';
diff --git a/settings.php b/settings.php
index c84d636..7ae864c 100644
--- a/settings.php
+++ b/settings.php
@@ -28,8 +28,12 @@ defined('MOODLE_INTERNAL') || die;
if ($hassiteconfig && is_enabled_auth('outage')) {
$defaults = outagelib::get_config_defaults();
- // Configure default settings page.
$settings->visiblename = get_string('menusettings', 'auth_outage');
+
+ $settings->add(new admin_setting_heading(
+ 'defaults',
+ get_string('settingssectiondefaults', 'auth_outage'),
+ get_string('settingssectiondefaultsdescription', 'auth_outage')));
$settings->add(new admin_setting_configcheckbox(
'auth_outage/default_autostart',
get_string('defaultoutageautostart', 'auth_outage'),
@@ -64,6 +68,12 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
$defaults['default_description'],
PARAM_RAW
));
+
+ $settings->add(new admin_setting_heading(
+ 'plugin',
+ get_string('settingssectionplugin', 'auth_outage'),
+ get_string('settingssectionplugindescription', 'auth_outage')));
+
$settings->add(new admin_setting_configtextarea(
'auth_outage/css',
get_string('defaultlayoutcss', 'auth_outage'),
@@ -71,6 +81,36 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
$defaults['css'],
PARAM_RAW
));
+
+ // Create 'Allowed IPs' settings.
+ $allowedips = outagelib::get_config()->allowedips;
+ $description = '';
+
+ if (!isset($CFG->auth_outage_check) || !$CFG->auth_outage_check) {
+ $description .= $OUTPUT->notification(get_string('allowedipsnoconfig', 'auth_outage'), 'notifyfailure');
+ }
+
+ if (trim($allowedips) == '') {
+ $message = 'allowedipsempty';
+ $type = 'notifymessage';
+ } else if (remoteip_in_list($allowedips)) {
+ $message = 'allowedipshasmyip';
+ $type = 'notifysuccess';
+ } else {
+ $message = 'allowedipshasntmyip';
+ $type = 'notifyfailure';
+ };
+ $description .= $OUTPUT->notification(get_string($message, 'auth_outage', ['ip' => getremoteaddr()]), $type);
+
+ $description .= '
'.get_string('ipblockersyntax', 'admin').'
'; + + $settings->add(new admin_setting_configiplist( + 'auth_outage/allowedips', + get_string('allowediplist', 'admin'), + $description, + $defaults['allowedips'] + )); + // Create category for Outage. $ADMIN->add('authsettings', new admin_category('auth_outage', get_string('pluginname', 'auth_outage'))); // Add settings page toconfigure defaults. diff --git a/tests/behat/behat_auth_outage.php b/tests/behat/behat_auth_outage.php index acd23bf..ad2c4f4 100644 --- a/tests/behat/behat_auth_outage.php +++ b/tests/behat/behat_auth_outage.php @@ -154,6 +154,21 @@ class behat_auth_outage extends behat_base { } } + /** + * @Then /^I should see an empty settings text area "([^"]*)"$/ + * @param string $name + */ + public function i_should_see_an_empty_settings_text_area($name) { + $this->assertSession()->fieldValueEquals('s_auth_outage_'.$name, ''); + } + + /** + * @When /^I go to the "Outage Settings" page$/ + */ + public function i_go_to_the_outage_settings_page() { + $this->getSession()->visit($this->locate_path('/admin/settings.php?section=authsettingoutage')); + } + /** * Counts how many times an specific action is visible. * @param string $action Action to check. diff --git a/tests/behat/ipblock.feature b/tests/behat/ipblock.feature new file mode 100644 index 0000000..77e8566 --- /dev/null +++ b/tests/behat/ipblock.feature @@ -0,0 +1,21 @@ +@dev @auth @auth_outage @javascript +Feature: IP Blocker + In order to allow admins to access the system during an outage + As an admin + I need to be able to login into Moodle + + Terminology: + - An ongoing outage does not block Moodle execution, although it can trigger maintenance mode. + - Maintenance mode completely blocks Moodle and can only be deactivated using the CLI. + + + Background: + Given the authentication plugin "outage" is enabled + + + Scenario: Default IP Whitelist Settings + Given I am an administrator + And I am on homepage + When I navigate to "Settings" node in "Site administration > Plugins > Authentication > Outage manager" + Then I should see "Allowed IP list" + And I should see an empty settings text area "allowedips" diff --git a/tests/behat/warningbar.feature b/tests/behat/warningbar.feature index 8fb5a8e..6be9c40 100644 --- a/tests/behat/warningbar.feature +++ b/tests/behat/warningbar.feature @@ -1,4 +1,4 @@ -@dev @auth @auth_outage @javascript +@auth @auth_outage @javascript Feature: Warning bar In order alert users about an outage As any user diff --git a/tests/phpunit/local/controllers/infopage_test.php b/tests/phpunit/local/controllers/infopage_test.php index d42a215..09d0b18 100644 --- a/tests/phpunit/local/controllers/infopage_test.php +++ b/tests/phpunit/local/controllers/infopage_test.php @@ -257,7 +257,7 @@ class infopagecontroller_test extends auth_outage_base_testcase { * Tests updating the static page when there is no outage. */ public function test_updatestaticpage_nooutage() { - infopage::update_static_page(); + infopage::update_static_page(null); } /** @@ -267,7 +267,7 @@ class infopagecontroller_test extends auth_outage_base_testcase { $file = infopage::get_defaulttemplatefile(); touch($file); self::assertFileExists($file); - infopage::update_static_page(); + infopage::update_static_page(null); self::assertFileNotExists($file); } @@ -276,7 +276,15 @@ class infopagecontroller_test extends auth_outage_base_testcase { */ public function test_updatestaticpage_invalidfile() { $this->set_expected_exception('coding_exception'); - infopage::update_static_page(123); + infopage::update_static_page(null, 123); + } + + /** + * Tests updating the static page with an invalid outage. + */ + public function test_updatestaticpage_invalidoutage() { + $this->set_expected_exception('coding_exception'); + infopage::update_static_page("foobar"); } /** @@ -339,6 +347,7 @@ class infopagecontroller_test extends auth_outage_base_testcase { * Checks if we can create and execute a task to update outage pages. */ public function test_tasks() { + $this->resetAfterTest(true); $task = new update_static_page(); self::assertNotEmpty($task->get_name()); $task->execute(); diff --git a/tests/phpunit/local/outagelib_test.php b/tests/phpunit/local/outagelib_test.php index 3e3998f..2b7a069 100644 --- a/tests/phpunit/local/outagelib_test.php +++ b/tests/phpunit/local/outagelib_test.php @@ -24,6 +24,7 @@ */ use auth_outage\dml\outagedb; +use auth_outage\local\controllers\infopage; use auth_outage\local\outage; use auth_outage\local\outagelib; @@ -70,7 +71,7 @@ class outagelib_test extends advanced_testcase { $this->resetAfterTest(true); set_config('maintenance_later', time() + (60 * 60 * 24 * 7)); // In 1 week. self::assertNotEmpty(get_config('moodle', 'maintenance_later')); - outagelib::outages_modified(); + outagelib::prepare_next_outage(); self::assertEmpty(get_config('moodle', 'maintenance_later')); } @@ -194,6 +195,7 @@ class outagelib_test extends advanced_testcase { 'default_duration', 'default_title', 'default_warning_duration', + 'allowedips', ]; // Set config with values. foreach ($keys as $k) { @@ -206,12 +208,33 @@ class outagelib_test extends advanced_testcase { } } + /** + * Check that config has key. + */ + public function test_config_keys() { + $this->resetAfterTest(true); + $keys = [ + 'allowedips', + 'css', + 'default_autostart', + 'default_description', + 'default_duration', + 'default_title', + 'default_warning_duration', + ]; + $defaults = outagelib::get_config_defaults(); + foreach ($keys as $k) { + self::assertArrayHasKey($k, $defaults); + } + } + /** * Check if get config works getting defaults when needed. */ public function test_get_config_invalid() { $this->resetAfterTest(true); // Set config with invalid values. + set_config('allowedips', " \n", 'auth_outage'); set_config('css', " \n", 'auth_outage'); set_config('default_autostart', " \n", 'auth_outage'); set_config('default_description', " \n", 'auth_outage'); @@ -221,7 +244,7 @@ class outagelib_test extends advanced_testcase { // Get defaults. $defaults = outagelib::get_config_defaults(); $config = outagelib::get_config(); - // Ensure it is using all defailts. + // Ensure it is using all defaults. foreach ($defaults as $k => $v) { self::assertSame($v, $config->$k); } @@ -255,5 +278,165 @@ class outagelib_test extends advanced_testcase { self::assertEmpty($CFG->additionalhtmltopofbody); } -} + public function test_createmaintenancephpcode() { + $expected = <<<'EOT' += 123) { + if (!defined('CLI_SCRIPT') || !CLI_SCRIPT) { + define('MOODLE_INTERNAL', true); + require_once($CFG->dirroot.'/lib/moodlelib.php'); + if (!remoteip_in_list('heyyou +a.b.c.d +e.e.e.e/20')) { + header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance'); + header('Status: 503 Moodle under maintenance'); + header('Retry-After: 300'); + header('Content-type: text/html; charset=utf-8'); + header('X-UA-Compatible: IE=edge'); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Cache-Control: post-check=0, pre-check=0', false); + header('Pragma: no-cache'); + header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Accept-Ranges: none'); + echo ''; + if (file_exists($CFG->dataroot.'/climaintenance.template.html')) { + require($CFG->dataroot.'/climaintenance.template.html'); + exit(0); + } + // The file above should always exist, but just in case... + die('We are currently under maintentance, please try again later.'); + } + } +} +$CFG->auth_outage_check = 1; +EOT; + $found = outagelib::create_climaintenancephp_code(123, 456, "hey'\"you\na.b.c.d\ne.e.e.e/20"); + self::assertSame($expected, $found); + } + + public function test_createmaintenancephpcode_withoutage() { + global $CFG; + $this->resetAfterTest(true); + + $expected = <<<'EOT' += 123) { + if (!defined('CLI_SCRIPT') || !CLI_SCRIPT) { + define('MOODLE_INTERNAL', true); + require_once($CFG->dirroot.'/lib/moodlelib.php'); + if (!remoteip_in_list('127.0.0.1')) { + header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance'); + header('Status: 503 Moodle under maintenance'); + header('Retry-After: 300'); + header('Content-type: text/html; charset=utf-8'); + header('X-UA-Compatible: IE=edge'); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Cache-Control: post-check=0, pre-check=0', false); + header('Pragma: no-cache'); + header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Accept-Ranges: none'); + echo ''; + if (file_exists($CFG->dataroot.'/climaintenance.template.html')) { + require($CFG->dataroot.'/climaintenance.template.html'); + exit(0); + } + // The file above should always exist, but just in case... + die('We are currently under maintentance, please try again later.'); + } + } +} +$CFG->auth_outage_check = 1; +EOT; + $outage = new outage([ + 'starttime' => 123, + 'stoptime' => 456, + ]); + $file = $CFG->dataroot.'/climaintenance.php'; + set_config('allowedips', '127.0.0.1', 'auth_outage'); + + outagelib::update_climaintenance_code($outage); + self::assertFileExists($file); + $found = file_get_contents($file); + self::assertSame($found, $expected); + } + + public function test_createmaintenancephpcode_withoutips() { + global $CFG; + $this->resetAfterTest(true); + + $outage = new outage([ + 'starttime' => 123, + 'stoptime' => 456, + ]); + $file = $CFG->dataroot.'/climaintenance.php'; + set_config('allowedips', '', 'auth_outage'); + + touch($file); + outagelib::update_climaintenance_code($outage); + self::assertFileNotExists($file); + } + + public function test_createmaintenancephpcode_withoutoutage() { + global $CFG; + $file = $CFG->dataroot.'/climaintenance.php'; + + touch($file); + outagelib::update_climaintenance_code(null); + self::assertFileNotExists($file); + } + + /** + * Related to Issue #70: Creating ongoing outage does not trigger maintenance file creation. + */ + public function test_preparenextoutage_notautostart() { + global $CFG; + + $this->resetAfterTest(true); + self::setAdminUser(); + $now = time(); + $outage = new outage([ + 'autostart' => false, + 'warntime' => $now - 200, + 'starttime' => $now - 100, + 'stoptime' => $now + 200, + 'title' => 'Title', + 'description' => 'Description', + ]); + set_config('allowedips', '127.0.0.1', 'auth_outage'); + outagedb::save($outage); + + // The method outagelib::prepare_next_outage() should have been called by save(). + foreach ([infopage::get_defaulttemplatefile(), $CFG->dataroot.'/climaintenance.php'] as $file) { + self::assertFileExists($file); + unlink($file); + } + } + + /** + * Related to Issue #72: IP Block still triggers cli maintenance mode even without autostart. + */ + public function test_preparenextoutage_noautostarttrigger() { + global $CFG; + + $this->resetAfterTest(true); + self::setAdminUser(); + $now = time(); + $outage = new outage([ + 'autostart' => false, + 'warntime' => $now - 200, + 'starttime' => $now - 100, + 'stoptime' => $now + 200, + 'title' => 'Title', + 'description' => 'Description', + ]); + outagedb::save($outage); + + // The method outagelib::prepare_next_outage() should have been called by save(). + self::assertFalse(get_config('moodle', 'maintenance_later')); + // This file should not exist even if the statement above fails as Moodle does not create it immediately but test anyway. + self::assertFileNotExists($CFG->dataroot.'/climaintenance.html'); + } +} diff --git a/version.php b/version.php index 02babdd..eead3a7 100644 --- a/version.php +++ b/version.php @@ -28,7 +28,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = "auth_outage"; -$plugin->version = 2016110200; // The current plugin version (Date: YYYYMMDDXX). -$plugin->release = '1.0.5'; // Human-readable release information. +$plugin->version = 2016110700; // The current plugin version (Date: YYYYMMDDXX). +$plugin->release = '1.0.6'; // Human-readable release information. $plugin->requires = 2014051200; // Requires Moodle 2.7 or later. Moodle 3.0 or later recommended. $plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments!