19 Commits

Author SHA1 Message Date
ScottVerbeek
f1cff274fe Updated README.md with new branch 2021-01-07 10:59:53 +10:00
Dan Marsden
b9baa58252 update readme to cover branch versions. 2021-01-07 09:36:59 +10:00
Brendan Heywood
1eb509d458 Merge pull request #199 from ledship/totara-10-time
Accept unix time for --start CLI option to totara-10 branch
2020-07-24 09:59:24 +10:00
Dan Marsden
03d33cb5c3 Remove incorrect usage of example.com in tests.
remove http part of test - site might be https.
2020-07-15 20:29:55 +12:00
Alexander
ee94917bf4 Accept unix time for --start CLI option 2020-07-07 10:12:03 +12:00
kristian-94
76f6523577 Merge pull request #202 from catalyst/WR336891
Issue 189 Unable to find Class 'core\ip_utils'
2020-07-03 13:43:40 +10:00
Heena Agheda
ab26bae579 Add services: mysql 2020-07-03 10:41:01 +10:00
Heena Agheda
be259f6ee5 Upgrade PHP version 2020-07-03 10:19:26 +10:00
Heena Agheda
186c75b00b Fix failing tests 2020-07-03 09:47:21 +10:00
Heena Agheda
c56025bcdd Upgrade postgresql version 2020-07-02 15:03:58 +10:00
katcher
3375ef6fea Issue 189 Unable to find Class 'core\ip_utils'
Following upgrade of moodle to 3.5.11, error above prevented moodle from
displaying on the web.  The class ip_utils was for somereason not loaded
and through an error preventing the site from displaying when in
maintenance mod.  Adding the require class appears to have fixed the
issue.
2020-07-02 11:14:14 +10:00
Nathan Nguyen
c234a70476 Fix problem with loading stylesheet in preview mode 2019-10-16 12:01:51 +11:00
Dan Marsden
21ff2fbd3b Fix resetAfterTest(false) in events_test file for Totara tests. 2019-07-22 10:41:44 +12:00
Dan Marsden
4cf8d12aa4 Fix #161 - make unit tests distinct. 2019-07-22 10:41:34 +12:00
Kristian Ringer
c8f99a7bf3 Fix unit tests in totara 10
- Change outagelib_test to use the auth_outage_base_testcase base class
  - Remove outages from test table in tearDown function after each test.
2019-05-08 13:30:08 +10:00
Ilya Tregubov
f72a03aa5a Incease timeout to prevent settings page throwing error (from time to time) 2018-10-11 11:56:40 +11:00
Dan Marsden
a42ad4141a Fix #120 increase timeout values to prevent ci failures. 2018-10-05 10:21:28 +13:00
Dan Marsden
4ce9f05ebf Fix #124 use correct urls in redirects. 2018-10-03 15:17:21 +13:00
Dan Marsden
bdf158a677 Update travis config for 3.2 and lower branch. 2018-10-03 15:05:09 +13:00
72 changed files with 635 additions and 1428 deletions

View File

@@ -1,10 +0,0 @@
# .github/workflows/ci.yml
name: ci
on: [push, pull_request]
jobs:
ci:
uses: catalyst/catalyst-moodle-workflows/.github/workflows/ci.yml@main
with:
disable_behat: true

View File

@@ -1,21 +0,0 @@
#
# Whenever version.php is changed, add the latest version
# to the Moodle Plugins directory at https://moodle.org/plugins
#
name: Releasing in the Plugins directory
on:
push:
branches:
- MOODLE_39_STABLE
paths:
- 'version.php'
jobs:
workflow_group_39_plus_release:
uses: catalyst/catalyst-moodle-workflows/.github/workflows/group-39-plus-release.yml@main
with:
plugin_name: auth_outage
disable_behat: true
secrets:
moodle_org_token: ${{ secrets.MOODLE_ORG_TOKEN }}

47
.travis.yml Normal file
View File

@@ -0,0 +1,47 @@
language: php
cache:
directories:
- $HOME/.composer/cache
addons:
postgresql: "9.5"
php:
- 7.0
services:
- mysql
env:
- DB=pgsql MOODLE_BRANCH=MOODLE_30_STABLE
- DB=pgsql MOODLE_BRANCH=MOODLE_31_STABLE
- DB=pgsql MOODLE_BRANCH=MOODLE_32_STABLE
matrix:
include:
- php: 5.6
env: DB=pgsql MOODLE_BRANCH=MOODLE_30_STABLE
- php: 5.6
env: DB=mysqli MOODLE_BRANCH=MOODLE_30_STABLE
before_install:
- phpenv config-rm xdebug.ini
- cd ../..
- composer selfupdate
- composer create-project -n --no-dev moodlerooms/moodle-plugin-ci ci ^1
- export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
install:
- moodle-plugin-ci install -vvv
script:
- moodle-plugin-ci validate
- moodle-plugin-ci phplint
- moodle-plugin-ci phpcpd
- moodle-plugin-ci phpmd
- moodle-plugin-ci codechecker
- moodle-plugin-ci csslint
- moodle-plugin-ci shifter
- moodle-plugin-ci jshint
- moodle-plugin-ci phpunit

View File

@@ -59,9 +59,6 @@ Basic Usage
_Anyone who tries to use Moodle now will receive a maintenance message._
**Note:** If the outage starts with the option `Auto start maintenance mode` checked, the maint mode won't exit automatically.
It will need to be disabled through command line.
1) Perform the maintenance activities.
At this point it is safe to perform the required maintenance as no one can use the system, not even admins.

View File

