From ded6b2d005363cea76c3c51434c6bd698a8418c5 Mon Sep 17 00:00:00 2001 From: Daniel Thee Roperto Date: Fri, 23 Sep 2016 15:53:28 +1000 Subject: [PATCH] Issue #32 - UX improvements, detect end of outage and show in warning bar. Does not redirect user to info page anymore. --- checkfinished.php | 32 +++ classes/local/controllers/infopage.php | 9 +- classes/local/outagelib.php | 23 +- .../{local => }/output/manage/base_table.php | 2 +- .../output/manage/history_table.php | 2 +- .../output/manage/planned_table.php | 2 +- classes/output/renderer.php | 263 ++++++++++++++++++ lang/en/auth_outage.php | 2 + renderer.php | 196 +------------ views/info/content.php | 20 +- views/info/static.php | 19 +- views/warningbar.js | 51 ---- views/warningbar.php | 91 ------ views/{ => warningbar}/warningbar.css | 48 +++- views/warningbar/warningbar.js | 122 ++++++++ views/warningbar/warningbar.php | 93 +++++++ 16 files changed, 598 insertions(+), 377 deletions(-) create mode 100644 checkfinished.php rename classes/{local => }/output/manage/base_table.php (99%) rename classes/{local => }/output/manage/history_table.php (98%) rename classes/{local => }/output/manage/planned_table.php (98%) create mode 100644 classes/output/renderer.php delete mode 100644 views/warningbar.js delete mode 100644 views/warningbar.php rename views/{ => warningbar}/warningbar.css (50%) create mode 100644 views/warningbar/warningbar.js create mode 100644 views/warningbar/warningbar.php diff --git a/checkfinished.php b/checkfinished.php new file mode 100644 index 0000000..3700146 --- /dev/null +++ b/checkfinished.php @@ -0,0 +1,32 @@ +. + +/** + * Called async from warning bar to check if the outage has finished. + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright 2016 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +use auth_outage\dml\outagedb; + +require_once(__DIR__.'/../../config.php'); + +$active = outagedb::get_active(); + +echo $active ? 'ongoing' : 'finished'; diff --git a/classes/local/controllers/infopage.php b/classes/local/controllers/infopage.php index 965a97f..aed01bd 100644 --- a/classes/local/controllers/infopage.php +++ b/classes/local/controllers/infopage.php @@ -19,6 +19,7 @@ namespace auth_outage\local\controllers; use auth_outage\dml\outagedb; use auth_outage\local\outage; use auth_outage\local\outagelib; +use auth_outage\output\renderer; use coding_exception; use context_system; use file_exception; @@ -186,9 +187,15 @@ class infopage { } } + $viewbag = [ + 'admin' => is_siteadmin(), + 'outage' => $this->outage, + ]; + $PAGE->set_context(context_system::instance()); if ($this->static) { - require($CFG->dirroot.'/auth/outage/views/info/static.php'); + $viewbag['admin'] = false; + renderer::get()->output_view('info/static.php', $viewbag); } else { $PAGE->set_title($this->outage->get_title()); $PAGE->set_heading($this->outage->get_title()); diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php index 9686bfe..67dbfb2 100644 --- a/classes/local/outagelib.php +++ b/classes/local/outagelib.php @@ -18,7 +18,7 @@ namespace auth_outage\local; use auth_outage\dml\outagedb; use auth_outage\local\controllers\infopage; -use auth_outage_renderer; +use auth_outage\output\renderer; use Exception; use moodle_url; use stdClass; @@ -38,22 +38,13 @@ class outagelib { /** * Initializes admin pages for outage. - * @return auth_outage_renderer The outage renderer for the page. + * @return renderer The outage renderer for the page. */ public static function page_setup() { global $PAGE; admin_externalpage_setup('auth_outage_manage'); $PAGE->set_url(new moodle_url('/auth/outage/manage.php')); - return self::get_renderer(); - } - - /** - * Returns the outage renderer. - * @return auth_outage_renderer The outage renderer. - */ - public static function get_renderer() { - global $PAGE; - return $PAGE->get_renderer('auth_outage'); + return renderer::get(); } /** @@ -74,9 +65,10 @@ class outagelib { $previewid = optional_param('auth_outage_preview', null, PARAM_INT); $time = time(); if (is_null($previewid)) { - if (!$active = outagedb::get_active()) { + if (!$active = outagedb::get_active($time)) { return; } + $preview = false; } else { if (!$active = outagedb::get_by_id($previewid)) { return; @@ -86,10 +78,11 @@ class outagelib { if (!$active->is_active($time)) { return; } + $preview = true; } // There is a previewing or active outage. - $CFG->additionalhtmltopofbody = self::get_renderer()->renderoutagebar($active, $time). + $CFG->additionalhtmltopofbody = renderer::get()->render_warningbar($active, $time, false, $preview). $CFG->additionalhtmltopofbody; } catch (Exception $e) { debugging('Exception occured while injecting our code: '.$e->getMessage()); @@ -119,7 +112,7 @@ class outagelib { 'default_warning_duration' => 60, 'default_warning_title' => get_string('defaultwarningtitlevalue', 'auth_outage'), 'default_warning_description' => get_string('defaultwarningdescriptionvalue', 'auth_outage'), - 'css' => file_get_contents($CFG->dirroot.'/auth/outage/views/warningbar.css'), + 'css' => file_get_contents($CFG->dirroot.'/auth/outage/views/warningbar/warningbar.css'), ]; } diff --git a/classes/local/output/manage/base_table.php b/classes/output/manage/base_table.php similarity index 99% rename from classes/local/output/manage/base_table.php rename to classes/output/manage/base_table.php index 8e1cb3c..8a83ab5 100644 --- a/classes/local/output/manage/base_table.php +++ b/classes/output/manage/base_table.php @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . -namespace auth_outage\local\output\manage; +namespace auth_outage\output\manage; use auth_outage\local\outage; use flexible_table; diff --git a/classes/local/output/manage/history_table.php b/classes/output/manage/history_table.php similarity index 98% rename from classes/local/output/manage/history_table.php rename to classes/output/manage/history_table.php index 20b6da8..93a4760 100644 --- a/classes/local/output/manage/history_table.php +++ b/classes/output/manage/history_table.php @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . -namespace auth_outage\local\output\manage; +namespace auth_outage\output\manage; use auth_outage\local\outage; diff --git a/classes/local/output/manage/planned_table.php b/classes/output/manage/planned_table.php similarity index 98% rename from classes/local/output/manage/planned_table.php rename to classes/output/manage/planned_table.php index 3266f1c..84697fb 100644 --- a/classes/local/output/manage/planned_table.php +++ b/classes/output/manage/planned_table.php @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . -namespace auth_outage\local\output\manage; +namespace auth_outage\output\manage; use auth_outage\local\outage; use html_writer; diff --git a/classes/output/renderer.php b/classes/output/renderer.php new file mode 100644 index 0000000..9ff9e3f --- /dev/null +++ b/classes/output/renderer.php @@ -0,0 +1,263 @@ +. + +namespace auth_outage\output; + +use auth_outage\local\outage; +use auth_outage\output\manage\history_table; +use auth_outage\output\manage\planned_table; +use coding_exception; +use html_writer; +use moodle_url; +use plugin_renderer_base; + +defined('MOODLE_INTERNAL') || die(); + +/** + * auth_outage auth_outage_renderer + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright 2016 Catalyst IT + * @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. + * @param mixed[] $viewbag Values to be used in the view. + * @throws coding_exception + */ + public function output_view($view, $viewbag = []) { + global $CFG; + + $viewbag['viewfile'] = $view; + unset($view); + + require($CFG->dirroot.'/auth/outage/views/'.$viewbag['viewfile']); + } + + /** + * Renders the view in a separate scope to avoid conflicts with variable names. + * @param string $view View PHP file. + * @param mixed[] $viewbag Values to be used in the view. + * @return string The rendered view code. + */ + public function render_view($view, $viewbag = []) { + ob_start(); + $this->output_view($view, $viewbag); + $html = ob_get_contents(); + ob_end_clean(); + return $html; + } + + /** + * Renders the subtitle of the page. + * @param string $subtitlekey Key to be used and localized. + * @return string HTML for the subtitle. + * @throws coding_exception + */ + public function rendersubtitle($subtitlekey) { + if (!is_string($subtitlekey)) { + throw new coding_exception('$subtitlekeym is not a string.', $subtitlekey); + } + return html_writer::tag('h2', get_string($subtitlekey, 'auth_outage')); + } + + /** + * Renders a confirmation to delete an outage. + * @param outage $outage Outage to be deleted. + * @return string HTML for the page. + */ + public function renderdeleteconfirmation(outage $outage) { + return $this->rendersubtitle('outagedelete'). + html_writer::tag('p', get_string('outagedeletewarning', 'auth_outage')). + $this->renderoutage($outage, false); + } + + /** + * Renders a confirmation to finish an outage. + * @param outage $outage Outage to be finished. + * @return string HTML for the page. + */ + public function renderfinishconfirmation(outage $outage) { + return $this->rendersubtitle('outagefinish'). + html_writer::tag('p', get_string('outagefinishwarning', 'auth_outage')). + $this->renderoutage($outage, false); + } + + /** + * Outputs the HTML data listing all given outages. + * @param outage[] $future Outages to list as planned. + * @param outage[] $past Outages to list as history. + */ + public function renderoutagelist(array $future, array $past) { + global $OUTPUT; + + // Add 'add' button. + $url = new moodle_url('/auth/outage/new.php'); + $img = html_writer::empty_tag('img', + ['src' => $OUTPUT->pix_url('t/add'), 'alt' => get_string('create'), 'class' => 'iconsmall']); + echo html_writer::tag('p', + html_writer::link( + $url, + $img.' '.get_string('outagecreate', 'auth_outage'), + ['title' => get_string('delete')] + ) + ); + + echo $this->rendersubtitle('outageslistfuture'); + if (empty($future)) { + echo html_writer::tag('p', html_writer::tag('small', get_string('notfound', 'auth_outage'))); + } else { + $table = new planned_table(); + $table->set_data($future); + $table->finish_output(); + } + + echo $this->rendersubtitle('outageslistpast'); + if (empty($past)) { + echo html_writer::tag('p', html_writer::tag('small', get_string('notfound', 'auth_outage'))); + } else { + $table = new history_table(); + $table->set_data($past); + $table->finish_output(); + } + } + + /** + * Renders the warning bar. + * @param outage $outage The outage to show in the warning bar. + * @param int $time Timestamp to send to the outage bar in order to render the outage. + * @param bool $static If the warning bar is rendering in a static page. + * @param bool $preview If in preview mode the warning bar will not check if we are back online. + * @return string HTML of the warning bar. + * @throws coding_exception + * @SuppressWarnings("unused") because $viewbag is used inside require() + */ + public function render_warningbar(outage $outage, $time, $static, $preview) { + global $CFG; + if (!is_int($time) || ($time <= 0)) { + throw new coding_exception('$time is not an positive int or null.', $time); + } + if (!is_bool($static)) { + throw new coding_exception('$static is not a bool.'); + } + if (!is_bool($preview)) { + throw new coding_exception('$preview is not a bool.'); + } + + $viewbag = [ + 'time' => $time, + 'outage' => $outage, + 'static' => $static, + 'preview' => $preview, + ]; + + return $this->render_view('warningbar/warningbar.php', $viewbag); + } + + /** + * Returns the HTML for displaying and outage information. + * @param outage $outage Outage to display. + * @param bool $buttons If should display management buttons (edit, delete, etc). + * @return string The formatted HTML. + */ + private function renderoutage(outage $outage, $buttons) { + global $OUTPUT; + + if ($outage->createdby == 0) { + $created = get_string('na', 'auth_outage'); + } else { + $created = core_user::get_user($outage->createdby, 'firstname,lastname', MUST_EXIST); + $created = html_writer::link( + new moodle_url('/user/profile.php', ['id' => $outage->createdby]), + trim($created->firstname.' '.$created->lastname) + ); + } + + if ($outage->modifiedby == 0) { + $modified = get_string('na', 'auth_outage'); + } else { + $modified = core_user::get_user($outage->modifiedby, 'firstname,lastname', MUST_EXIST); + $modified = html_writer::link( + new moodle_url('/user/profile.php', ['id' => $outage->modifiedby]), + trim($modified->firstname.' '.$modified->lastname) + ); + } + + $url = new moodle_url('/auth/outage/edit.php', ['id' => $outage->id]); + $img = html_writer::empty_tag( + 'img', + ['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' => $OUTPUT->pix_url('t/delete'), 'alt' => get_string('delete'), 'class' => 'iconsmall'] + ); + $linkdelete = html_writer::link($url, $img, ['title' => get_string('delete')]); + + $finished = $outage->finished; + if (is_null($finished)) { + $finished = get_string('na', 'auth_outage'); + } else { + $finished = userdate($finished, get_string('datetimeformat', 'auth_outage')); + } + + 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) : '') + ) + ); + } +} diff --git a/lang/en/auth_outage.php b/lang/en/auth_outage.php index 4eac9d0..b12b871 100644 --- a/lang/en/auth_outage.php +++ b/lang/en/auth_outage.php @@ -83,6 +83,8 @@ $string['infostartofwarning'] = 'start of warning'; $string['infopagestaticgenerated'] = 'This warning was generated on {$a->time}.'; $string['menudefaults'] = 'Default Settings'; $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'; diff --git a/renderer.php b/renderer.php index 1ee8fe8..20d7473 100644 --- a/renderer.php +++ b/renderer.php @@ -14,206 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . -use auth_outage\local\outage; -use auth_outage\local\output\manage\history_table; -use auth_outage\local\output\manage\planned_table; - defined('MOODLE_INTERNAL') || die(); /** - * auth_outage auth_outage_renderer + * auth_outage auth_outage_renderer should just extend our renderer class in the classes directory. + * This is done to keep code organized and make easier to run tests and check coverage. * * @package auth_outage * @author Daniel Thee Roperto * @copyright 2016 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class auth_outage_renderer extends plugin_renderer_base { - /** - * Renders the subtitle of the page. - * @param string $subtitlekey Key to be used and localized. - * @return string HTML for the subtitle. - */ - public function rendersubtitle($subtitlekey) { - if (!is_string($subtitlekey)) { - throw new coding_exception('$subtitlekeym is not a string.', $subtitlekey); - } - return html_writer::tag('h2', get_string($subtitlekey, 'auth_outage')); - } - - /** - * Renders a confirmation to delete an outage. - * @param outage $outage Outage to be deleted. - * @return string HTML for the page. - */ - public function renderdeleteconfirmation(outage $outage) { - return $this->rendersubtitle('outagedelete'). - html_writer::tag('p', get_string('outagedeletewarning', 'auth_outage')). - $this->renderoutage($outage, false); - } - - /** - * Renders a confirmation to finish an outage. - * @param outage $outage Outage to be finished. - * @return string HTML for the page. - */ - public function renderfinishconfirmation(outage $outage) { - return $this->rendersubtitle('outagefinish'). - html_writer::tag('p', get_string('outagefinishwarning', 'auth_outage')). - $this->renderoutage($outage, false); - } - - /** - * Outputs the HTML data listing all given outages. - * @param outage[] $future Outages to list as planned. - * @param outage[] $past Outages to list as history. - */ - public function renderoutagelist(array $future, array $past) { - global $OUTPUT; - - // Add 'add' button. - $url = new moodle_url('/auth/outage/new.php'); - $img = html_writer::empty_tag('img', - ['src' => $OUTPUT->pix_url('t/add'), 'alt' => get_string('create'), 'class' => 'iconsmall']); - echo html_writer::tag('p', - html_writer::link( - $url, - $img.' '.get_string('outagecreate', 'auth_outage'), - ['title' => get_string('delete')] - ) - ); - - echo $this->rendersubtitle('outageslistfuture'); - if (empty($future)) { - echo html_writer::tag('p', html_writer::tag('small', get_string('notfound', 'auth_outage'))); - } else { - $table = new planned_table(); - $table->set_data($future); - $table->finish_output(); - } - - echo $this->rendersubtitle('outageslistpast'); - if (empty($past)) { - echo html_writer::tag('p', html_writer::tag('small', get_string('notfound', 'auth_outage'))); - } else { - $table = new history_table(); - $table->set_data($past); - $table->finish_output(); - } - } - - /** - * Renders the warning bar. - * @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; - - if (is_null($time)) { - $time = time(); - } - if (!is_int($time) || ($time <= 0)) { - throw new coding_exception('$time is not an positive int or null.', $time); - } - - $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', - 'auth_outage', - ['start' => $start, 'stop' => $stop] - ); - - ob_start(); - require($CFG->dirroot.'/auth/outage/views/warningbar.php'); - $html = ob_get_contents(); - ob_end_clean(); - return $html; - } - - /** - * Returns the HTML for displaying and outage information. - * @param outage $outage Outage to display. - * @param bool $buttons If should display management buttons (edit, delete, etc). - * @return string The formatted HTML. - */ - private function renderoutage(outage $outage, $buttons) { - global $OUTPUT; - - if ($outage->createdby == 0) { - $created = get_string('na', 'auth_outage'); - } else { - $created = core_user::get_user($outage->createdby, 'firstname,lastname', MUST_EXIST); - $created = html_writer::link( - new moodle_url('/user/profile.php', ['id' => $outage->createdby]), - trim($created->firstname.' '.$created->lastname) - ); - } - - if ($outage->modifiedby == 0) { - $modified = get_string('na', 'auth_outage'); - } else { - $modified = core_user::get_user($outage->modifiedby, 'firstname,lastname', MUST_EXIST); - $modified = html_writer::link( - new moodle_url('/user/profile.php', ['id' => $outage->modifiedby]), - trim($modified->firstname.' '.$modified->lastname) - ); - } - - $url = new moodle_url('/auth/outage/edit.php', ['id' => $outage->id]); - $img = html_writer::empty_tag( - 'img', - ['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' => $OUTPUT->pix_url('t/delete'), 'alt' => get_string('delete'), 'class' => 'iconsmall'] - ); - $linkdelete = html_writer::link($url, $img, ['title' => get_string('delete')]); - - $finished = $outage->finished; - if (is_null($finished)) { - $finished = get_string('na', 'auth_outage'); - } else { - $finished = userdate($finished, get_string('datetimeformat', 'auth_outage')); - } - - 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) : '') - ) - ); - } +class auth_outage_renderer extends auth_outage\output\renderer { } diff --git a/views/info/content.php b/views/info/content.php index be85d6b..f99f2bd 100644 --- a/views/info/content.php +++ b/views/info/content.php @@ -25,20 +25,20 @@ defined('MOODLE_INTERNAL') || die(); -if ($this->has_admin_options()) { +if ($viewbag['admin']) { $adminlinks = []; foreach ([ - 'startofwarning' => -$this->outage->get_warning_duration(), + 'startofwarning' => -$viewbag['outage']->get_warning_duration(), '15secondsbefore' => -15, 'start' => 0, - 'endofoutage' => $this->outage->get_duration_planned(), + 'endofoutage' => $viewbag['outage']->get_duration_planned() - 1, ] as $title => $delta) { $adminlinks[] = html_writer::link( new moodle_url( '/auth/outage/info.php', [ - 'id' => $this->outage->id, - 'auth_outage_preview' => $this->outage->id, + 'id' => $viewbag['outage']->id, + 'auth_outage_preview' => $viewbag['outage']->id, 'auth_outage_delta' => $delta, ] ), @@ -47,7 +47,7 @@ if ($this->has_admin_options()) { } $admineditlink = html_writer::link( - new moodle_url('/auth/outage/edit.php', ['id' => $this->outage->id]), + new moodle_url('/auth/outage/edit.php', ['id' => $viewbag['outage']->id]), get_string('outageedit', 'auth_outage') ); } @@ -57,15 +57,15 @@ if ($this->has_admin_options()) {
- outage->starttime, get_string('datetimeformat', 'auth_outage')); ?> + starttime, get_string('datetimeformat', 'auth_outage')); ?>
- outage->stoptime, get_string('datetimeformat', 'auth_outage')); ?> + stoptime, get_string('datetimeformat', 'auth_outage')); ?>
-
outage->get_description(); ?>
+
get_description(); ?>
- has_admin_options()): ?> +