From 92681c7ec4558141894e071fed39d79b48ea6608 Mon Sep 17 00:00:00 2001 From: Daniel Thee Roperto Date: Tue, 13 Sep 2016 16:00:44 +1000 Subject: [PATCH] Issue #26 - Added the option to preview how a warning bar will look before and during an outage. --- classes/models/outage.php | 19 +++++++++++ classes/outagelib.php | 12 +++---- info.php | 3 ++ lang/en/auth_outage.php | 6 ++++ renderer.php | 66 ++++++++++++++++++++++++++------------- tests/outage_test.php | 50 +++++++++++++++++++++++++++-- views/infopage.php | 50 +++++++++++++++++++++++++++++ views/warningbar.php | 2 +- 8 files changed, 176 insertions(+), 32 deletions(-) create mode 100644 views/infopage.php diff --git a/classes/models/outage.php b/classes/models/outage.php index 5b0b8d9..d258806 100644 --- a/classes/models/outage.php +++ b/classes/models/outage.php @@ -97,6 +97,25 @@ class outage { throw new \InvalidArgumentException('$data must be null (default), an array or an object.'); } + /** + * Checks if the outage is active (in warning period or ongoing). + * @param int|null $time Null to check if the outage is active now or another time to use as reference. + * @return bool True if outage is ongoing or during the warning period. + */ + public function is_active($time = null) { + if ($time === null) { + $time = time(); + } + if (!is_int($time) || ($time <= 0)) { + throw new \InvalidArgumentException('$time must be an positive int.'); + } + if (is_null($this->warntime) || is_null($this->stoptime)) { + return false; + } + + return (($this->warntime <= $time) && ($time < $this->stoptime)); + } + /** * Checks if the outage is happening. * @param int|null $time Null to check if the outage is happening now or another time to use as reference. diff --git a/classes/outagelib.php b/classes/outagelib.php index f84f560..d04f79c 100644 --- a/classes/outagelib.php +++ b/classes/outagelib.php @@ -68,17 +68,17 @@ class outagelib { $previewid = optional_param('auth_outage_preview', null, PARAM_INT); $time = time(); if (is_null($previewid)) { - if (($active = outagedb::get_active()) == null) { + if (!$active = outagedb::get_active()) { return; } } else { - if (($active = outagedb::get_by_id($previewid)) == null) { + if (!$active = outagedb::get_by_id($previewid)) { return; } - $delta = optional_param('auth_outage_delta', null, PARAM_FLOAT); - if ($delta) { - // Delta is float in minutes, allowing to check the redirect in a few seconds. - $time = $active->starttime + (int)($delta * 60); + // Delta is in seconds, setting the time our warning bar will consider relative to the outage start time. + $time = $active->starttime + optional_param('auth_outage_delta', 0, PARAM_INT); + if (!$active->is_active($time)) { + return; } } diff --git a/info.php b/info.php index 1ac03cb..046c0bc 100644 --- a/info.php +++ b/info.php @@ -39,6 +39,9 @@ $PAGE->set_title($outage->get_title()); $PAGE->set_heading($outage->get_title()); $PAGE->set_url(new \moodle_url('/auth/outage/info.php')); +// No hooks injecting into this page, do it manually. +outagelib::inject(); + echo $OUTPUT->header(); echo outagelib::get_renderer()->renderoutagepage($outage); diff --git a/lang/en/auth_outage.php b/lang/en/auth_outage.php index 403adce..db1ec24 100644 --- a/lang/en/auth_outage.php +++ b/lang/en/auth_outage.php @@ -39,6 +39,12 @@ $string['defaultwarningdescriptiondescription'] = 'Default warning message for o $string['defaultwarningdescriptionvalue'] = 'There is an scheduled maintenance from {{start}} to {{stop}} and our system will not be available during that time.'; $string['description'] = 'Public Description'; $string['description_help'] = 'A full description of the outage, publicly visible by all users.'; +$string['info1minutebefore'] = '1 minute before'; +$string['infoendofoutage'] = 'end of outage'; +$string['infofrom'] = 'From:'; +$string['infountil'] = 'Until:'; +$string['infostart'] = 'start'; +$string['infostartofwarning'] = 'start of warning'; $string['menudefaults'] = 'Default Settings'; $string['menumanage'] = 'Manage'; $string['messageoutageongoing'] = 'Our system will be under maintenance until {$a->stop}.'; diff --git a/renderer.php b/renderer.php index 5cccc52..2a91e40 100644 --- a/renderer.php +++ b/renderer.php @@ -138,30 +138,52 @@ class auth_outage_renderer extends plugin_renderer_base { ); } - public function renderoutagepage(outage $outage) { - $start = userdate($outage->starttime, get_string('strftimedatetimeshort')); - $stop = userdate($outage->stoptime, get_string('strftimedatetimeshort')); + /** + * @param outage $outage + * @param null $time + * @return string + * @SuppressWarnings("unused") because $admineditlink is used inside require(...) + */ + public function renderoutagepage(outage $outage, $time = null) { + global $CFG; - $admin = ''; - if (is_siteadmin()) { - $admin = html_writer::tag('div', - '[' . html_writer::link( - new moodle_url('/auth/outage/edit.php', ['id' => $outage->id]), - get_string('outageedit', 'auth_outage') - ) . ']' + if (is_null($time)) { + $time = time(); + } + if (!is_int($time)) { + throw new \InvalidArgumentException('$time is not an int or null.'); + } + + $adminlinks = []; + foreach ([ + 'startofwarning' => -$outage->get_warning_duration(), + '1minutebefore' => -60, + 'start' => 0, + 'endofoutage' => $outage->get_duration(), + ] as $title => $delta) { + $adminlinks[] = html_writer::link( + new moodle_url( + '/auth/outage/info.php', + [ + 'id' => $outage->id, + 'auth_outage_preview' => $outage->id, + 'auth_outage_delta' => $delta, + ] + ), + get_string('info' . $title, 'auth_outage') ); } - return html_writer::div( - html_writer::tag('p', - html_writer::tag('b', 'From: ') - . $start - . html_writer::tag('b', ' Until: ') - . $stop - ) - . html_writer::div($outage->get_description()) - . $admin + $admineditlink = html_writer::link( + new moodle_url('/auth/outage/edit.php', ['id' => $outage->id]), + get_string('outageedit', 'auth_outage') ); + + ob_start(); + require($CFG->dirroot . '/auth/outage/views/infopage.php'); + $html = ob_get_contents(); + ob_end_clean(); + return $html; } /** @@ -169,7 +191,6 @@ class auth_outage_renderer extends plugin_renderer_base { * @param outage $outage The outage to show in the warning bar. * @param int|null $time Timestamp to send to the outage bar in order to render the outage. Null for current time. * @return string HTML of the warning bar. - * @SuppressWarnings("unused") because $countdown is used inside require(...) */ public function renderoutagebar(outage $outage, $time = null) { global $CFG; @@ -181,8 +202,8 @@ class auth_outage_renderer extends plugin_renderer_base { throw new \InvalidArgumentException('$time is not an int or null.'); } - $start = userdate($outage->starttime, get_string('strftimedatetimeshort')); - $stop = userdate($outage->stoptime, get_string('strftimedatetimeshort')); + $start = userdate($outage->starttime, get_string('datetimeformat', 'auth_outage')); + $stop = userdate($outage->stoptime, get_string('datetimeformat', 'auth_outage')); $countdown = get_string( $outage->is_ongoing($time) ? 'messageoutageongoing' : 'messageoutagewarning', @@ -190,6 +211,7 @@ class auth_outage_renderer extends plugin_renderer_base { ['start' => $start, 'stop' => $stop] ); + ob_start(); require($CFG->dirroot . '/auth/outage/views/warningbar.php'); $html = ob_get_contents(); diff --git a/tests/outage_test.php b/tests/outage_test.php index 79e4535..38c21dc 100644 --- a/tests/outage_test.php +++ b/tests/outage_test.php @@ -44,8 +44,8 @@ class outage_test extends basic_testcase { // In the past. $outage = new outage([ - 'starttime' => $now + (-3 * 60 * 60), - 'stoptime' => $now + (-2 * 60 * 60), + 'starttime' => $now - (3 * 60 * 60), + 'stoptime' => $now - (2 * 60 * 60), 'warntime' => $now - (2 * 60 * 60), 'title' => '', 'description' => '' @@ -54,7 +54,7 @@ class outage_test extends basic_testcase { // In the present (ongoing). $outage = new outage([ - 'starttime' => $now + (-1 * 60 * 60), + 'starttime' => $now - (1 * 60 * 60), 'stoptime' => $now + (1 * 60 * 60), 'warntime' => $now - (2 * 60 * 60), 'title' => '', @@ -72,4 +72,48 @@ class outage_test extends basic_testcase { ]); self::assertFalse($outage->is_ongoing($now)); } + + public function test_isactive() { + $now = time(); + + // In the past. + $outage = new outage([ + 'starttime' => $now - (3 * 60 * 60), + 'stoptime' => $now - (2 * 60 * 60), + 'warntime' => $now - (2 * 60 * 60), + 'title' => '', + 'description' => '' + ]); + self::assertFalse($outage->is_active($now)); + + // In the present (ongoing). + $outage = new outage([ + 'starttime' => $now - (1 * 60 * 60), + 'stoptime' => $now + (1 * 60 * 60), + 'warntime' => $now - (2 * 60 * 60), + 'title' => '', + 'description' => '' + ]); + self::assertTrue($outage->is_active($now)); + + // In the future (warning). + $outage = new outage([ + 'starttime' => $now + (1 * 60 * 60), + 'stoptime' => $now + (2 * 60 * 60), + 'warntime' => $now - (2 * 60 * 60), + 'title' => '', + 'description' => '' + ]); + self::assertTrue($outage->is_active($now)); + + // In the future (not warning). + $outage = new outage([ + 'starttime' => $now + (2 * 60 * 60), + 'stoptime' => $now + (3 * 60 * 60), + 'warntime' => $now + (1 * 60 * 60), + 'title' => '', + 'description' => '' + ]); + self::assertFalse($outage->is_active($now)); + } } diff --git a/views/infopage.php b/views/infopage.php new file mode 100644 index 0000000..e5e1084 --- /dev/null +++ b/views/infopage.php @@ -0,0 +1,50 @@ +. + +/** + * View included by the renderer to output the outage information page. + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); // It must be included from a Moodle page. +} +?> + +
+
+ + starttime, get_string('datetimeformat', 'auth_outage')); ?> +
+
+ + stoptime, get_string('datetimeformat', 'auth_outage')); ?> +
+
get_description(); ?>
+ + + + + +
diff --git a/views/warningbar.php b/views/warningbar.php index 23e0e21..d418417 100644 --- a/views/warningbar.php +++ b/views/warningbar.php @@ -67,11 +67,11 @@ echo html_writer::tag('style', , init: function () { this.span = document.getElementById('auth_outage_warningbar_countdown'); this.text = this.span.innerHTML; - this.tick(); var $this = this; this.timer = setInterval(function () { $this.tick(); }, 1000); + this.tick(); } , tick: function () { var elapsed = Math.round((Date.now() - this.clienttime) / 1000);