@@ -1,12 +1,13 @@
![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/catalyst/moodle-auth_outage/ci.yml?branch=MOODLE_39_STABLE)
<a href="https://travis-ci.org/catalyst/moodle-auth_outage">
<img src="https://travis-ci.org/catalyst/moodle-auth_outage.svg?branch=master">
</a>
# Moodle Outage manager plugin
* [Version Support](#version-support)
* [What is this?](#what-is-this)
* [Moodle Requirements](#moodle-requirements)
* [Screenshots](#screenshots)
* [Installation](#installation)
* [Theme configuration](#theme-configuration)
* [How to use](#how-to-use)
* [Quick Guide](#quick-guide)
* [Why is it an auth plugin?](#why-it-is-an-auth-plugin)
@@ -24,7 +25,10 @@ this plugin creates the concept of graduated outages where at predefined times b
an outage and after, different levels of warning and access can be provided to students
and testers letting them know what is about to happen and why.
![image](https://user-images.githubusercontent.com/187449/149717343-1d2c5237-dbc6-4d2a-a08c-2bdb343e87d2.png)
<img alt="Default" src="https://cdn.rawgit.com/catalyst/moodle-auth_outage/master/docs/default.svg" width="520">
<img alt="Manager" src="https://cdn.rawgit.com/catalyst/moodle-auth_outage/master/docs/outage.svg" width="520">
Moodle Requirements
-------------------
@@ -37,12 +41,14 @@ need to manually add one extra plugin, please check:
Branches
--------
| Moodle version | Totara | Branch | PHP |
| ------------------ | --------------- | ---------------- | ---- |
| Moodle 3.9+ | Totara 13+ | MOODLE_39_STABLE | 7.2+ |
| Moodle 3.3 to 3.8 | Totara 11 to 12 | MOODLE_38_STABLE | 7.1+ |
| Moodle 2.7 to 3.2 | | MOODLE_32_STABLE | 5.5+ |
| | Totara up to 10 | TOTARA_10 | 5.5+ |
| Moodle version | Branch | PHP |
| ----------------- | ----------- | ---- |
| Moodle 2.7 to 3.2 | MOODLE_32_STABLE | 5.5+ |
| Totara up to 10 | TOTARA_10 | 5.5+ |
| Moodle 3.3 to 3.9 | MOODLE_39_STABLE | 7.0+ |
| Totara 11 to 12 | MOODLE_39_STABLE | 7.0+ |
| Moodle 3.10 | master | 7.2+ |
| Totara 13+ | master | 7.2+ |
Screenshots
-----------
@@ -87,62 +93,6 @@ if (file_exists(__DIR__.'/auth/outage/bootstrap.php')) {
}
```
Theme configuration
-------------------
This plugin must work gracefully with your theme, but every theme can be different so it's impossible to get this right out of the box (other than with the default moodle theme Boost).
There is an admin setting which allows you to add or override and css to fix css issues. Typically these include properly pushing the page down when the outage notification bar is visible, including making this work with fixed headers and when the hamburger menu is open / closed and at different responsive breakpoints.
This can be found at:
`Dashboard / Site administration / Plugins / Authentication / Outage manager / Settings`
Custom Theme Additional SCSS
-------------------
Custom themes generally do not have the same `$navbar-height` variable set to 80px (MOODLE), therefore custom themes will not calculate the change in navbar height with page elements that calculate the navbar total height.
Add the following SCSS For Moodle 3.11+
```
body.auth_outage {
#page-wrapper {
#nav-drawer {
top: $navbar-height + 100px;
height: calc(100% - (#{$navbar-height} + 100px));
}
#page {
margin-top: $navbar-height + 100px;
}
}
[data-region=right-hand-drawer].drawer {
top: $navbar-height + 100px;
height: calc(100% - (#{$navbar-height} + 100px));
}
}
```
Totara is a little different with version 13+ and no variables are used to set the `totaraNav` height
Add the following CSS For Totara 13+
```
.totaraNav {
margin-top: 100px;
}
.local_envbar .totaraNav {
margin-top: 50px;
}
body.auth_outage #page {
margin-top: 0;
}
```
How to use
----------

View File

@@ -58,6 +58,7 @@ class auth_plugin_outage extends auth_plugin_base {
/**
* Always returns false (password wrong or user does not exist).
*
* @inheritdoc PHPMD will not warn about unused parameters if overriding.
* @param string $username Not used in this plugin.
* @param string $password Not used in this plugin.
* @return bool False
@@ -65,4 +66,11 @@ class auth_plugin_outage extends auth_plugin_base {
public function user_login($username, $password) {
return false;
}
/**
* Login page hook.
*/
public function loginpage_hook() {
outagelib::inject();
}
}

View File

@@ -30,9 +30,7 @@
*/
// This call is required by Moodle, but this script should have been called by config.php anyway.
// @codingStandardsIgnoreStart
require_once(__DIR__.'/../../config.php');
// @codingStandardsIgnoreEnd
// We need the CFG->dataroot, if not set yet this script is called too early in config.php file.
if (!isset($CFG->dataroot)) {
@@ -69,20 +67,9 @@ if (is_callable('auth_outage_bootstrap_callback')) {
}
// 3) Check for allowed scripts or IPs during outages.
if (!empty($_SERVER['REQUEST_URI'])) {
$rooturl = parse_url($CFG->wwwroot);
$path = '';
if (array_key_exists('path', $rooturl) && !empty($rooturl['path'])) {
$path = $rooturl['path'];
}
$url = $path.'/auth/outage/info.php';
$outageinfo = strpos($_SERVER['REQUEST_URI'], $url) === 0 ? true : false;
}
$allowed = !file_exists($CFG->dataroot.'/climaintenance.php') // Not in maintenance mode.
|| (defined('ABORT_AFTER_CONFIG') && ABORT_AFTER_CONFIG) // Only config requested.
|| (defined('CLI_SCRIPT') && CLI_SCRIPT) // Allow CLI scripts.
|| $outageinfo // Allow outage info requests.
|| (defined('NO_AUTH_OUTAGE') && NO_AUTH_OUTAGE); // Allow any page should not be blocked by maintenance mode.
|| (defined('CLI_SCRIPT') && CLI_SCRIPT); // Allow CLI scripts.
if (!$allowed) {
// Call the climaintenance.php which will check for allowed IPs.
$CFG->dirroot = dirname(dirname(dirname(__FILE__))); // It is not defined yet but the script below needs it.

View File

@@ -25,12 +25,6 @@
use auth_outage\dml\outagedb;
define('NO_MOODLE_COOKIES', true);
// @codingStandardsIgnoreStart
header('Cache-Control: public, max-age=10,s-maxage=10');
// @codingStandardsIgnoreEnd
define('NO_AUTH_OUTAGE', true);
require_once(__DIR__.'/../../config.php');
$active = outagedb::get_active();

View File

@@ -65,7 +65,7 @@ class calendar {
debugging('Cannot update calendar entry for outage #'.$outage->id.', event not found. Creating it...');
self::create($outage);
} else {
$event->update(self::create_data($outage), false);
$event->update(self::create_data($outage));
}
}

View File

@@ -117,40 +117,25 @@ class outagedb {
$outage->createdby = $USER->id;
// Then create it, log it and adjust its id.
$outage->id = $DB->insert_record('auth_outage', $outage, true);
$other = (array) $outage;
$other['title'] = $outage->get_title();
$event = outage_created::create([
'objectid' => $outage->id,
'other' => $other,
]);
$event->add_record_snapshot('auth_outage', (object)(array) $outage);
$event->trigger();
outage_created::create(
['objectid' => $outage->id, 'other' => (array)$outage]
)->trigger();
// Create calendar entry.
calendar::create($outage);
} else {
$other = (array) $outage;
$other['title'] = $outage->get_title();
$event = outage_updated::create([
'objectid' => $outage->id,
'other' => $other,
]);
$event->add_record_snapshot('auth_outage', (object)(array) $outage);
$event->trigger();
// Remove the createdby field so it does not get updated.
unset($outage->createdby);
$DB->update_record('auth_outage', $outage);
// Log it.
outage_updated::create(
['objectid' => $outage->id, 'other' => (array)$outage]
)->trigger();
// Update calendar entry.
calendar::update($outage);
}
// Trigger outages modified events.
outagelib::prepare_next_outage(true);
outagelib::prepare_next_outage();
// All done, return the id.
return $outage->id;
@@ -171,16 +156,7 @@ class outagedb {
// Log it.
$previous = $DB->get_record('auth_outage', ['id' => $id], '*', MUST_EXIST);
$outage = new outage($previous);
$other = (array) $outage;
$other['title'] = $outage->get_title();
$event = outage_deleted::create([
'objectid' => $id,
'other' => $other,
]);
$event = outage_deleted::create(['objectid' => $id, 'other' => (array)$previous]);
$event->add_record_snapshot('auth_outage', $previous);
$event->trigger();
@@ -211,20 +187,21 @@ class outagedb {
throw new coding_exception('$time must be null or a positive int.', $time);
}
// Get cached outage, or null.
$outageinfo = get_config('moodle', 'auth_outage_active_outage');
$select = ':datetime2 <= stoptime AND (finished IS NULL OR :datetime3 <= finished)'; // End condition.
$select = "(warntime <= :datetime1 AND (${select}))"; // Full select part.
$data = $DB->get_records_select(
'auth_outage',
$select,
['datetime1' => $time, 'datetime2' => $time, 'datetime3' => $time],
'starttime ASC, stoptime DESC, title ASC',
'*',
0,
1
);
if (!$outageinfo) {
return null;
} else {
$outagecache = new outage(json_decode($outageinfo));
}
if ($outagecache && $outagecache->warntime <= $time && $outagecache->stoptime >= $time
&& (!$outagecache->finished || $outagecache->finished >= $time)) {
return $outagecache;
}
return null;
// 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));
}
/**

View File

@@ -28,6 +28,8 @@ namespace auth_outage\event;
use core\event\base;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
/**
* outage_created class.
*
@@ -43,7 +45,8 @@ class outage_created extends base {
* @return string
*/
public function get_description() {
return "The user with the id '{$this->userid}' created outage {$this->other['id']} '{$this->other['title']}'";
return "The user with the id '{$this->userid}' created a new outage title '{$this->other['title']}' ".
" with id '{$this->other['id']}'.";
}
/**
@@ -51,7 +54,7 @@ class outage_created extends base {
* @return moodle_url
*/
public function get_url() {
return new moodle_url('/auth/outage/edit.php', ['edit' => $this->other['id']]);
return new moodle_url('/auth/outage/list.php#auth_outage_id_'.$this->other['id']);
}
/**

View File

@@ -27,6 +27,8 @@ namespace auth_outage\event;
use core\event\base;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
/**
* outage_deleted class.
*
@@ -42,7 +44,8 @@ class outage_deleted extends base {
* @return string
*/
public function get_description() {
return "The user with the id '{$this->userid}' deleted outage {$this->other['id']} '{$this->other['title']}'";
return "The user with the id '{$this->userid}' deleted the outage titled '{$this->other['title']}' ".
"with id '{$this->other['id']}'.";
}
/**
@@ -50,7 +53,7 @@ class outage_deleted extends base {
* @return moodle_url
*/
public function get_url() {
return new moodle_url('/auth/outage/manage.php');
return new moodle_url('/auth/outage/list.php#auth_outage_id_'.$this->other['id']);
}
/**

View File

@@ -28,6 +28,8 @@ namespace auth_outage\event;
use core\event\base;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
/**
* outage_updated class.
*
@@ -43,7 +45,8 @@ class outage_updated extends base {
* @return string
*/
public function get_description() {
return "The user with the id '{$this->userid}' updated outage {$this->other['id']} '{$this->other['title']}'";
return "The user with the id '{$this->userid}' updated the outage title '{$this->other['title']}' ".
"with id '{$this->other['id']}'.";
}
/**
@@ -51,7 +54,7 @@ class outage_updated extends base {
* @return moodle_url
*/
public function get_url() {
return new moodle_url('/auth/outage/edit.php', ['edit' => $this->other['id']]);
return new moodle_url('/auth/outage/list.php');
}
/**

View File

@@ -82,7 +82,6 @@ class edit extends moodleform {
$mform->addHelpButton('description', 'description', 'auth_outage');
$mform->addElement('static', 'usagehints', '', get_string('textplaceholdershint', 'auth_outage'));
$mform->addElement('static', 'warningreenablemaintenancemode', '');
$this->add_action_buttons();
}
@@ -147,9 +146,6 @@ class edit extends moodleform {
* @throws coding_exception
*/
public function set_data($outage) {
global $OUTPUT, $CFG;
$mform = $this->_form;
// Cannot change method signature, check type.
if ($outage instanceof outage) {
$this->_form->setDefaults([
@@ -161,21 +157,6 @@ class edit extends moodleform {
'title' => $outage->title,
'description' => ['text' => $outage->description, 'format' => '1'],
]);
// If the default_autostart is configured in config, then force autostart to be the default value.
if (array_key_exists('auth_outage', $CFG->forced_plugin_settings)
&& array_key_exists('default_autostart', $CFG->forced_plugin_settings['auth_outage'])) {
$this->_form->setDefaults([
'autostart' => $CFG->forced_plugin_settings['auth_outage']['default_autostart']
]);
$mform->freeze('autostart');
}
if (!empty($outage->id) && $outage->autostart && $outage->starttime < time() && $outage->stoptime > time()) {
$warning = $mform->getElement('warningreenablemaintenancemode');
$warning->setValue($OUTPUT->notification(get_string('warningreenablemaintenancemode', 'auth_outage'),
'notifywarning'));
}
} else {
throw new coding_exception('$outage must be an outage object.', $outage);
}

View File

@@ -27,6 +27,8 @@ namespace auth_outage\local\cli;
use Exception;
defined('MOODLE_INTERNAL') || die();
/**
* cli_exception class.
*

View File

@@ -29,6 +29,8 @@ use auth_outage\local\outagelib;
use coding_exception;
use core\session\manager;
defined('MOODLE_INTERNAL') || die();
/**
* clibase class.
*
@@ -104,25 +106,25 @@ abstract class clibase {
* Generates all options (parameters) available for the CLI command.
* @return mixed[] Options.
*/
abstract public function generate_options();
public abstract function generate_options();
/**
* Generate all short forms for the available options.
* @return string[] Short form options.
*/
abstract public function generate_shortcuts();
public abstract function generate_shortcuts();
/**
* Executes the CLI script.
*/
abstract public function execute();
public abstract function execute();
/**
* Change session to admin user.
*/
protected function become_admin_user() {
global $DB;
$user = get_admin();
$user = $DB->get_record('user', ['id' => 2]);
unset($user->description);
unset($user->access);
unset($user->preference);
@@ -145,6 +147,5 @@ abstract class clibase {
$long = '--'.$long;
printf(" %-4s %-20s %s\n", $short, $long, $text);
}
printf("\n%s\n\n", get_string('cli'.$cliname.'examples', 'auth_outage'));
}
}

View File

@@ -29,6 +29,8 @@ use auth_outage\dml\outagedb;
use auth_outage\local\outage;
use coding_exception;
defined('MOODLE_INTERNAL') || die();
/**
* create class.
*
@@ -198,7 +200,7 @@ class create extends clibase {
private function clone_defaults() {
$id = $this->options['clone'];
if (!is_number($id) || ($id <= 0)) {
throw new cli_exception(get_string('clierrorinvalidvaluenotid', 'auth_outage', ['param' => 'clone']),
throw new cli_exception(get_string('clierrorinvalidvalue', 'auth_outage', ['param' => 'clone']),
cli_exception::ERROR_PARAMETER_INVALID);
}
@@ -243,12 +245,12 @@ class create extends clibase {
*/
private function merge_options_check_parameters_int_nonnegative($option, $param) {
if (!is_number($option)) {
throw new cli_exception(get_string('clierrorinvalidvaluenotnumber', 'auth_outage', ['param' => $param]),
throw new cli_exception(get_string('clierrorinvalidvalue', 'auth_outage', ['param' => $param]),
cli_exception::ERROR_PARAMETER_INVALID);
}
$option = (int)$option;
if ($option < 0) {
throw new cli_exception(get_string('clierrorinvalidvaluenegativenumber', 'auth_outage', ['param' => $param]),
throw new cli_exception(get_string('clierrorinvalidvalue', 'auth_outage', ['param' => $param]),
cli_exception::ERROR_PARAMETER_INVALID);
}
return $option;
@@ -263,12 +265,12 @@ class create extends clibase {
*/
private function merge_options_check_parameters_string_nonempty($option, $param) {
if (!is_string($option)) {
throw new cli_exception(get_string('clierrorinvalidvaluenotstring', 'auth_outage', ['param' => $param]),
throw new cli_exception(get_string('clierrorinvalidvalue', 'auth_outage', ['param' => $param]),
cli_exception::ERROR_PARAMETER_INVALID);
}
$option = trim($option);
if (strlen($option) == 0) {
throw new cli_exception(get_string('clierrorinvalidvalueemptystring', 'auth_outage', ['param' => $param]),
throw new cli_exception(get_string('clierrorinvalidvalue', 'auth_outage', ['param' => $param]),
cli_exception::ERROR_PARAMETER_INVALID);
}
return $option;
@@ -296,7 +298,7 @@ class create extends clibase {
}
}
throw new cli_exception(get_string('clierrorinvalidvaluenotbool', 'auth_outage', ['param' => $param]),
throw new cli_exception(get_string('clierrorinvalidvalue', 'auth_outage', ['param' => $param]),
cli_exception::ERROR_PARAMETER_INVALID);
}
}

View File

@@ -28,6 +28,8 @@ namespace auth_outage\local\cli;
use auth_outage\dml\outagedb;
use auth_outage\local\outage;
defined('MOODLE_INTERNAL') || die();
/**
* finish class.
*

View File

@@ -28,6 +28,8 @@ namespace auth_outage\local\cli;
use auth_outage\dml\outagedb;
use auth_outage\local\outage;
defined('MOODLE_INTERNAL') || die();
/**
* waitforit class.
*
@@ -129,7 +131,7 @@ class waitforit extends clibase {
return;
}
$time = \totara_core\strftime::format('%F %T %Z');
$time = strftime('%F %T %Z');
printf("[%s] %s\n", $time, $message);
}

View File

@@ -32,6 +32,8 @@ use coding_exception;
use context_system;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
/**
* infopage class.
*
@@ -46,32 +48,20 @@ class infopage {
*/
private $outage;
/**
* @var bool|null Defines if the page is generated for a static outage page.
*/
private $static;
/**
* infopage_controller constructor.
* @param array $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),
'outage' => null,
'static' => optional_param('static', false, PARAM_BOOL),
];
} else {
$defaults = [
'id' => null,
'outage' => null,
'static' => false,
];
$params = array_merge($defaults, $params);
}
@@ -98,6 +88,7 @@ class infopage {
/**
* Generates and outputs the HTML for the info page.
* @uses redirect
* @SuppressWarnings(PHPMD.UnusedLocalVariable) $viewbag is used inside 'require'.
*/
public function output() {
global $PAGE, $CFG, $OUTPUT;
@@ -106,17 +97,13 @@ class infopage {
redirect(new moodle_url('/'));
}
// If it's not static outage page, then check access, then redirect if not allowed.
if (!$this->static && !has_capability('auth/outage:viewinfo', context_system::instance())) {
redirect(new moodle_url('/'));
}
$PAGE->set_context(context_system::instance());
$PAGE->set_title($this->outage->get_title());
$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();
outagelib::inject();
echo $OUTPUT->header();
$viewbag = [
@@ -152,6 +139,5 @@ class infopage {
}
$this->outage = $params['outage'];
$this->static = $params['static'];
}
}

View File

@@ -29,6 +29,8 @@ use auth_outage\local\outage;
use coding_exception;
use DOMDocument;
defined('MOODLE_INTERNAL') || die();
/**
* maintenance_static_page class.
*
@@ -55,11 +57,11 @@ class maintenance_static_page {
if (is_null($outage)) {
$html = null;
} else if (PHPUNIT_TEST || defined('BEHAT_SITE_RUNNING')) {
} else if (PHPUNIT_TEST) {
$html = '<html></html>';
} else {
$data = maintenance_static_page_io::file_get_data(
$CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&static=1&id='.$outage->id);
$CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&id='.$outage->id);
$html = $data['contents'];
}
@@ -120,7 +122,6 @@ class maintenance_static_page {
}
/**
* Gets generator io.
* @return maintenance_static_page_io
*/
public function get_io() {

View File

@@ -27,11 +27,11 @@ namespace auth_outage\local\controllers;
use auth_outage\local\outagelib;
use coding_exception;
use core_php_time_limit;
use DOMDocument;
use DOMElement;
use invalid_state_exception;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
/**
* maintenance_static_page_generator class.
@@ -42,15 +42,6 @@ use moodle_url;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class maintenance_static_page_generator {
/** PATTERN
* The pattern should match the attribute values that
* go as 'url(xxxxx)', but make sure 'url(data:xxxxx)' is not
* rewritten. Must be case insensitive to match 'URL(xxxxx)'.
* It should be possible to specify other background attributes as
* 'background: color url(xxxxx) no-repeat'.
*/
protected const PATTERN = '/url\s*\(\s*[\'"]?(?![\'"]?data:)([^\s\'"]+)[\'"]?\s*\)/i';
/** @var DOMDocument */
protected $dom;
@@ -83,10 +74,6 @@ class maintenance_static_page_generator {
$this->io->cleanup();
if (!is_null($this->dom)) {
// This can take a while to process using repeated curls.
core_php_time_limit::raise();
$this->io->create_resources_path();
$this->remove_script_tags();
@@ -95,7 +82,6 @@ class maintenance_static_page_generator {
$this->update_link_favicon();
$this->update_images();
$this->remove_configured_css_selectors();
$this->update_inline_background_images();
$html = $this->dom->saveHTML();
if (trim($html) == '') {
@@ -108,7 +94,6 @@ class maintenance_static_page_generator {
}
/**
* Gets maintenance_static_page_io.
* @return maintenance_static_page_io
*/
public function get_io() {
@@ -142,7 +127,7 @@ class maintenance_static_page_generator {
continue;
}
$saved = $this->io->save_url_file($href);
if (empty($saved['url'])) {
if (is_null($saved['url'])) {
$url = $href; // Skipped, use original URL.
} else {
$this->update_link_stylesheet_parse($saved['file'], dirname($href));
@@ -152,29 +137,6 @@ class maintenance_static_page_generator {
}
}
/**
* Retrieves all URLs from file content using regular expressions.
*
* @param string $contents Content of the file
* @return array Array of all matches in multi-dimensional array
*/
public function get_urls_from_stylesheet($contents) {
preg_match_all('#url\([\'"]?(?!data:)([^\'"\)]+)#', $contents, $matches);
return $matches;
}
/**
* Retrieves a URL from inline style using regular expressions.
*
* @param string $style Content of the style attribute
* @return array Array containing match
*/
public function get_url_from_inline_style($style) {
preg_match(self::PATTERN, $style, $match);
return $match;
}
/**
* Checks for urls inside filename.
*
@@ -185,15 +147,15 @@ class maintenance_static_page_generator {
global $CFG;
$contents = file_get_contents($filename);
$matches = $this->get_urls_from_stylesheet($contents);
if (!preg_match_all('#url\([\'"]?([^\'"\)]+)#', $contents, $matches)) {
return;
}
foreach ($matches[1] as $originalurl) {
// Allow incomplete URLs in CSS, assume it is from moodle root.
if (maintenance_static_page_io::is_url($originalurl)) {
$fullurl = $originalurl;
} else if ($originalurl[0] == '/') {
$rooturl = parse_url($CFG->wwwroot);
$fullurl = $rooturl['scheme'].'://'.$rooturl['host'].$originalurl;
$fullurl = $CFG->wwwroot.$originalurl;
} else {
$fullurl = $baseref.'/'.$originalurl;
}
@@ -217,12 +179,10 @@ class maintenance_static_page_generator {
foreach ($links as $link) {
$rel = $link->getAttribute("rel");
$href = $link->getAttribute("href");
if (($rel == 'shortcut icon') && ($href != '')) {
if (!maintenance_static_page_io::is_url($href)) {
$href = (string) new moodle_url($href);
}
$link->setAttribute('href', $this->io->generate_file_url($href)); // Works for most image formats.
if (($rel != 'shortcut icon') || ($href == '')) {
continue;
}
$link->setAttribute('href', $this->io->generate_file_url($href)); // Works for most image formats.
}
}
@@ -234,37 +194,10 @@ class maintenance_static_page_generator {
foreach ($links as $link) {
$src = $link->getAttribute("src");
if ($src != '') {
if (!maintenance_static_page_io::is_url($src)) {
$src = (string) new moodle_url($src);
}
$link->setAttribute('src', $this->io->generate_file_url($src)); // Works for most image formats.
}
}
}
/**
* Fetch and fixes all inline background images.
*/
private function update_inline_background_images() {
global $CFG;
$xpath = new \DOMXPath($this->dom);
$elements = $xpath->query("//*[contains(@style,'background')]");
foreach ($elements as $element) {
$style = $element->getAttribute("style");
$matches = $this->get_url_from_inline_style($style);
if (isset($matches[1])) {
// Allow incomplete URLs in style, assume it is from moodle root.
if (maintenance_static_page_io::is_url($matches[1])) {
$fullurl = $matches[1];
} else {
$fullurl = (string) new moodle_url($matches[1]);
}
$newurl = $this->io->generate_file_url($fullurl);
$updated = preg_replace(self::PATTERN, ' url('.$newurl.') ', $style);
$element->setAttribute('style', $updated);
if ($src == '') {
continue;
}
$link->setAttribute('src', $this->io->generate_file_url($src)); // Works for most image formats.
}
}
@@ -303,7 +236,7 @@ class maintenance_static_page_generator {
/**
* Fetches all elements based on the given selector.
*
* @param string $selector element selector
* @param $selector
*
* @return DOMElement[]
*/
@@ -321,7 +254,7 @@ class maintenance_static_page_generator {
/**
* Fetch all elements which contains the given class.
*
* @param string $class element class
* @param $class
*
* @return DOMElement[]
*/
@@ -337,9 +270,6 @@ class maintenance_static_page_generator {
return $matches;
}
/**
* Adds meta refresh to head element.
*/
private function add_meta_refresh() {
$meta = $this->dom->createElement('meta');
$meta->setAttribute('http-equiv', 'refresh');
@@ -352,7 +282,6 @@ class maintenance_static_page_generator {
}
/**
* Gets refresh time.
* @return int
*/
public function get_refresh_time() {
@@ -360,7 +289,6 @@ class maintenance_static_page_generator {
}
/**
* Sets refresh time.
* @param int $refreshtime
*/
public function set_refresh_time($refreshtime) {

View File

@@ -31,6 +31,8 @@ use finfo;
use invalid_parameter_exception;
use moodle_url;
defined('MOODLE_INTERNAL') || die();
/**
* maintenance_static_page_io class.
*
@@ -42,13 +44,11 @@ use moodle_url;
class maintenance_static_page_io {
/**
* Checks if the given string starts with "http://" or "https://".
* Also checks for "//" at the start of image, which setting_file_url still uses.
*
* @param string $url url string for check
* @param $url
* @return bool
*/
public static function is_url($url) {
return ((bool) preg_match('#^http(s)?://#', $url) || (bool) preg_match('#^//#', $url));
return (bool)preg_match('#^http(s)?://#', $url);
}
/**
@@ -80,7 +80,6 @@ class maintenance_static_page_io {
protected $preview = false;
/**
* Sets preview
* @param boolean $preview
*/
public function set_preview($preview) {
@@ -214,7 +213,7 @@ class maintenance_static_page_io {
/**
* Saves the content of the URL into a file, returning the local filename.
* @param string $url Input URL.
* @return array|null Output an array with the filename and url or null if skipped.
* @return string|null Output filename or null if skipped.
*/
public function save_url_file($url) {
global $CFG;

View File

@@ -28,6 +28,8 @@ namespace auth_outage\local;
use coding_exception;
use stdClass;
defined('MOODLE_INTERNAL') || die();
/**
* outage class.
*
@@ -279,17 +281,7 @@ class outage {
*/
private function adjust_field_types() {
// Adjust int fields.
$fs = [
'id',
'starttime',
'stoptime',
'warntime',
'finished',
'createdby',
'lastmodified',
'modifiedby',
];
$fs = ['createdby', 'id', 'lastmodified', 'modifiedby', 'starttime', 'stoptime', 'warntime', 'finished'];
foreach ($fs as $f) {
$this->$f = ($this->$f === null) ? null : (int)$this->$f;
}
@@ -297,12 +289,4 @@ class outage {
// Adjust bool fields.
$this->autostart = ($this->autostart === null) ? null : (bool)$this->autostart;
}
/**
* Return json encoded outage.
* @return string Json string.
*/
public function __toString() {
return json_encode(get_object_vars($this));
}
}

View File

@@ -29,7 +29,6 @@ use auth_outage\dml\outagedb;
use auth_outage\local\controllers\maintenance_static_page;
use auth_outage\output\renderer;
use coding_exception;
use curl;
use Exception;
use file_exception;
use invalid_parameter_exception;
@@ -48,72 +47,39 @@ require_once(__DIR__.'/../../lib.php');
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class outagelib {
/** Outage start. */
const OUTAGE_START = '<!-- OUTAGESTART -->';
/** Outage end. */
const OUTAGE_END = '<!-- OUTAGEEND -->';
/**
* @var bool Flags in the injection function was already called.
*/
private static $injectcalled = false;
/**
* Fetches page.
* @param string $file file to be fetched
*/
public static function fetch_page($file) {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$curl = new curl();
$contents = $curl->get($file);
$info = $curl->get_info();
if (!empty($info['content_type'])) {
$mime = $info['content_type'];
} else {
$mime = '';
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $file);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); // It is localhost, time to connect is enough.
curl_setopt($curl, CURLOPT_TIMEOUT, 15); // It is localhost, time to fetch index is enough.
$contents = curl_exec($curl);
$mime = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
curl_close($curl);
return compact('contents', 'mime');
}
/**
* Resets inject called to allow the code to be regenerated.
* Calls inject even if it was already called before.
*/
public static function reset_injectcalled() {
public static function reinject() {
self::$injectcalled = false;
self::inject();
}
/**
* Given a time, usually now, when is the next outage window?
* @param int $time time for next window
* Will check for ongoing or warning outages and will attach the message bar as required.
*/
public static function get_next_window($time = null) {
public static function inject() {
global $CFG;
$config = self::get_config();
if (!$time) {
$time = time();
}
$default = $config->default_time;
if ($default) {
// First try natural language parsing.
$time = strtotime($default, $time);
}
return $time;
}
/**
* Will check for ongoing or warning outages and will return the message bar as required.
*
* @return string|void CSS and HTML for the warning bar if it should be displayed
*/
public static function get_inject_code() {
global $PAGE;
// Ensure we do not kill the whole website in case of an error.
try {
// Check if we should inject the code.
@@ -143,8 +109,8 @@ class outagelib {
}
// There is a previewing or active outage.
$renderer = $PAGE->get_renderer('auth_outage');
return $renderer->render_warningbar($active, $time, false, $preview);
$CFG->additionalhtmltopofbody = renderer::get()->render_warningbar($active, $time, false, $preview).
$CFG->additionalhtmltopofbody;
} catch (Exception $e) {
debugging('Exception occured while injecting our code: '.$e->getMessage());
debugging($e->getTraceAsString(), DEBUG_DEVELOPER);
@@ -168,12 +134,7 @@ class outagelib {
}
}
$config = array_merge(self::get_config_defaults(), $config);
// Combine allowed IPs config values together.
if (isset($config['allowedips_forced'])) {
$config['allowedips'] = trim($config['allowedips'] . "\n" . $config['allowedips_forced']);
}
return (object)$config;
return (object)array_merge(self::get_config_defaults(), $config);
}
/**
@@ -184,7 +145,6 @@ class outagelib {
return [
'allowedips' => '',
'css' => '',
'default_time' => '',
'default_autostart' => '0',
'default_duration' => (string)(60 * 60),
'default_warning_duration' => (string)(60 * 60),
@@ -196,34 +156,18 @@ class outagelib {
/**
* Executed when outages are modified (created, updated or deleted).
*
* @param bool $reenablemaint should we re-enable maintenance mode for ongoing outage
* @throws coding_exception
* @throws file_exception
*/
public static function prepare_next_outage($reenablemaint = false) {
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();
$ongoingoutage = false;
} else {
$ongoingoutage = true;
}
// Set json formatted outage string to cache.
set_config('auth_outage_active_outage', (string)$outage);
maintenance_static_page::create_from_outage($outage)->generate();
self::update_climaintenance_code($outage);
if (!$ongoingoutage || $reenablemaint || is_null($outage)) {
self::update_maintenance_later($outage);
}
self::update_maintenance_later($outage);
}
/**
* Checks if wwwroot accessible.
*/
private static function check_wwwroot_accessible() {
global $CFG;
$result = self::fetch_page($CFG->wwwroot);
@@ -246,7 +190,6 @@ class outagelib {
unset_config('maintenance_message');
}
set_config('maintenance_later', $outage->starttime);
self::maintenance_config_log($outage);
}
}
@@ -303,16 +246,14 @@ class outagelib {
}
// 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 = addslashes($allowedips);
$allowedips = str_replace('\'"', '', $allowedips);
$code = <<<'EOT'
<?php
if ((time() >= {{STARTTIME}}) && (time() < {{STOPTIME}})) {
define('MOODLE_INTERNAL', true);
require_once($CFG->dirroot.'/lib/moodlelib.php');
if (file_exists($CFG->dirroot.'/lib/classes/ip_utils.php')) {
require_once($CFG->dirroot.'/lib/classes/ip_utils.php');
}
require_once($CFG->dirroot.'/lib/classes/ip_utils.php');
if (!remoteip_in_list('{{ALLOWEDIPS}}')) {
header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance');
header('Status: 503 Moodle under maintenance');
@@ -325,7 +266,6 @@ if ((time() >= {{STARTTIME}}) && (time() < {{STOPTIME}})) {
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');
header('X-Moodle-Maintenance: manager');
if ((defined('AJAX_SCRIPT') && AJAX_SCRIPT) || (defined('WS_SERVER') && WS_SERVER)) {
exit(0);
}
@@ -382,14 +322,16 @@ EOT;
* Generates a warning message in case the plugin is not active and configured.
*
* @return string
*
* @internal stdClass $CFG
* @internal bootstrap_renderer $OUTPUT
*/
public static function generate_plugin_configuration_warning() {
global $CFG, $OUTPUT, $PAGE;
global $CFG, $OUTPUT;
$message = [];
if (trim(self::get_config()->allowedips) != ''
&& (!isset($CFG->auth_outage_bootstrap_loaded) || !$CFG->auth_outage_bootstrap_loaded)) {
if (!isset($CFG->auth_outage_bootstrap_loaded) || !$CFG->auth_outage_bootstrap_loaded) {
$message[] = get_string('configurationwarning', 'auth_outage');
}
@@ -397,10 +339,8 @@ EOT;
$message[] = get_string('configurationdisabled', 'auth_outage');
}
if ($PAGE->pagetype == "admin-setting-auth_outage" || $PAGE->pagetype == "admin-setting-authsettingoutage") {
if (!self::check_wwwroot_accessible()) {
$message[] = get_string('configurationinaccessiblewwwroot', 'auth_outage', ['wwwroot' => $CFG->wwwroot]);
}
if (!self::check_wwwroot_accessible()) {
$message[] = get_string('configurationinaccessiblewwwroot', 'auth_outage', ['wwwroot' => $CFG->wwwroot]);
}
if (count($message) == 0) {
@@ -415,18 +355,4 @@ EOT;
return $message;
}
/**
* Logging for maintenance mode configuration.
*
* @param outage|null $outage Outage or null if no scheduled outage.
*/
private static function maintenance_config_log(outage $outage) {
mtrace(get_string('logformaintmodeconfig', 'auth_outage'));
$timezone = ' (Timezone ' . \core_date::get_server_timezone_object()->getName() . ')';
mtrace('... updated at ' . date('H:i:s'));
$time = date("Y-m-d H:i:s", $outage->starttime);
mtrace("... enable maintenance mode at $time $timezone");
mtrace(get_string('logformaintmodeconfigcomplete', 'auth_outage'));
}
}

View File

@@ -48,10 +48,6 @@ class base_table extends flexible_table {
*/
private static $autoid = 0;
/**
* Creates start time string.
* @param string $starttime start time
*/
protected static function create_starttime_string($starttime) {
$absolute = userdate($starttime, get_string('datetimeformat', 'auth_outage'));
$relative = $starttime - time();
@@ -88,7 +84,7 @@ class base_table extends flexible_table {
$buttons .= html_writer::link(
new moodle_url('/auth/outage/info.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->image_url('t/preview'),
'src' => $OUTPUT->pix_url('t/preview'),
'alt' => get_string('view'),
'class' => 'iconsmall',
@@ -104,7 +100,7 @@ class base_table extends flexible_table {
$buttons .= html_writer::link(
new moodle_url('/auth/outage/edit.php', ['edit' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->image_url('t/edit'),
'src' => $OUTPUT->pix_url('t/edit'),
'alt' => get_string('edit'),
'class' => 'iconsmall',
]),
@@ -116,7 +112,7 @@ class base_table extends flexible_table {
$buttons .= html_writer::link(
new moodle_url('/auth/outage/edit.php', ['clone' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->image_url('t/copy'),
'src' => $OUTPUT->pix_url('t/copy'),
'alt' => get_string('clone', 'auth_outage'),
'class' => 'iconsmall',
@@ -129,7 +125,7 @@ class base_table extends flexible_table {
$buttons .= html_writer::link(
new moodle_url('/auth/outage/finish.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->image_url('t/check'),
'src' => $OUTPUT->pix_url('t/check'),
'alt' => get_string('finish', 'auth_outage'),
'class' => 'iconsmall',
]),
@@ -142,7 +138,7 @@ class base_table extends flexible_table {
$buttons .= html_writer::link(
new moodle_url('/auth/outage/delete.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->image_url('t/delete'),
'src' => $OUTPUT->pix_url('t/delete'),
'alt' => get_string('delete'),
'class' => 'iconsmall',
]),

View File

@@ -26,13 +26,14 @@
namespace auth_outage\output;
use auth_outage\local\outage;
use auth_outage\local\outagelib;
use coding_exception;
use core_user;
use html_writer;
use moodle_url;
use plugin_renderer_base;
defined('MOODLE_INTERNAL') || die();
/**
* auth_outage_renderer class.
*
@@ -42,6 +43,15 @@ use plugin_renderer_base;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class renderer extends plugin_renderer_base {
/**
* Returns the outage renderer.
* @return renderer The outage renderer.
*/
public static function get() {
global $PAGE;
return $PAGE->get_renderer('auth_outage');
}
/**
* Outputs the view in a separate scope to avoid conflicts with variable names.
* @param string $view View PHP file.
@@ -64,13 +74,6 @@ class renderer extends plugin_renderer_base {
* @return string The rendered view code.
*/
public function render_view($view, $viewbag = []) {
// Do not render if the request are from some layouts.
$excludelayout = ['embedded', 'popup', 'secure', 'maintenance'];
if (in_array($this->page->pagelayout, $excludelayout)) {
return '';
}
ob_start();
$this->output_view($view, $viewbag);
$html = ob_get_contents();
@@ -150,6 +153,8 @@ class renderer extends plugin_renderer_base {
* @return string The formatted HTML.
*/
private function renderoutage(outage $outage, $buttons) {
global $OUTPUT;
if ($outage->createdby == 0) {
$created = get_string('na', 'auth_outage');
} else {
@@ -173,14 +178,14 @@ class renderer extends plugin_renderer_base {
$url = new moodle_url('/auth/outage/edit.php', ['edit' => $outage->id]);
$img = html_writer::empty_tag(
'img',
['src' => $this->output->image_url('t/edit'), 'alt' => get_string('edit'), 'class' => 'iconsmall']
['src' => $OUTPUT->pix_url('t/edit'), 'alt' => get_string('edit'), 'class' => 'iconsmall']
);
$linkedit = html_writer::link($url, $img, ['title' => get_string('edit')]);
$url = new moodle_url('/auth/outage/delete.php', ['id' => $outage->id]);
$img = html_writer::empty_tag(
'img',
['src' => $this->output->image_url('t/delete'), 'alt' => get_string('delete'), 'class' => 'iconsmall']
['src' => $OUTPUT->pix_url('t/delete'), 'alt' => get_string('delete'), 'class' => 'iconsmall']
);
$linkdelete = html_writer::link($url, $img, ['title' => get_string('delete')]);
@@ -191,38 +196,35 @@ class renderer extends plugin_renderer_base {
$finished = userdate($finished, get_string('datetimeformat', 'auth_outage'));
}
$start = outagelib::OUTAGE_START;
$end = outagelib::OUTAGE_END;
$outagehtml = html_writer::div(
return 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', get_string('tableheaderwarnbefore', 'auth_outage').': ').
format_time($outage->get_warning_duration())
).
html_writer::div(
html_writer::tag('b', get_string('tableheaderstarttime', 'auth_outage').': ').
userdate($outage->starttime, get_string('datetimeformat', 'auth_outage'))
).
html_writer::div(
html_writer::tag('b', get_string('tableheaderdurationplanned', 'auth_outage').': ').
format_time($outage->get_duration_planned())
).
html_writer::div(
html_writer::tag('b', get_string('tableheaderdurationactual', 'auth_outage').': ').
$finished
).
html_writer::div(
html_writer::tag('small',
'Created by '.$created.
', modified by '.$modified.' on '.
userdate($outage->lastmodified, get_string('datetimeformat', 'auth_outage'))
)
).
($buttons ? html_writer::div($linkedit.$linkdelete) : '')
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', get_string('tableheaderwarnbefore', 'auth_outage').': ').
format_time($outage->get_warning_duration())
).
html_writer::div(
html_writer::tag('b', get_string('tableheaderstarttime', 'auth_outage').': ').
userdate($outage->starttime, get_string('datetimeformat', 'auth_outage'))
).
html_writer::div(
html_writer::tag('b', get_string('tableheaderdurationplanned', 'auth_outage').': ').
format_time($outage->get_duration_planned())
).
html_writer::div(
html_writer::tag('b', get_string('tableheaderdurationactual', 'auth_outage').': ').
$finished
).
html_writer::div(
html_writer::tag('small',
'Created by '.$created.
', modified by '.$modified.' on '.
userdate($outage->lastmodified, get_string('datetimeformat', 'auth_outage'))
)
).
($buttons ? html_writer::div($linkedit.$linkdelete) : '')
)
);
return $start . $outagehtml . $end;
}
}

View File

@@ -23,6 +23,8 @@
namespace auth_outage\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\local\legacy_polyfill;
/**

View File

@@ -29,6 +29,8 @@ use auth_outage\local\controllers\infopage;
use auth_outage\local\outagelib;
use core\task\scheduled_task;
defined('MOODLE_INTERNAL') || die();
/**
* update_static_page class.
*

View File

@@ -1,37 +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/>.
/**
* Define capabilities for plugin.
*
* @package auth_outage
* @author Andrew Madden <andrewmadden@catalyst-au.net>
* @copyright 2021 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = [
'auth/outage:viewinfo' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => array(
'guest' => CAP_ALLOW,
'user' => CAP_ALLOW,
)
),
];

View File

@@ -24,11 +24,14 @@
*/
use auth_outage\local\controllers\maintenance_static_page;
defined('MOODLE_INTERNAL') || die();
/**
* Auth Outage plugin uninstall code.
* @return bool result
* @throws moodle_exception
*/
function xmldb_auth_outage_uninstall() {
global $DB;

View File

@@ -22,6 +22,7 @@
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Outage plugin upgrade code

View File

@@ -33,7 +33,6 @@ require_once($CFG->libdir.'/formslib.php');
admin_externalpage_setup('auth_outage_manage');
$PAGE->set_url(new moodle_url('/auth/outage/manage.php'));
$output = $PAGE->get_renderer('auth_outage');
$mform = new delete();
if ($mform->is_cancelled()) {
@@ -53,10 +52,10 @@ $dataid = new stdClass();
$dataid->id = $outage->id;
$mform->set_data($dataid);
echo $output->header();
echo $OUTPUT->header();
echo $output->renderdeleteconfirmation($outage);
echo renderer::get()->renderdeleteconfirmation($outage);
$mform->display();
echo $output->footer();
echo $OUTPUT->footer();

View File

@@ -34,7 +34,6 @@ require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/formslib.php');
admin_externalpage_setup('auth_outage_manage');
$output = $PAGE->get_renderer('auth_outage');
$PAGE->set_url(new moodle_url('/auth/outage/manage.php'));
$mform = new edit();
@@ -43,12 +42,11 @@ if ($mform->is_cancelled()) {
redirect(new moodle_url('/auth/outage/manage.php'));
} else if ($outage = $mform->get_data()) {
$id = outagedb::save($outage);
redirect(new moodle_url('/auth/outage/manage.php'));
redirect($CFG->wwwroot. '/auth/outage/manage.php#auth_outage_id_'.$id);
}
$clone = optional_param('clone', 0, PARAM_INT);
$edit = optional_param('edit', 0, PARAM_INT);
$time = optional_param('starttime', 0, PARAM_INT);
if ($clone && $edit) {
throw new invalid_parameter_exception('Cannot provide both clone and edit ids.');
}
@@ -62,10 +60,7 @@ if ($clone) {
$action = 'outageedit';
} else {
$config = outagelib::get_config();
if (empty($time)) {
$time = outagelib::get_next_window();
}
$time = time();
$outage = new outage([
'autostart' => $config->default_autostart,
'starttime' => $time,
@@ -84,7 +79,7 @@ if ($outage == null) {
$mform->set_data($outage);
$PAGE->navbar->add(get_string($action.'crumb', 'auth_outage'));
echo $output->header();
echo $output->rendersubtitle($action);
echo $OUTPUT->header();
echo renderer::get()->rendersubtitle($action);
$mform->display();
echo $output->footer();
echo $OUTPUT->footer();

View File

@@ -57,6 +57,7 @@ header('Accept-Ranges: none');
/**
* Callback used in bootstrap.
* @SupressWarnings(PHPMD)
*/
function auth_outage_bootstrap_callback() {
// Not using classes as classloader has not been initialized yet. Keep it minimalist.
@@ -73,9 +74,7 @@ function auth_outage_bootstrap_callback() {
exit(0);
}
// @codingStandardsIgnoreStart
require_once(__DIR__.'/../../config.php');
// @codingStandardsIgnoreEnd
// We should never reach here if config.php and auth/outage/bootstrap.php intercepted it correctly.
// If config.php did not execute the callback function we can use the debugging function here.

View File

@@ -33,7 +33,6 @@ require_once($CFG->libdir.'/formslib.php');
admin_externalpage_setup('auth_outage_manage');
$PAGE->set_url(new moodle_url('/auth/outage/manage.php'));
$output = $PAGE->get_renderer('auth_outage');
$mform = new finish();
if ($mform->is_cancelled()) {
@@ -53,10 +52,10 @@ $dataid = new stdClass();
$dataid->id = $outage->id;
$mform->set_data($dataid);
echo $output->header();
echo $OUTPUT->header();
echo $output->renderfinishconfirmation($outage);
echo renderer::get()->renderfinishconfirmation($outage);
$mform->display();
echo $output->footer();
echo $OUTPUT->footer();

View File

@@ -25,9 +25,7 @@
use auth_outage\local\controllers\infopage;
// @codingStandardsIgnoreStart
require_once(__DIR__.'/../../config.php');
// @codingStandardsIgnoreEnd
$info = new infopage();
$info->output();

View File

@@ -26,10 +26,7 @@
$string['auth_outagedescription'] = 'Auxiliary plugin that warns users about a future outage and prevents them from logging in once the outage starts.';
$string['autostart'] = 'Auto start maintenance mode.';
$string['autostart_help'] = 'If selected, when the outage starts it will automatically turn on Moodle maintenance mode.';
$string['builtinallowediplist'] = 'Builtin Allowed IP List';
$string['builtinallowediplist_desc'] = 'A second allowed IP list which makes it easier to have some IPs forced in config.php and others editable in the UI';
$string['clicreatehelp'] = 'Creates a new outage.';
$string['clicreateexamples'] = "Create an outage starting in 10 seconds\n\n> php create.php -s=10";
$string['clicreateparamautostart'] = 'must be Y or N, sets if the outage automatically triggers maintenance mode.';
$string['clicreateparamblock'] = 'blocks until outage starts.';
$string['clicreateparamclone'] = 'clone another outage except for the start time.';
@@ -41,7 +38,6 @@ $string['clicreateparamstart'] = 'in how many seconds should this outage start o
$string['clicreateparamtitle'] = 'the title of the outage.';
$string['clicreateparamwarn'] = 'how many seconds before it starts to display a warning.';
$string['clifinishhelp'] = 'Finishes an ongoing outage.';
$string['clifinishexamples'] = '';
$string['clifinishnotongoing'] = 'Outage is not ongoing.';
$string['clifinishparamhelp'] = 'shows parameters help.';
$string['clifinishparamactive'] = 'finishes the currently active outage.';
@@ -49,7 +45,6 @@ $string['clifinishparamoutageid'] = 'the id of the outage to finish.';
$string['cliinmaintenancemode'] = 'Moodle maintenance mode is on. Use "php admin/cli/maintenance.php --disable" to disable it before finishing the outage.';
$string['cliwaitforiterroridxoractive'] = 'You must use --outageid=# or --active parameter but not both.';
$string['cliwaitforithelp'] = 'Waits until an outage starts.';
$string['cliwaitforitexamples'] = '';
$string['cliwaitforitoutagestarted'] = 'Outage started!';
$string['cliwaitforitoutagestartingin'] = 'Outage starting in {$a->countdown}.';
$string['cliwaitforitparamactive'] = 'wait for the currently active outage.';
@@ -58,12 +53,6 @@ $string['cliwaitforitparamoutageid'] = 'the id of the outage to wait until it st
$string['cliwaitforitparamsleep'] = 'maximum amount of seconds before status output.';
$string['cliwaitforitparamverbose'] = 'enable verbose mode.';
$string['clierrorinvalidvalue'] = 'Invalid value for parameter: {$a->param}';
$string['clierrorinvalidvaluenotid'] = 'Param --{$a->param} must be an id number';
$string['clierrorinvalidvaluenotbool'] = 'Param --{$a->param} must be set to either Y or N';
$string['clierrorinvalidvaluenotnumber'] = 'Param --{$a->param} must be a number';
$string['clierrorinvalidvaluenegativenumber'] = 'Param --{$a->param} must be a positive number';
$string['clierrorinvalidvaluenotstring'] = 'Param --{$a->param} must be a string';
$string['clierrorinvalidvalueemptystring'] = 'Param --{$a->param} must not be an empty string';
$string['clierrormissingparamaters'] = 'You must specify the start time, use --help for more information.';
$string['clierroroutagechanged'] = 'Outage was changed while waiting.';
$string['clierroroutageended'] = 'Outage has already ended.';
@@ -82,11 +71,9 @@ $string['defaultoutageduration'] = 'Outage duration';
$string['defaultoutagedurationdescription'] = 'Default duration (in minutes) of an outage.';
$string['defaultwarningduration'] = 'Warning duration';
$string['defaultwarningdurationdescription'] = 'Default warning time (in minutes) for outages.';
$string['defaulttime'] = 'Default time';
$string['defaulttimedescription'] = 'The default time for the next outage, expressed in natural language eg "next Thursday 7pm". See <a target=_blank href="https://www.php.net/manual/en/datetime.formats.relative.php">PHP relative dates</a>';
$string['defaulttitle'] = 'Title';
$string['defaulttitledescription'] = 'Default title for outages. Use {{start}} and {{stop}} placeholders as required.';
$string['defaulttitlevalue'] = 'System down from {{start}} for {{duration}}';
$string['defaulttitlevalue'] = 'System down from {{start}} for {{duration}}.';
$string['defaultdescription'] = 'Description';
$string['defaultdescriptiondescription'] = 'Default warning message for outages. Use {{start}} and {{stop}} placeholders as required.';
$string['defaultdescriptionvalue'] = 'There is an scheduled maintenance from {{start}} to {{stop}} and our system will not be available during that time.';
@@ -102,22 +89,18 @@ $string['infostart'] = 'start';
$string['infostartofwarning'] = 'start of warning';
$string['infostaticpage'] = 'static page';
$string['infopagestaticgenerated'] = 'This warning was generated on {$a->time}.';
$string['ips_combine'] = 'The IPs listed above will be combined with the IPs listed below.';
$string['allowedipsempty'] = 'When the allowed IPs list is empty we will not block anyone. You can add your own IP address (<i>{$a->ip}</i>) and block all other IPs.';
$string['allowedipshasmyip'] = 'Your IP (<i>{$a->ip}</i>) is in the list and you will not be blocked out during an Outage.';
$string['allowedipshasntmyip'] = 'Your IP (<i>{$a->ip}</i>) 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.<br />Please refer to our <a href="https://github.com/catalyst/moodle-auth_outage#installation" target="_blank">README.md</a> file for more information.';
$string['logformaintmodeconfig'] = 'Update maintenance mode configuration.';
$string['logformaintmodeconfigcomplete'] = 'Updating maintenance mode configuration complete.';
$string['menusettings'] = 'Settings';
$string['menumanage'] = 'Manage outages';
$string['menumanage'] = 'Manage';
$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['na'] = 'n/a';
$string['notfound'] = 'No outages found.';
$string['outage:viewinfo'] = 'View outage info';
$string['outageedit'] = 'Edit outage';
$string['outageeditcrumb'] = 'Edit';
$string['outageclone'] = 'Clone outage';
@@ -133,7 +116,6 @@ $string['outagefinish'] = 'Finish outage';
$string['outagefinishwarning'] = 'You are about to mark this outage as finished. The system will be immediately back online.';
$string['outageslistfuture'] = 'Planned outages';
$string['outageslistpast'] = 'Outage history';
$string['outage:updatenotify'] = '';
$string['pluginname'] = 'Outage manager';
$string['removeselectors'] = 'Remove selectors';
$string['removeselectorsdescription'] = 'CSS selectors to remove when rendering a static themed maintenance page. One selector per line.';
@@ -161,7 +143,6 @@ $string['title_help'] = 'A short title to for this outage. It will be displayed
$string['warningdurationerrorinvalid'] = 'Warning duration must be positive.';
$string['warningduration'] = 'Warning duration';
$string['warningduration_help'] = 'How long before the start of the outage should the warning be displayed.';
$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)

46
lib.php
View File

@@ -25,6 +25,29 @@
use auth_outage\local\outagelib;
defined('MOODLE_INTERNAL') || die;
/**
* Used in Moodle 30+ when a user is logged on.
*/
function auth_outage_extend_navigation_user_settings() {
outagelib::inject();
}
/**
* Used in Moodle 30+ on the frontpage.
*/
function auth_outage_extend_navigation_frontpage() {
outagelib::inject();
}
/**
* Used in Moodle 31+ when a user is logged on.
*/
function auth_outage_extend_navigation_user() {
outagelib::inject();
}
/**
* Used for adminlib::set_updatedcallback which requires a string that resolves to a function.
*
@@ -39,7 +62,7 @@ function auth_outage_outagelib_prepare_next_outage() {
*
* To keep it minimalist it was not added to the outagelib.php class.
*
* @param string $file Filename to fetch from sitedata
* @param $file string Filename to fetch from sitedata
* @return string|null Full path to the sitedata file or null if file is not valid.
*/
function auth_outage_get_climaintenance_resource_file($file) {
@@ -64,24 +87,3 @@ function auth_outage_get_climaintenance_resource_file($file) {
$realpath = realpath($resourcedir.'/'.$file);
return ($realpath == false) ? null : $realpath;
}
/**
* Display required icon for the calendar events.
*
* @return array
*/
function auth_outage_get_fontawesome_icon_map() {
return [
'core:i/auth_outageevent' => 'fa-power-off',
];
}
/**
* Inject the warning bar into the page if there is currently an outage.
*
* @return string|void
*/
function auth_outage_before_standard_top_of_body_html() {
// Get code to inject.
return outagelib::get_inject_code();
}

View File

@@ -32,17 +32,16 @@ require_once($CFG->libdir.'/adminlib.php');
admin_externalpage_setup('auth_outage_manage');
$PAGE->set_url(new moodle_url('/auth/outage/manage.php'));
$output = $PAGE->get_renderer('auth_outage');
echo $output->header();
echo $OUTPUT->header();
// Give it a consistent time so all outages are listed. Useful when debugging.
$now = time();
$output->output_view('manage.php', [
renderer::get()->output_view('manage.php', [
'unended' => outagedb::get_all_unended($now),
'ended' => outagedb::get_all_ended($now),
'warning' => outagelib::generate_plugin_configuration_warning(),
]);
echo $output->footer();
echo $OUTPUT->footer();

View File

@@ -28,9 +28,7 @@
use auth_outage\dml\outagedb;
use auth_outage\local\controllers\maintenance_static_page;
// @codingStandardsIgnoreStart
require_once(__DIR__.'/../../config.php');
// @codingStandardsIgnoreEnd
$id = optional_param('id', null, PARAM_INT);
$outage = is_null($id) ? outagedb::get_next_starting() : outagedb::get_by_id($id);
if (is_null($outage)) {

View File

@@ -26,6 +26,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* auth_outage_renderer class.
*

View File

@@ -26,30 +26,25 @@
* @var admin_settingpage $settings
* @var bootstrap_renderer $OUTPUT
* @var admin_root $ADMIN
* @var moodle_page $PAGE
*/
use auth_outage\local\outagelib;
defined('MOODLE_INTERNAL') || die;
if ($hassiteconfig) {
if ($hassiteconfig && is_enabled_auth('outage')) {
$defaults = outagelib::get_config_defaults();
$settings->visiblename = get_string('menusettings', 'auth_outage');
$description = outagelib::generate_plugin_configuration_warning();
$settings->add(new admin_setting_heading(
'defaults',
get_string('settingssectiondefaults', 'auth_outage'),
get_string('settingssectiondefaultsdescription', 'auth_outage') . $description
));
get_string('settingssectiondefaultsdescription', 'auth_outage')));
$settings->add(new admin_setting_configcheckbox(
'auth_outage/default_autostart',
get_string('defaultoutageautostart', 'auth_outage'),
get_string('defaultoutageautostartdescription', 'auth_outage'),
$defaults['default_autostart']
));
$settings->add(new admin_setting_configduration(
'auth_outage/default_warning_duration',
get_string('defaultwarningduration', 'auth_outage'),
@@ -64,13 +59,6 @@ if ($hassiteconfig) {
$defaults['default_duration'],
60
));
$settings->add(new admin_setting_configtext(
'auth_outage/default_time',
get_string('defaulttime', 'auth_outage'),
get_string('defaulttimedescription', 'auth_outage'),
'',
PARAM_TEXT
));
$settings->add(new admin_setting_configtext(
'auth_outage/default_title',
get_string('defaulttitle', 'auth_outage'),
@@ -101,23 +89,20 @@ if ($hassiteconfig) {
// Create 'Allowed IPs' settings.
$allowedips = outagelib::get_config()->allowedips;
$description = outagelib::generate_plugin_configuration_warning();
if (trim($allowedips) == '') {
$message = 'allowedipsempty';
$type = 'notifymessage';
} else if (remoteip_in_list($allowedips)) {
$message = 'allowedipshasmyip';
$type = 'notifysuccess';
} else {
if (remoteip_in_list($allowedips)) {
$message = 'allowedipshasmyip';
$type = 'notifysuccess';
} else {
$message = 'allowedipshasntmyip';
$type = 'notifyerror';
}
$message = 'allowedipshasntmyip';
$type = 'notifyerror';
};
$description = $OUTPUT->notification(get_string($message, 'auth_outage', ['ip' => getremoteaddr()]), $type);
$description .= '<p>' . get_string('ipblockersyntax', 'admin') . '</p>';
$description .= '<p>' . get_string('ips_combine', 'auth_outage') . '</p>';
$description .= $OUTPUT->notification(get_string($message, 'auth_outage', ['ip' => getremoteaddr()]), $type);
$description .= '<p>'.get_string('ipblockersyntax', 'admin').'</p>';
$iplist = new admin_setting_configiplist(
'auth_outage/allowedips',
get_string('allowediplist', 'admin'),
@@ -127,14 +112,6 @@ if ($hassiteconfig) {
$iplist->set_updatedcallback('auth_outage_outagelib_prepare_next_outage');
$settings->add($iplist);
$iplist = new admin_setting_configiplist(
'auth_outage/allowedips_forced',
get_string('builtinallowediplist', 'auth_outage'),
get_string('builtinallowediplist_desc', 'auth_outage'),
''
);
$settings->add($iplist);
// Create 'Static Page - Elements to Remove' settings.
$toremove = new admin_setting_configtextarea(
'auth_outage/remove_selectors',
@@ -156,7 +133,7 @@ if ($hassiteconfig) {
new admin_externalpage(
'auth_outage_manage',
get_string('menumanage', 'auth_outage'),
new moodle_url($CFG->wwwroot . '/auth/outage/manage.php')
new moodle_url($CFG->wwwroot.'/auth/outage/manage.php')
)
);
}

View File

@@ -39,6 +39,7 @@ require_once(__DIR__.'/../../../../lib/behat/behat_base.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class behat_auth_outage extends behat_base {
/**
@@ -154,7 +155,6 @@ class behat_auth_outage extends behat_base {
}
/**
* Check if an specific action is not visible.
* @Then /^I should see an empty settings text area "([^"]*)"$/
* @param string $name
*/
@@ -163,7 +163,6 @@ class behat_auth_outage extends behat_base {
}
/**
* Check if an specific action is not visible.
* @When /^I go to the "Outage Settings" page$/
*/
public function i_go_to_the_outage_settings_page() {
@@ -322,7 +321,7 @@ class behat_auth_outage extends behat_base {
}
if ($seconds >= 0) {
$seconds++; // Give one extra second for things to happen.
$this->getSession()->wait($seconds * 1000);
$this->getSession()->wait($seconds * 1000, false);
}
}

View File

@@ -11,8 +11,9 @@ Feature: Change the default settings
Given the authentication plugin "outage" is enabled
And I am an administrator
Scenario Outline: Check if I can save the default settings.
When I navigate to "Plugins > Authentication > Outage manager > Settings" in site administration
When I navigate to "Settings" node in "Site administration > Plugins > Authentication > Outage manager"
And I set the following fields to these values:
| s_auth_outage_default_autostart | <autostart> |
| s_auth_outage_default_warning_duration[v] | <warning> |

View File

@@ -1,48 +0,0 @@
@auth @auth_outage @javascript @_file_upload @_switch_iframe
Feature: Disable warning bar in embedded layout
In order alert users about an outage
As any user
I need to view the warning bar, but not in embedded layout
Background:
Given the authentication plugin "outage" is enabled
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "activities" exist:
| activity | name | intro | introformat | course | content | contentformat | idnumber |
| page | PageName1 | PageDesc1 | 1 | C1 | H5Ptest | 1 | 1 |
And the "displayh5p" filter is "on"
Scenario: Disable warning bar in embedded h5p in book activity
Given I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add a "File" to section "1"
And I set the following fields to these values:
| Name | ipsumFile |
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "Select files" filemanager
And I press "Save and return to course"
And I follow "PageName1"
And I navigate to "Edit settings" in current page administration
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
And I click on "Server files" "link" in the ".fp-repo-area" "css_element"
And I click on "ipsumFile (File)" "link"
And I click on "ipsums.h5p" "link"
And I click on "Select this file" "button"
And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
And I wait until the page is ready
And I click on "Save and display" "button"
When there is the following outage:
| warnbefore | startsin |
| 0 | 0 |
And I reload the page
Then I should see "Back online at" in the warning bar
And I should not see "Lorum ipsum"
# Switch to iframe created by filter
And I switch to "h5p-iframe" class iframe
And I should not see the warning bar
# Switch to iframe created by embed.php page
And I switch to "h5p-iframe" class iframe
And I should see "Lorum ipsum"
And I should not see the warning bar

View File

@@ -8,11 +8,14 @@ Feature: IP Blocker
- 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
When I navigate to "Plugins > Authentication > Outage manager > Settings" in site administration
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"

View File

@@ -11,19 +11,22 @@ Feature: Manage outages
- finished is an outage that has explicitly been marked as finished.
- stopped is an outage that has already ended but not explicitly marked as finished.
Background: Always login as admin, enable the auth_outage plugin and go to the outage management page.
Given the authentication plugin "outage" is enabled
And I log in as "admin"
And I wait "1" seconds
Scenario: Check if I can navigate to management page.
Given I am on homepage
When I navigate to "Plugins > Authentication > Outage manager > Manage outages" in site administration
When I navigate to "Manage" node in "Site administration > Plugins > Authentication > Outage manager"
Then I should see "Planned outages"
And I should see "No outages found." in the "#section_planned_outages" "css_element"
And I should see "Outage history"
And I should see "No outages found." in the "#section_outage_history" "css_element"
Scenario Outline: Planned outages should include all outages not finished or stopped.
Given there is a "<type>" outage
When I am on Outage Management Page
@@ -37,6 +40,7 @@ Feature: Manage outages
| finished | outage_history |
| stopped | outage_history |
Scenario Outline: Planned and history outages have different actions.
Given there is a "<type>" outage
When I am on Outage Management Page
@@ -55,12 +59,14 @@ Feature: Manage outages
| finished | see | see | not see | not see | not see |
| stopped | see | see | not see | not see | not see |
Scenario: Create an outage using defaults.
Given I am on Outage Management Page
When I press "Create outage"
And I press "Save changes"
And I should not see "No outages found." in the "#section_planned_outages" "css_element"
And I should see "No outages found." in the "#section_outage_history" "css_element"
# Scenario: Create an outage using defaults.
# Given I am on Outage Management Page
# When I press "Create outage"
# And I press "Save changes"
# And I should not see "No outages found." in the "#section_planned_outages" "css_element"
# And I should see "No outages found." in the "#section_outage_history" "css_element"
Scenario: View an outage which should open in a new window or tab.
Given there is a "waiting" outage
@@ -69,26 +75,29 @@ Feature: Manage outages
Then I should be in a new window
And I should see "Example of waiting outage"
Scenario: Clone an outage.
Given there is a "waiting" outage
And I am on Outage Management Page
When I click on the "Clone" action button
Then I should see "Clone outage"
And I set the field "title" to "My cloned outage"
And I press "Save changes"
Then I should see "Example of waiting outage"
And I should see "My cloned outage"
Scenario: Edit an outage.
Given there is a "warning" outage
And I am on Outage Management Page
And I should see "Example of warning outage"
When I click on the "Edit" action button
Then I should see "Edit outage"
And I set the field "title" to "My previous warning outage"
And I press "Save changes"
Then I should not see "Example of warning outage"
And I should see "My previous warning outage"
# Scenario: Clone an outage.
# Given there is a "waiting" outage
# And I am on Outage Management Page
# When I click on the "Clone" action button
# Then I should see "Clone outage"
# And I set the field "title" to "My cloned outage"
# And I press "Save changes"
# Then I should see "Example of waiting outage"
# And I should see "My cloned outage"
# Scenario: Edit an outage.
# Given there is a "warning" outage
# And I am on Outage Management Page
# And I should see "Example of warning outage"
# When I click on the "Edit" action button
# Then I should see "Edit outage"
# And I set the field "title" to "My previous warning outage"
# And I press "Save changes"
# Then I should not see "Example of warning outage"
# And I should see "My previous warning outage"
Scenario: Delete an outage
Given there is a "warning" outage
@@ -100,6 +109,7 @@ Feature: Manage outages
Then I press "Delete"
And I should not see "Example of warning outage"
Scenario: Finish an outage
Given there is a "ongoing" outage
And I am on Outage Management Page

View File

@@ -11,45 +11,46 @@ Feature: Warning bar
- finished is an outage that has explicitly been marked as finished.
- stopped is an outage that has already ended but not explicitly marked as finished.
Background:
Given the authentication plugin "outage" is enabled
Scenario: This is how an outage should happen without maintenance mode and manual finish.
Given there is the following outage:
| warnbefore | startsin | stopsafter |
| 10 | 20 | 10 |
When I am on homepage
Then I should not see the warning bar
When I wait until the outage warns
And I reload the page
Then I should see "Shutting down in" in the warning bar
When I wait until the outage starts
And I reload the page
Then I should see "Back online at" in the warning bar
When I wait until the outage stops
Then I should see "We are back online!" in the warning bar
When I reload the page
Then I should not see the warning bar
#
#
# Scenario Outline: Some stages should show its own warning message.
# Given there is a "<type>" outage
# When I am on homepage
# Then I should see "<see>" in the warning bar
#
# Examples:
# | type | see |
# | warning | Shutting down in |
# | ongoing | Back online at |
#
#
# Scenario Outline: Some stages should not have a warning bar.
# Given there is a "<type>" outage
# Scenario: This is how an outage should happend without maintenance mode and manual finish.
# Given there is the following outage:
# | warnbefore | startsin | stopsafter |
# | 10 | 20 | 10 |
# When I am on homepage
# Then I should not see the warning bar
#
# Examples:
# | type |
# | waiting |
# | finished |
# | stopped |
# When I wait until the outage warns
# And I reload the page
# Then I should see "Shutting down in" in the warning bar
# When I wait until the outage starts
# Then I should see "Back online at" in the warning bar
# When I wait until the outage stops
# Then I should see "We are back online!" in the warning bar
# When I reload the page
# Then I should not see the warning bar
Scenario Outline: Some stages should show its own warning message.
Given there is a "<type>" outage
When I am on homepage
Then I should see "<see>" in the warning bar
Examples:
| type | see |
| warning | Shutting down in |
| ongoing | Back online at |
Scenario Outline: Some stages should not have a warning bar.
Given there is a "<type>" outage
When I am on homepage
Then I should not see the warning bar
Examples:
| type |
| waiting |
| finished |
| stopped |

View File

@@ -31,8 +31,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use auth_outage\dml\outagedb;
use auth_outage\local\outage;
defined('MOODLE_INTERNAL') || die();
/**
* auth_outage_base_testcase class.
@@ -41,6 +40,7 @@ use auth_outage\local\outage;
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
abstract class auth_outage_base_testcase extends advanced_testcase {
/**
@@ -64,55 +64,15 @@ abstract class auth_outage_base_testcase extends advanced_testcase {
}
}
/**
* Revoke permission to see info page.
*/
protected function revoke_info_page_permissions() {
global $DB;
$guestrole = $DB->get_record('role', array('shortname' => 'guest'));
role_change_permission($guestrole->id, context_system::instance(), 'auth/outage:viewinfo', CAP_PREVENT);
$this->setGuestUser();
}
/**
* Get an outage object.
*
* @return \auth_outage\local\outage
*/
protected function get_dummy_outage() {
$now = time();
return new outage([
'id' => 1,
'autostart' => false,
'warntime' => $now - 100,
'starttime' => $now + 100,
'stoptime' => $now + 200,
'title' => 'Title',
'description' => 'Description',
]);
}
/**
* Setup testcase.
*/
public function setUp(): void {
public function setUp() {
global $CFG;
parent::setUp();
$this->resetAfterTest(true);
}
/**
* Tear down to restore the original DB reference.
*/
public function tearDown(): void {
public function tearDown() {
global $DB;
foreach (outagedb::get_all() as $i => $outage) {
$DB->delete_records('auth_outage', ['id' => $outage->id]);
}
$DB->delete_records('auth_outage');
}
}

View File

@@ -26,6 +26,8 @@
use auth_outage\calendar\calendar;
use auth_outage\local\outage;
defined('MOODLE_INTERNAL') || die();
/**
* calendar_test test class.
*
@@ -37,7 +39,7 @@ use auth_outage\local\outage;
* @copyright Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_outage_calendar_test extends advanced_testcase {
class calendar_test extends advanced_testcase {
/**
* @var outage|null The calendar entry owner.
*/
@@ -132,8 +134,8 @@ class auth_outage_calendar_test extends advanced_testcase {
]);
calendar::update($outage);
self::assertCount(1, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(1, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**
@@ -144,8 +146,8 @@ class auth_outage_calendar_test extends advanced_testcase {
self::setAdminUser();
calendar::delete(1);
self::assertCount(1, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(1, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**

View File

@@ -36,8 +36,9 @@ require_once(__DIR__.'/../base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_outagedb_test extends auth_outage_base_testcase {
class outagedb_test extends auth_outage_base_testcase {
/**
* Creates an array of ids in from the given outages array.
* @param outage[] $outages An array of outages.
@@ -78,7 +79,7 @@ class auth_outage_outagedb_test extends auth_outage_base_testcase {
/**
* Ensure DB tests run as admin.
*/
public function setUp(): void {
public function setUp() {
parent::setUp();
$this->setAdminUser();
}
@@ -244,15 +245,6 @@ class auth_outage_outagedb_test extends auth_outage_base_testcase {
$activeid = self::saveoutage(false, $now, -2, 1, 2, 'An outage in warning period.');
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
$activeid = self::saveoutage(false, $now, -2, 0, 2, 'An outage starts now.');
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
self::saveoutage(false, $now, -2, 0, -1, 'Invalid outage.');
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
self::saveoutage(false, $now, -2, 0, 0, 'Invalid outage.');
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
self::saveoutage(false, $now, -1, 2, 3,
'Another outage in warning period, but ignored as it starts after the previous one.');
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
@@ -436,8 +428,8 @@ class auth_outage_outagedb_test extends auth_outage_base_testcase {
public function test_finish_now_notfound() {
$this->resetAfterTest(true);
outagedb::finish(1);
self::assertCount(1, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(1, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**
@@ -458,8 +450,8 @@ class auth_outage_outagedb_test extends auth_outage_base_testcase {
self::assertTrue(!$outage->is_ongoing($time));
outagedb::finish($id, $time);
self::assertCount(1, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(1, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**

View File

@@ -26,6 +26,8 @@
use auth_outage\dml\outagedb;
use auth_outage\local\outage;
defined('MOODLE_INTERNAL') || die();
/**
* events_test tests class.
*
@@ -37,7 +39,7 @@ use auth_outage\local\outage;
* @copyright Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_outage_events_test extends advanced_testcase {
class events_test extends advanced_testcase {
/**
* @var outage|null Outage used in the tests.
*/

View File

@@ -39,7 +39,7 @@ require_once(__DIR__.'/../base_testcase.php');
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_outage_forms_test extends auth_outage_base_testcase {
class forms_test extends auth_outage_base_testcase {
/**
* Create a delete form.
*/
@@ -146,8 +146,8 @@ class auth_outage_forms_test extends auth_outage_base_testcase {
$_POST['description'] = ['text' => 'The <b>description</b>.', 'format' => '2'];
$edit = new edit();
self::assertNull($edit->get_data());
self::assertCount(1, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(1, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**
@@ -198,10 +198,6 @@ class auth_outage_forms_test extends auth_outage_base_testcase {
];
}
/**
* Skip tests for moodle below 30.
* @param string $reason reason to be filled
*/
private function skip_because_moodle_is_below_30($reason = '') {
global $CFG;

View File

@@ -39,8 +39,9 @@ require_once(__DIR__.'/base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_installation_test extends auth_outage_base_testcase {
class installation_test extends auth_outage_base_testcase {
/**
* Checks if plugin cleans up data after uninstall.
*
@@ -63,11 +64,7 @@ class auth_outage_installation_test extends auth_outage_base_testcase {
'title' => 'Title',
'description' => 'Description',
]);
ob_start();
\auth_outage\dml\outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertSame(1, $DB->count_records_select('event', "eventtype = 'auth_outage'", null));
// Uninstall plugin.
@@ -75,7 +72,7 @@ class auth_outage_installation_test extends auth_outage_base_testcase {
$progress = new progress_trace_buffer(new text_progress_trace(), false);
core_plugin_manager::instance()->uninstall_plugin('auth_outage', $progress);
$progress->finished();
self::assertStringContainsString('++ Success ++', $progress->get_buffer());
self::assertContains('++ Success ++', $progress->get_buffer());
// Check ...
self::assertSame(0, $DB->count_records_select('event', "eventtype = 'auth_outage'", null),

View File

@@ -34,11 +34,9 @@ require_once(__DIR__.'/../../lib.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2017 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_lib_test extends auth_outage_base_testcase {
/**
* Test this plugin gets climaintenance resource file.
*/
class lib_test extends auth_outage_base_testcase {
public function test_auth_outage_get_climaintenance_resource_file_resolves_a_file() {
global $CFG;
$dir = $CFG->dataroot.'/auth_outage/climaintenance';
@@ -90,9 +88,6 @@ class auth_outage_lib_test extends auth_outage_base_testcase {
self::assertSame($realfile, $actual);
}
/**
* Test this plugin gets climaintenance resource file and prevents path traversal attack.
*/
public function test_auth_outage_get_climaintenance_resource_file_prevent_path_traversal() {
global $CFG;

View File

@@ -36,8 +36,9 @@ require_once(__DIR__.'/cli_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_cli_test extends auth_outage_cli_testcase {
class cli_test extends auth_outage_cli_testcase {
/**
* Tests providing an unknown parameter.
*/
@@ -81,8 +82,8 @@ class auth_outage_cli_test extends auth_outage_cli_testcase {
$this->set_parameters(['-h']);
$cli = new create();
$output = $this->execute($cli);
self::assertStringContainsString('-h', $output);
self::assertStringContainsString('--help', $output);
self::assertContains('-h', $output);
self::assertContains('--help', $output);
}
/**

View File

@@ -35,12 +35,13 @@ require_once(__DIR__.'/../../base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
abstract class auth_outage_cli_testcase extends auth_outage_base_testcase {
/**
* Always enable the auth outage plugin, resets after test and set no parameters.
*/
public function setUp(): void {
public function setUp() {
global $CFG;
// PHPUnit does not load config.php file.

View File

@@ -38,8 +38,9 @@ require_once(__DIR__.'/cli_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_create_test extends auth_outage_cli_testcase {
class create_test extends auth_outage_cli_testcase {
/**
* Tests without any arguments.
*/
@@ -120,8 +121,8 @@ class auth_outage_create_test extends auth_outage_cli_testcase {
$this->set_parameters(['--help']);
$cli = new create();
$output = $this->execute($cli);
self::assertStringContainsString('Creates', $output);
self::assertStringContainsString('--help', $output);
self::assertContains('Creates', $output);
self::assertContains('--help', $output);
}
/**
@@ -157,10 +158,10 @@ class auth_outage_create_test extends auth_outage_cli_testcase {
$cli = new create();
$cli->set_referencetime($now);
$text = $this->execute($cli);
self::assertStringContainsString('created', $text);
self::assertContains('created', $text);
// Check creted outage.
$clioutput = explode(':', $text);
$id = (int)end($clioutput);
list(, $id) = explode(':', $text);
$id = (int)$id;
$outage = outagedb::get_by_id($id);
self::assertSame($now, $outage->starttime);
self::assertSame(10, $outage->get_warning_duration());
@@ -221,10 +222,10 @@ class auth_outage_create_test extends auth_outage_cli_testcase {
'description' => 'Default Description',
]);
$text = $this->execute($cli);
self::assertStringContainsString('created', $text);
self::assertContains('created', $text);
// Check creted outage.
$clioutput = explode(':', $text);
$id = (int)end($clioutput);
list(, $id) = explode(':', $text);
$id = (int)$id;
$outage = outagedb::get_by_id($id);
self::assertSame($now + 50, $outage->starttime, 'Wrong starttime.');
self::assertSame($outage->starttime - 100, $outage->warntime, 'Wrong warntime.');
@@ -299,8 +300,8 @@ class auth_outage_create_test extends auth_outage_cli_testcase {
$cli = new create();
$cli->set_referencetime($now);
$text = $this->execute($cli);
self::assertStringContainsString('created', $text);
self::assertStringContainsString('started', $text);
self::assertContains('created', $text);
self::assertContains('started', $text);
}
/**

View File

@@ -38,8 +38,9 @@ require_once(__DIR__.'/cli_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_finish_test extends auth_outage_cli_testcase {
class finish_test extends auth_outage_cli_testcase {
/**
* Tests the constructor.
*/
@@ -72,8 +73,8 @@ class auth_outage_finish_test extends auth_outage_cli_testcase {
$this->set_parameters(['--help']);
$cli = new finish();
$text = $this->execute($cli);
self::assertStringContainsString('Finishes', $text);
self::assertStringContainsString('--help', $text);
self::assertContains('Finishes', $text);
self::assertContains('--help', $text);
}
/**

View File

@@ -38,8 +38,9 @@ require_once(__DIR__.'/cli_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_waitforit_test extends auth_outage_cli_testcase {
class waitforit_test extends auth_outage_cli_testcase {
/**
* Tests the constructor.
*/
@@ -78,8 +79,8 @@ class auth_outage_waitforit_test extends auth_outage_cli_testcase {
$this->set_parameters(['--help']);
$cli = new waitforit();
$text = $this->execute($cli);
self::assertStringContainsString('Waits', $text);
self::assertStringContainsString('--help', $text);
self::assertContains('Waits', $text);
self::assertContains('--help', $text);
}
/**
@@ -151,9 +152,9 @@ class auth_outage_waitforit_test extends auth_outage_cli_testcase {
$cli = new waitforit();
$cli->set_referencetime($now);
$output = $this->execute($cli);
self::assertStringContainsString('Verbose mode', $output);
self::assertStringContainsString('starting in 1 sec', $output);
self::assertStringContainsString('started', $output);
self::assertContains('Verbose mode', $output);
self::assertContains('starting in 1 sec', $output);
self::assertContains('started', $output);
}
/**
@@ -178,11 +179,11 @@ class auth_outage_waitforit_test extends auth_outage_cli_testcase {
return $now;
});
$output = $this->execute($cli);
self::assertStringContainsString("starting in 45", $output);
self::assertStringContainsString("sleep 30 second", $output);
self::assertStringContainsString("starting in 15", $output);
self::assertStringContainsString("sleep 15 second", $output);
self::assertStringContainsString("started!", $output);
self::assertContains("starting in 45", $output);
self::assertContains("sleep 30 second", $output);
self::assertContains("starting in 15", $output);
self::assertContains("sleep 15 second", $output);
self::assertContains("started!", $output);
}
/**

View File

@@ -3,5 +3,5 @@ a {
}
div {
background-image: url('/moodle/auth/outage/tests/phpunit/local/controllers/fixtures/catalyst.png');
background-image: url('/auth/outage/tests/phpunit/local/controllers/fixtures/catalyst.png');
}

View File

@@ -3,5 +3,5 @@ a {
}
div {
background-image: url(/moodle/auth/outage/tests/phpunit/local/controllers/fixtures/catalyst.png);
background-image: url(/auth/outage/tests/phpunit/local/controllers/fixtures/catalyst.png);
}

View File

@@ -36,14 +36,13 @@ require_once(__DIR__.'/../../base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_infopagecontroller_test extends auth_outage_base_testcase {
class infopagecontroller_test extends auth_outage_base_testcase {
/**
* Tests the constructor.
*/
public function test_constructor() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
new infopage();
}
@@ -51,8 +50,6 @@ class auth_outage_infopagecontroller_test extends auth_outage_base_testcase {
* Tests the constructor with given parameters.
*/
public function test_constructor_withparams() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
$_GET = ['id' => 1, 'static' => 'true'];
new infopage();
}
@@ -61,10 +58,16 @@ class auth_outage_infopagecontroller_test extends auth_outage_base_testcase {
* Tests the constructor with different id and outage id.
*/
public function test_constructor_idmismatch() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
$outage = $this->get_dummy_outage();
$this->set_expected_exception('coding_exception', 'Provided id and outage->id do not match. (2/1)');
$outage = new outage([
'id' => 1,
'autostart' => false,
'warntime' => time() - 60,
'starttime' => time(),
'stoptime' => time() + 60,
'title' => 'Title',
'description' => 'Description',
]);
$this->set_expected_exception('coding_exception');
new infopage(['id' => 2, 'outage' => $outage]);
}
@@ -72,94 +75,35 @@ class auth_outage_infopagecontroller_test extends auth_outage_base_testcase {
* Tests the constructor with an invalid outage.
*/
public function test_constructor_invalidoutage() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
$this->set_expected_exception('coding_exception', 'Provided outage is not a valid outage object. (My outage)');
$this->set_expected_exception('coding_exception');
new infopage(['outage' => 'My outage']);
}
/**
* We should have an exception because CLI cannot redirect.
*/
public function test_output_nonstatic_nooutage() {
$info = new infopage(['static' => false]);
$this->set_expected_exception('moodle_exception');
$info->output();
}
/**
* Checks the output of the info page.
*/
public function test_output() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
$outage = $this->get_dummy_outage();
$now = time();
$outage = new outage([
'id' => 1,
'autostart' => false,
'warntime' => $now - 100,
'starttime' => $now + 100,
'stoptime' => $now + 200,
'title' => 'Title',
'description' => 'Description',
]);
$info = new infopage(['outage' => $outage]);
$output = $info->get_output();
self::assertStringContainsString('auth_outage_info', $output);
}
/**
* Checks the output of the info page.
*/
public function test_output_without_permission() {
$this->revoke_info_page_permissions();
$this->assertFalse(has_capability('auth/outage:viewinfo', context_system::instance()));
$outage = $this->get_dummy_outage();
$info = new infopage(['outage' => $outage]);
$this->set_expected_exception('moodle_exception', 'Unsupported redirect detected, script execution terminated');
$output = $info->get_output();
}
/**
* Checks the output of the info page.
*/
public function test_output_without_permission_but_static() {
$this->revoke_info_page_permissions();
$this->assertFalse(has_capability('auth/outage:viewinfo', context_system::instance()));
$outage = $this->get_dummy_outage();
$info = new infopage(['outage' => $outage, 'static' => true]);
$output = $info->get_output();
self::assertStringContainsString('auth_outage_info', $output);
}
/**
* Checks the output of the info page.
*/
public function test_output_with_forcelogin() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
set_config('forcelogin', true);
$outage = $this->get_dummy_outage();
$info = new infopage(['outage' => $outage]);
$this->set_expected_exception('moodle_exception', 'Unsupported redirect detected, script execution terminated');
$info->get_output();
}
/**
* Checks the output of the info page.
*/
public function test_output_with_forcelogin_if_static() {
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
set_config('forcelogin', true);
$outage = $this->get_dummy_outage();
$info = new infopage(['outage' => $outage, 'static' => true]);
$output = $info->get_output();
self::assertStringContainsString('auth_outage_info', $output);
}
/**
* Tests the constructor enables SVG support.
*/
public function test_svgicons_is_true() {
global $CFG;
$this->assertTrue(has_capability('auth/outage:viewinfo', context_system::instance()));
$CFG->svgicons = false;
new infopage();
self::assertTrue($CFG->svgicons);
self::assertContains('auth_outage_info', $output);
}
}

View File

@@ -25,7 +25,6 @@
use auth_outage\local\controllers\maintenance_static_page;
use auth_outage\local\controllers\maintenance_static_page_io;
use auth_outage\local\controllers\maintenance_static_page_generator;
use auth_outage\task\update_static_page;
defined('MOODLE_INTERNAL') || die();
@@ -38,11 +37,10 @@ require_once(__DIR__.'/../../base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
* @SuppressWarnings(methods) Allow as many methods as needed.
*/
class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase {
/**
* Test template file.
*/
class maintenance_static_page_test extends auth_outage_base_testcase {
public function test_templatefile() {
global $CFG;
$page = maintenance_static_page::create_from_html('<html></html>');
@@ -52,9 +50,6 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
$page->get_io()->get_template_file());
}
/**
* Test resources folder.
*/
public function test_resourcesfolder() {
global $CFG;
$page = maintenance_static_page::create_from_html('<html></html>');
@@ -63,16 +58,10 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
self::assertSame($CFG->dataroot.'/auth_outage/climaintenance/preview', $page->get_io()->get_resources_folder());
}
/**
* Test create from outage.
*/
public function test_createfromoutage() {
// How to fetch a page from PHPUnit environment?
}
/**
* Test create from HTML.
*/
public function test_createfromhtml() {
$html = "<!DOCTYPE html>\n<html><head><title>Title</title></head><body>Content</body></html>";
$expected = "<!DOCTYPE html>\n<html><head><title>Title</title><meta http-equiv=\"refresh\" content=\"300\">".
@@ -80,9 +69,6 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
self::assertSame($expected, $this->generated_page_html($html));
}
/**
* Test remove script tags.
*/
public function test_removescripttags() {
$html = "<!DOCTYPE html>\n".
'<html><head><script type="text/javascript" src="http://xyz"></script><title>Title</title></head>'.
@@ -90,12 +76,9 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
maintenance_static_page::create_from_html($html)->generate();
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString('<script', $generated);
self::assertNotContains('<script', $generated);
}
/**
* Test remove script tags.
*/
public function test_updatelinkstylesheet() {
$localcsslink = $this->get_fixture_path('simple.css');
$externalcsslink = 'http://google.com/coolstuff.css';
@@ -104,14 +87,11 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
'<body>Content<link rel="stylesheet" href="'.$externalcsslink.'"></body></html>';
$generated = $this->generated_page_html($html);
self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=', $generated);
self::assertStringNotContainsString($localcsslink, $generated);
self::assertStringContainsString($externalcsslink, $generated);
self::assertContains('www.example.com/moodle/auth/outage/file.php?file=', $generated);
self::assertNotContains($localcsslink, $generated);
self::assertContains($externalcsslink, $generated);
}
/**
* Test update link style sheet urls.
*/
public function test_updatelinkstylesheet_urls() {
$localcsslink = $this->get_fixture_path('withurls.css');
$html = "<!DOCTYPE html>\n".
@@ -121,15 +101,12 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
$page->generate();
// Check for css file.
self::assertFileExists($page->get_io()->get_resources_folder().'/d8643101d96b093e642b15544e4d1f7815b5ba55.dGV4dC9wbGFpbg');
self::assertFileExists($page->get_io()->get_resources_folder().'/622ef6e83acfcb274cdf37bdb3bffa0923f9a7ad.dGV4dC9wbGFpbg');
// Check for catalyst.png file referenced in url(..) of css.
self::assertFileExists($page->get_io()->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n');
}
/**
* Test update link style sheet urls quoted.
*/
public function test_updatelinkstylesheet_urls_quoted() {
$localcsslink = $this->get_fixture_path('withurls-quoted.css');
$html = "<!DOCTYPE html>\n".
@@ -139,15 +116,12 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
$page->generate();
// Check for css file.
self::assertFileExists($page->get_io()->get_resources_folder().'/9fe2374b03953e1949d54ab750be2d8706891c03.dGV4dC9wbGFpbg');
self::assertFileExists($page->get_io()->get_resources_folder().'/1d84b6d321fef780237f84834b7316c079221a31.dGV4dC9wbGFpbg');
// Check for catalyst.png file referenced in url(..) of css.
self::assertFileExists($page->get_io()->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n');
}
/**
* Test update link style sheet urls with sub dir.
*/
public function test_updatelinkstylesheet_urls_subdir() {
$localcsslink = $this->get_fixture_path('subdir/withurls-subdir.css');
$html = "<!DOCTYPE html>\n".
@@ -163,9 +137,6 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
self::assertFileExists($page->get_io()->get_resources_folder().'/a02a8a442fa82d5205ffb24722d9df7f35161f56.dGV4dC9wbGFpbg');
}
/**
* Test update images to file.php style link.
*/
public function test_updateimages() {
$localimglink = $this->get_fixture_path('catalyst.png');
$externalimglink = 'http://google.com/coolstyle.css';
@@ -174,14 +145,11 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
'<body><img src="'.$localimglink.'">Content<img src="'.$externalimglink.'" /></body></html>';
$generated = $this->generated_page_html($html);
self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=', $generated);
self::assertStringNotContainsString($localimglink, $generated);
self::assertStringContainsString($externalimglink, $generated);
self::assertContains('www.example.com/moodle/auth/outage/file.php?file=', $generated);
self::assertNotContains($localimglink, $generated);
self::assertContains($externalimglink, $generated);
}
/**
* Test update favicon to file.php style link.
*/
public function test_updatelinkfavicon() {
$link = $this->get_fixture_path('catalyst.png');
$html = "<!DOCTYPE html>\n".
@@ -189,67 +157,10 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
'<body>Content</body></html>';
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString($link, $generated);
self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=', $generated);
self::assertNotContains($link, $generated);
self::assertContains('www.example.com/moodle/auth/outage/file.php?file=', $generated);
}
/**
* Data provider for test_update_inline_background_images
* @return array
*/
public function test_update_inline_background_images_provider() {
return [
// Empty string.
["", false],
// URLs that should be retrieved.
["color: #FF00FF; background: lightblue url(/pluginfile.php/1/theme_custom/banner/251298630/0001.png) no-repeat", true],
["background: lightblue url(https://www.example.com/moodle/pluginfile.php/1/theme_custom/banner/251298630/0001.png) no-repeat", true],
["background:url('https://www.example.com/moodle/pluginfile.php/1/theme_custom/banner/251298630/0001.png')", true],
["background-image : url( /pix/help.png);", true],
["background-image: url ('/pix/help.png')", true],
// URLs that should not be retrieved.
["background-image:url(data:image/gif;base64,R0lGODlhYADIAP=)", false],
["background-image:url('data:image/gif;base64,R0lGODlhYADIAP=')", false]
];
}
/**
* Tests update_inline_background_images() method to update the background images.
*
* @dataProvider test_update_inline_background_images_provider
* @param string $stylecontent Content of the style to test
* @param bool $rewrite Flag if URL should be rewritten
* @throws coding_exception
*/
public function test_update_inline_background_images($stylecontent, $rewrite) {
global $CFG;
$this->resetAfterTest(true);
$generator = new maintenance_static_page_generator(new DOMDocument(), new maintenance_static_page_io());
$html = '<!DOCTYPE html>\n'.
'<html><head><title>Title</title></head>'.
'<body><div style="'.$stylecontent.'">Content</div></body></html>';
// Temporarily disable debugging to prevent errors because file does not exist
$debuglevel = $CFG->debug;
$CFG->debug = '';
$generated = $this->generated_page_html($html);
// Restore debugging level
$CFG->debug = $debuglevel;
$matches = $generator->get_url_from_inline_style($stylecontent);
if ($rewrite) {
self::assertStringNotContainsString($matches[1], $generated);
self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=', $generated);
self::assertIsArray($matches);
} else {
self::assertStringContainsString($stylecontent, $generated);
}
}
/**
* Test update preview path to file.php style link.
*/
public function test_previewpath() {
$link = $this->get_fixture_path('catalyst.png');
$html = "<!DOCTYPE html>\n".
@@ -260,8 +171,8 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
$page->generate();
$generated = trim(file_get_contents($page->get_io()->get_template_file()));
self::assertStringNotContainsString($link, $generated);
self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=preview%2F', $generated);
self::assertNotContains($link, $generated);
self::assertContains('www.example.com/moodle/auth/outage/file.php?file=preview%2F', $generated);
}
/**
@@ -297,17 +208,9 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
touch($file);
self::assertFileExists($file);
maintenance_static_page::create_from_outage(null)->generate();
// Backwards compatibility with older PHPUnit - use old assertFile method.
if (method_exists($this, 'assertFileDoesNotExist')) {
self::assertFileDoesNotExist($file);
} else {
self::assertFileNotExists($file);
}
self::assertFileNotExists($file);
}
/**
* Tests created file.
*/
public function test_createdfile() {
global $CFG;
@@ -331,7 +234,7 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
/**
* Gets a fixture file for this test case.
*
* @param string $file file name
* @param $file
*
* @return string
*/
@@ -339,59 +242,30 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
return (string)new moodle_url('/auth/outage/tests/phpunit/local/controllers/fixtures/'.$file);
}
/**
* Test saving empty string for template file.
*/
public function test_invalid_string_saving_template_empty() {
$io = new maintenance_static_page_io();
$this->set_expected_exception('coding_exception');
$io->save_template_file('');
}
/**
* Test saving non string for template file.
*/
public function test_invalid_string_saving_template_nostring() {
$io = new maintenance_static_page_io();
$this->set_expected_exception('coding_exception');
$io->save_template_file(50);
}
/**
* Test get url for file.
*/
public function test_get_url_for_file() {
$io = new maintenance_static_page_io();
self::assertStringContainsString('www.example.com/moodle/auth/outage/file.php?file=img.png', $io->get_url_for_file('img.png'));
self::assertContains('www.example.com/moodle/auth/outage/file.php?file=img.png', $io->get_url_for_file('img.png'));
}
/**
* Return array of url data provider and true or false.
*/
public function is_url_dataprovider() {
return [
[true, 'http://catalyst.net.nz'],
[true, 'https://www.catalyst-au.net/'],
[false, '/homepage'],
[false, 'file://homepage'],
[true, '//catalyst-au.net/img/test.jpg'],
[false, '://www.catalyst-au.net/img/test.jpg']
];
public function test_is_url() {
self::assertTrue(maintenance_static_page_io::is_url('http://catalyst.net.nz'));
self::assertTrue(maintenance_static_page_io::is_url('https://www.catalyst-au.net/'));
self::assertFalse(maintenance_static_page_io::is_url('/homepage'));
self::assertFalse(maintenance_static_page_io::is_url('file://homepage'));
}
/**
* Test if it is url
* @dataProvider is_url_dataprovider
* @param string $result expected result
* @param string $url url to be checked
*/
public function test_is_url($result, $url) {
self::assertEquals($result, maintenance_static_page_io::is_url($url));
}
/**
* Test file get_data.
*/
public function test_file_get_data() {
$file = __DIR__.'/fixtures/catalyst.png';
$found = maintenance_static_page_io::file_get_data($file);
@@ -399,28 +273,19 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
self::assertSame('image/png', $found['mime']);
}
/**
* Test invalid file get_data.
*/
public function test_file_get_data_invalidfile() {
$found = maintenance_static_page_io::file_get_data(__DIR__.'/fixtures/invalidfile');
self::assertSame('', $found['contents']);
self::assertSame('unknown', $found['mime']);
self::assertCount(1, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(1, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**
* Test invalid file get_data.
*/
public function test_file_get_data_invalidfilename() {
$this->set_expected_exception('coding_exception');
maintenance_static_page_io::file_get_data(200);
}
/**
* Test remove css selector.
*/
public function test_remove_css_selector() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -429,13 +294,10 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', '.removeme', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString('removeme', $generated);
self::assertStringNotContainsString('Goodbye cruel world', $generated);
self::assertNotContains('removeme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
/**
* Test remove css selector id.
*/
public function test_remove_css_selector_id() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -444,13 +306,10 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', '#removeme', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString('removeme', $generated);
self::assertStringNotContainsString('Goodbye cruel world', $generated);
self::assertNotContains('removeme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
/**
* Test remove css selector with multi lines.
*/
public function test_remove_css_selector_with_multiline() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -462,14 +321,11 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', ".removeme\n.deleteme", 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString('removeme', $generated);
self::assertStringNotContainsString('deleteme', $generated);
self::assertStringNotContainsString('Goodbye cruel world', $generated);
self::assertNotContains('removeme', $generated);
self::assertNotContains('deleteme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
/**
* Test remove css selector needs trim.
*/
public function test_remove_css_selector_needing_trim() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -481,14 +337,11 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', " .removeme \n .deleteme ", 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString('removeme', $generated);
self::assertStringNotContainsString('deleteme', $generated);
self::assertStringNotContainsString('Goodbye cruel world', $generated);
self::assertNotContains('removeme', $generated);
self::assertNotContains('deleteme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
/**
* Test remove css selector with empty line.
*/
public function test_remove_css_selector_with_empty_line() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -500,14 +353,11 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', "\n\n.removeme\n\n\n\n.deleteme\n\n", 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringNotContainsString('removeme', $generated);
self::assertStringNotContainsString('deleteme', $generated);
self::assertStringNotContainsString('Goodbye cruel world', $generated);
self::assertNotContains('removeme', $generated);
self::assertNotContains('deleteme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
/**
* Test remove css selector with invalid id.
*/
public function test_remove_css_selector_with_invalid_id() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -516,13 +366,10 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', '#invalidid', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringContainsString('removeme', $generated);
self::assertStringContainsString('Goodbye cruel world', $generated);
self::assertContains('removeme', $generated);
self::assertContains('Goodbye cruel world', $generated);
}
/**
* Test meta refresh 5 minutes.
*/
public function test_meta_refresh_5minutes() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -531,12 +378,9 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
set_config('remove_selectors', '#invalidid', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertStringContainsString('<meta http-equiv="refresh" content="300">', $generated);
self::assertContains('<meta http-equiv="refresh" content="300">', $generated);
}
/**
* Test meta refresh maximum 5 minutes.
*/
public function test_meta_refresh_maximum_5seconds() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
@@ -549,47 +393,6 @@ class auth_outage_maintenance_static_page_test extends auth_outage_base_testcase
$generated = trim(file_get_contents($page->get_io()->get_template_file()));
return $generated;
self::assertStringContainsString('<meta http-equiv="refresh" content="5">', $generated);
}
/**
* Data provider for test_get_urls_from_stylesheet
* @return array
*/
public function test_get_urls_from_stylesheet_provider() {
return [
// Empty string.
["", 0],
// URLs that should be retrieved.
["background:url(/theme/image.php/_s/boost/core/1581292565/t/expanded)", 1],
["background:url('/theme/image.php/_s/boost/core/1581292565/t/expanded')", 1],
["src:url(\"/theme/font.php/boost/core/1581292565/fontawesome-webfont.eot?#iefix&v=4.7.0\")", 1],
["background-image:url(pix/vline-rtl.gif)", 1],
// URLs that should not be retrieved.
["background-image:url(data:image/gif;base64,R0lGODlhYADIAP=)", 0],
["background-image:url('data:image/gif;base64,R0lGODlhYADIAP=')", 0],
["background-image:url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\'\")", 0],
// Combination of URLs used above.
["background-image:url(pix/vline-rtl.gif) background:url(/theme/image.php/_s/boost/core/158/t/expanded)", 2],
["background-image:url(data:image/gif;base64,R0lG=)src:url(\"/theme/font.php/fontawesome-webfont.eot\")", 1],
];
}
/**
* Tests get_urls_from_stylesheet() method to get all appropriate URLS from the file.
*
* @dataProvider test_get_urls_from_stylesheet_provider
* @param string $filecontent Content of the file
* @param int $count Expected quantity of found URLs
* @throws coding_exception
*/
public function test_get_urls_from_stylesheet($filecontent, $count) {
$this->resetAfterTest(true);
$generator = new maintenance_static_page_generator(new DOMDocument(), new maintenance_static_page_io());
$matches = $generator->get_urls_from_stylesheet($filecontent);
self::assertIsArray($matches);
self::assertCount(2, $matches);
self::assertCount($count, $matches[1]);
self::assertContains('<meta http-equiv="refresh" content="5">', $generated);
}
}

View File

@@ -35,8 +35,9 @@ require_once(__DIR__.'/../base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_outage_test extends auth_outage_base_testcase {
class outage_test extends auth_outage_base_testcase {
/**
* Tests the constructor.
*/
@@ -280,11 +281,11 @@ class auth_outage_outage_test extends auth_outage_base_testcase {
'description' => 'Description {{start}} {{stop}} {{duration}}',
]);
$title = $outage->get_title();
self::assertStringNotContainsString('{', $title);
self::assertStringNotContainsString('}', $title);
self::assertNotContains('{', $title);
self::assertNotContains('}', $title);
$description = $outage->get_description();
self::assertStringNotContainsString('{', $description);
self::assertStringNotContainsString('}', $description);
self::assertNotContains('{', $description);
self::assertNotContains('}', $description);
}
/**

View File

@@ -32,7 +32,6 @@ defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir.'/adminlib.php');
require_once(__DIR__.'/../base_testcase.php');
/**
* outagelib_test test class.
*
@@ -40,8 +39,9 @@ require_once(__DIR__.'/../base_testcase.php');
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright 2016 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @SuppressWarnings(public) Allow as many methods as needed.
*/
class auth_outage_outagelib_test extends auth_outage_base_testcase {
class outagelib_test extends auth_outage_base_testcase {
/**
* Check if maintenance message is disabled as needed.
*/
@@ -60,14 +60,10 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
]);
set_config('maintenance_message', 'A message.');
ob_start();
outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertFalse((bool)get_config('moodle', 'maintenance_message'));
self::assertCount(2, $this->getDebuggingMessages());
$this->resetDebugging();
self::assertCount(2, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**
@@ -85,7 +81,7 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
* Check outagelib::inject() works as expected.
*/
public function test_inject() {
global $OUTPUT;
global $CFG;
$this->resetAfterTest(true);
self::setAdminUser();
@@ -98,23 +94,19 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
'title' => 'Title',
'description' => 'Description',
]);
ob_start();
$outage->id = outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertEmpty($CFG->additionalhtmltopofbody);
outagelib::reset_injectcalled();
// Get full header to avoid interactions with other single inject plugins.
$header1 = $OUTPUT->standard_top_of_body_html();
self::assertStringContainsString('<style>', $header1);
self::assertStringContainsString('<script>', $header1);
outagelib::reinject();
self::assertContains('<style>', $CFG->additionalhtmltopofbody);
self::assertContains('<script>', $CFG->additionalhtmltopofbody);
// Should not inject more than once.
$size = strlen($OUTPUT->standard_top_of_body_html());
self::assertSame($size, strlen($OUTPUT->standard_top_of_body_html()));
// Check styles aren't reinjected.
self::assertStringNotContainsString('<style>', $OUTPUT->standard_top_of_body_html());
// Should not inject more than once with the inject() function.
$size = strlen($CFG->additionalhtmltopofbody);
outagelib::inject();
self::assertSame($size, strlen($CFG->additionalhtmltopofbody));
$this->resetDebugging(); // Function pix_url deprecated in Moodle 33+.
}
/**
@@ -122,10 +114,9 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
*/
public function test_inject_broken() {
$_GET = ['auth_outage_break_code' => '1'];
outagelib::reset_injectcalled();
$header = outagelib::get_inject_code();
self::assertCount(2, $this->getDebuggingMessages());
$this->resetDebugging();
outagelib::reinject();
self::assertCount(2, phpunit_util::get_debugging_messages());
phpunit_util::reset_debugging();
}
/**
@@ -144,18 +135,15 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
'title' => 'Title',
'description' => 'Description',
]);
ob_start();
$outage->id = outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertEmpty($CFG->additionalhtmltopofbody);
$_GET = ['auth_outage_preview' => (string)$outage->id];
outagelib::reset_injectcalled();
$header = outagelib::get_inject_code();
self::assertStringContainsString('<style>', $header);
self::assertStringContainsString('<script>', $header);
outagelib::reinject();
self::assertContains('<style>', $CFG->additionalhtmltopofbody);
self::assertContains('<script>', $CFG->additionalhtmltopofbody);
$this->resetDebugging(); // Function pix_url deprecated in Moodle 33+.
}
/**
@@ -163,12 +151,11 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
*/
public function test_inject_preview_notfound() {
global $CFG;
self::assertEmpty($CFG->additionalhtmltopofbody);
$_GET = ['auth_outage_preview' => '1'];
// Should not throw exception or halt anything, silently ignore it.
outagelib::reset_injectcalled();
$header = outagelib::get_inject_code();
self::assertEmpty($header);
outagelib::reinject();
self::assertEmpty($CFG->additionalhtmltopofbody);
}
/**
@@ -187,24 +174,19 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
'title' => 'Title',
'description' => 'Description',
]);
ob_start();
$outage->id = outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertEmpty($CFG->additionalhtmltopofbody);
$_GET = ['auth_outage_preview' => (string)$outage->id, 'auth_outage_delta' => '500'];
outagelib::reset_injectcalled();
$header = outagelib::get_inject_code();
outagelib::reinject();
// Still empty, delta is too high (outage ended).
self::assertEmpty($header);
self::assertEmpty($CFG->additionalhtmltopofbody);
}
/**
* Test injection without active outage.
*/
public function test_inject_noactive() {
outagelib::reset_injectcalled();
outagelib::get_inject_code();
outagelib::reinject();
}
/**
@@ -231,10 +213,6 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
foreach ($keys as $k) {
self::assertSame($config->$k, $k.'_value', 'auth_outage');
}
set_config('allowedips_forced', 'allowedips_forced_value', 'auth_outage');
$config = outagelib::get_config();
self::assertSame($config->allowedips, "allowedips_value\nallowedips_forced_value", 'auth_outage');
}
/**
@@ -297,35 +275,26 @@ class auth_outage_outagelib_test extends auth_outage_base_testcase {
'title' => 'Title',
'description' => 'Description',
]);
ob_start();
$outage->id = outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertEmpty($CFG->additionalhtmltopofbody);
// Pretend we are there...
$_SERVER['SCRIPT_FILENAME'] = '/var/www/alternativepath/admin/settings.php'; // Issue #88 regression test.
$_SERVER['SCRIPT_NAME'] = '/admin/settings.php';
$_GET['section'] = 'additionalhtml';
outagelib::reset_injectcalled();
$header = outagelib::get_inject_code();
outagelib::reinject();
self::assertEmpty($header);
self::assertEmpty($CFG->additionalhtmltopofbody);
}
/**
* Test create maintenance php code
*/
public function test_createmaintenancephpcode() {
$expected = <<<'EOT'
<?php
if ((time() >= 123) && (time() < 456)) {
define('MOODLE_INTERNAL', true);
require_once($CFG->dirroot.'/lib/moodlelib.php');
if (file_exists($CFG->dirroot.'/lib/classes/ip_utils.php')) {
require_once($CFG->dirroot.'/lib/classes/ip_utils.php');
}
if (!remoteip_in_list('hey\'\"you
require_once($CFG->dirroot.'/lib/classes/ip_utils.php');
if (!remoteip_in_list('heyyou
a.b.c.d
e.e.e.e/20')) {
header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance');
@@ -339,7 +308,6 @@ e.e.e.e/20')) {
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');
header('X-Moodle-Maintenance: manager');
if ((defined('AJAX_SCRIPT') && AJAX_SCRIPT) || (defined('WS_SERVER') && WS_SERVER)) {
exit(0);
}
@@ -357,13 +325,7 @@ EOT;
self::assertSame($expected, $found);
}
/**
* Test create maintenance php code without age
*
* @param string $configkey The key of the config.
* @dataProvider test_createmaintenancephpcode_withoutage_provider
*/
public function test_createmaintenancephpcode_withoutage($configkey) {
public function test_createmaintenancephpcode_withoutage() {
global $CFG;
$this->resetAfterTest(true);
@@ -372,9 +334,7 @@ EOT;
if ((time() >= 123) && (time() < 456)) {
define('MOODLE_INTERNAL', true);
require_once($CFG->dirroot.'/lib/moodlelib.php');
if (file_exists($CFG->dirroot.'/lib/classes/ip_utils.php')) {
require_once($CFG->dirroot.'/lib/classes/ip_utils.php');
}
require_once($CFG->dirroot.'/lib/classes/ip_utils.php');
if (!remoteip_in_list('127.0.0.1')) {
header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance');
header('Status: 503 Moodle under maintenance');
@@ -387,7 +347,6 @@ if ((time() >= 123) && (time() < 456)) {
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');
header('X-Moodle-Maintenance: manager');
if ((defined('AJAX_SCRIPT') && AJAX_SCRIPT) || (defined('WS_SERVER') && WS_SERVER)) {
exit(0);
}
@@ -406,7 +365,7 @@ EOT;
'stoptime' => 456,
]);
$file = $CFG->dataroot.'/climaintenance.php';
set_config($configkey, '127.0.0.1', 'auth_outage');
set_config('allowedips', '127.0.0.1', 'auth_outage');
outagelib::update_climaintenance_code($outage);
self::assertFileExists($file);
@@ -414,13 +373,6 @@ EOT;
self::assertSame($found, $expected);
}
public function test_createmaintenancephpcode_withoutage_provider(): array {
return [['allowedips'], ['allowedips_forced']];
}
/**
* Test create maintenance php code without IPs
*/
public function test_createmaintenancephpcode_withoutips() {
global $CFG;
$this->resetAfterTest(true);
@@ -431,33 +383,19 @@ EOT;
]);
$file = $CFG->dataroot.'/climaintenance.php';
set_config('allowedips', '', 'auth_outage');
set_config('allowedips_forced', '', 'auth_outage');
touch($file);
outagelib::update_climaintenance_code($outage);
// Backwards compatibility with older PHPUnit - use old assertFile method.
if (method_exists($this, 'assertFileDoesNotExist')) {
self::assertFileDoesNotExist($file);
} else {
self::assertFileNotExists($file);
}
self::assertFileNotExists($file);
}
/**
* Test create maintenance php code without outage
*/
public function test_createmaintenancephpcode_withoutoutage() {
global $CFG;
$file = $CFG->dataroot.'/climaintenance.php';
touch($file);
outagelib::update_climaintenance_code(null);
// Backwards compatibility with older PHPUnit - use old assertFile method.
if (method_exists($this, 'assertFileDoesNotExist')) {
self::assertFileDoesNotExist($file);
} else {
self::assertFileNotExists($file);
}
self::assertFileNotExists($file);
}
/**
@@ -484,7 +422,9 @@ EOT;
$this->create_outage();
// Change settings.
set_config('s_auth_outage_allowedips', '127', 'auth_outage');
admin_write_settings((object)[
's_auth_outage_allowedips' => '127',
]);
// The method outagelib::prepare_next_outage() should have been called from admin_write_settings().
foreach ([$CFG->dataroot.'/climaintenance.template.html', $CFG->dataroot.'/climaintenance.php'] as $file) {
@@ -502,7 +442,9 @@ EOT;
$this->create_outage();
// Change settings.
set_config('s_auth_outage_remove_selectors', '.something', 'auth_outage');
admin_write_settings((object)[
's_auth_outage_remove_selectors' => '.something',
]);
// The method outagelib::prepare_next_outage() should have been called from admin_write_settings().
foreach ([$CFG->dataroot.'/climaintenance.template.html', $CFG->dataroot.'/climaintenance.php'] as $file) {
@@ -533,12 +475,7 @@ EOT;
// 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.
// Backwards compatibility with older PHPUnit - use old assertFile method.
if (method_exists($this, 'assertFileDoesNotExist')) {
self::assertFileDoesNotExist($CFG->dataroot.'/climaintenance.html');
} else {
self::assertFileNotExists($CFG->dataroot.'/climaintenance.html');
}
self::assertFileNotExists($CFG->dataroot.'/climaintenance.html');
}
/**
@@ -558,24 +495,20 @@ EOT;
'title' => 'Title',
'description' => 'Description',
]);
ob_start();
$outage->id = outagedb::save($outage);
$text = trim(ob_get_contents());
ob_end_clean();
self::assertStringContainsString('Update maintenance mode configuration', $text);
self::assertEmpty($CFG->additionalhtmltopofbody);
// Pretend we are there...
$_SERVER['SCRIPT_FILENAME'] = '/var/www/alternativepath/admin/settings.php'; // Issue #88 regression test.
$_SERVER['SCRIPT_NAME'] = '/admin/settings.php';
$_GET['section'] = 'notadditionalhtml';
outagelib::reset_injectcalled();
outagelib::reinject();
$header = outagelib::get_inject_code();
self::assertNotEmpty($header);
self::assertNotEmpty($CFG->additionalhtmltopofbody);
$this->resetDebugging(); // Function pix_url deprecated in Moodle 33+.
}
/**
* Creates outage for tests.
*/
private function create_outage() {
$this->resetAfterTest(true);
self::setAdminUser();

View File

@@ -28,8 +28,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = "auth_outage";
$plugin->version = 2023012700; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2023012700; // Human-readable release information.
$plugin->requires = 2017111309; // 2017111309 = T13, but this really requires 3.9 and higher.
$plugin->version = 2018062500; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = '1.0.9'; // 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!
$plugin->supported = [39, 401]; // A range of branch numbers of supported moodle versions.

View File

@@ -26,20 +26,16 @@
use auth_outage\output\manage\history_table;
use auth_outage\output\manage\planned_table;
use auth_outage\output\renderer;
use auth_outage\dml\outagedb;
use auth_outage\local\outagelib;
defined('MOODLE_INTERNAL') || die();
global $PAGE;
$output = $PAGE->get_renderer('auth_outage');
$urlnew = new moodle_url('/auth/outage/edit.php');
echo $viewbag['warning'];
?>
<section id="section_planned_outages">
<?php echo $output->rendersubtitle('outageslistfuture'); ?>
<?php echo renderer::get()->rendersubtitle('outageslistfuture'); ?>
<?php if (empty($viewbag['unended'])): ?>
<p>
<small><?php echo get_string('notfound', 'auth_outage'); ?></small>
@@ -51,27 +47,13 @@ echo $viewbag['warning'];
$table->finish_output();
?>
<?php endif; ?>
<?php
$outage = outagedb::get_ongoing();
if (is_null($outage)) :
$config = outagelib::get_config();
$default = $config->default_time;
$max = $default ? 3 : 1;
$next = time();
for ($c = 0; $c < $max; $c++) {
echo '<p>';
$next = outagelib::get_next_window($next);
$urlnew->param('starttime', $next);
echo $output->single_button($urlnew, get_string('outagecreate', 'auth_outage'));
if ($default) {
echo ' ' . userdate( $next, get_string('datetimeformat', 'auth_outage'));
}
}
endif; ?>
<input type="button" class="form-submit"
value="<?php echo get_string('outagecreate', 'auth_outage'); ?>"
onclick="location.href='<?php echo $urlnew; ?>';"/>
</section>
<section id="section_outage_history">
<?php echo $output->rendersubtitle('outageslistpast'); ?>
<?php echo renderer::get()->rendersubtitle('outageslistpast'); ?>
<?php if (empty($viewbag['ended'])): ?>
<p>
<small><?php echo get_string('notfound', 'auth_outage'); ?></small>

View File

@@ -7,78 +7,71 @@ If you need to make changes here, remember to update your settings inside Moodle
background-color: red;
box-sizing: content-box;
color: white;
height: 100px;
height: 90px;
left: 0;
padding: 0;
position: fixed;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
top: 0;
transition: background 3s ease-out;
width: 100%;
z-index: 9999;
}
#auth_outage_warningbar_box .auth_outage_warningbar_center {
/* fix to prevent existing theme hacks to fix issue */
margin-top: 0;
position: static;
}
#auth_outage_warningbar_box.auth_outage_warning_period {
background:
repeating-linear-gradient(
background: repeating-linear-gradient(
-45deg,
#ff7c00,
#ff7c00 10px,
#ff6c00 10px,
#ff6c00 20px
);
);
background-color: #ff7c00;
}
#auth_outage_warningbar_box.auth_outage_imminent_period {
background:
repeating-linear-gradient(
background: repeating-linear-gradient(
-45deg,
#a000a0,
#a000a0 10px,
#800080 10px,
#800080 20px
);
);
background-color: #800080;
}
#auth_outage_warningbar_box.auth_outage_ongoing_period {
background:
repeating-linear-gradient(
background: repeating-linear-gradient(
-45deg,
#e00,
#e00 10px,
#c00 10px,
#c00 20px
);
background-color: #e00;
#ee0000,
#ee0000 10px,
#cc0000 10px,
#cc0000 20px
);
background-color: #ee0000;
}
#auth_outage_warningbar_box.auth_outage_finished_period {
background:
repeating-linear-gradient(
background: repeating-linear-gradient(
-45deg,
#0a0,
#0a0 10px,
#090 10px,
#090 20px
);
background-color: #090;
#00aa00,
#00aa00 10px,
#009900 10px,
#009900 20px
);
background-color: #009900;
}
.auth_outage_warningbar_center {
margin-top: -35px;
position: relative;
top: 50%;
}
#auth_outage_warningbar_message {
font-size: 200%;
font-weight: bold;
margin: 0;
margin: 10px 0;
}
a.auth_outage_warningbar_box_title {
@@ -90,7 +83,6 @@ a.auth_outage_warningbar_box_finish {
border: 1px solid black;
border-radius: 5px;
color: darkgray;
white-space: nowrap;
font-weight: bold;
margin-left: 10px;
padding-left: 5px;
@@ -103,36 +95,10 @@ a.auth_outage_warningbar_box_finish:hover {
background-color: black;
}
body.auth_outage #nav-drawer {
top: 150px;
.navbar.navbar-fixed-top {
top: 90px;
}
body.auth_outage nav.fixed-top.navbar {
top: 100px;
}
body.auth_outage #page {
margin-top: 150px;
}
body.auth_outage.path-mod-assign [data-region="grading-navigation-panel"] {
top: 100px;
}
body.auth_outage.path-mod-assign [data-region="grade-panel"] {
top: 185px;
}
body.auth_outage .layout.fullscreen {
top: 150px;
}
body.auth_outage .modal-dialog {
margin: calc(150px + 1.75rem) auto;
}
@media (max-width: 767px) {
#auth_outage_warningbar_message {
font-size: 120%;
}
.auth_outage_warningbar_spacer {
height: 80px;
}

View File

@@ -56,8 +56,6 @@ var authOutageWarningBar = {
},
tickOngoing: function() {
const MINSECS = 60;
if (this.finished) {
return;
}
@@ -80,8 +78,13 @@ var authOutageWarningBar = {
xmlhttp.open("GET", this.checkfinishedurl, true);
xmlhttp.send();
// Checking if the site is back online every 4-6 minutes.
var sleepSeconds = 4 * MINSECS + (2 * MINSECS * Math.random());
var estimatedServerTime = this.servertime + (Date.now() - this.clienttime);
var sleepSeconds = this.stops - estimatedServerTime; // How long to sleep until it stops.
if (sleepSeconds <= 0) {
sleepSeconds = 5; // It should be back, keep checking every 5 seconds.
} else {
sleepSeconds = Math.min(sleepSeconds, (5 * 60)); // Check at least every 5 minutes.
}
setTimeout(function() {
$this.tickOngoing();
@@ -111,10 +114,8 @@ var authOutageWarningBar = {
seconds2hms: function(seconds) {
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
var days = Math.floor(hours / 24);
seconds %= 60;
minutes %= 60;
hours %= 24;
// Cross-browser simple solution for padding zeroes.
if (minutes < 10) {
minutes = "0" + minutes;
@@ -122,15 +123,6 @@ var authOutageWarningBar = {
if (seconds < 10) {
seconds = "0" + seconds;
}
if (days > 0) {
if (days > 1) {
days = days + ' days ';
} else {
days = days + ' day ';
}
} else {
days = '';
}
return days + hours + ':' + minutes + ':' + seconds;
return hours + ':' + minutes + ':' + seconds;
}
};

View File

@@ -48,7 +48,7 @@ if (!$viewbag['static']) {
if (is_siteadmin()) {
$url = new moodle_url('/auth/outage/finish.php', ['id' => $viewbag['outage']->id]);
$text = html_writer::empty_tag('img', [
'src' => $OUTPUT->image_url('t/check'),
'src' => $OUTPUT->pix_url('t/check'),
'alt' => get_string('finish', 'auth_outage'),
'class' => 'iconsmall',
]).' '.get_string('finish', 'auth_outage');
@@ -74,6 +74,8 @@ if (!$viewbag['static']) {
</div>
</div>
<div class="auth_outage_warningbar_spacer">&nbsp;</div>
<?php if (!$viewbag['static']): ?>
<script>
document.body.className += ' auth_outage';