Issue #30 - Add finished flag to mark the real time that an outage was finished.

This commit is contained in:
Daniel Thee Roperto
2016-09-15 18:24:36 +10:00
parent 7ca44c74ab
commit 2cfda63922
17 changed files with 508 additions and 210 deletions

View File

@@ -43,17 +43,4 @@ class delete extends \moodleform {
$this->add_action_buttons(true, get_string('delete'));
}
/**
* Validate the parts of the request form for this module
*
* @param array $data An array of form data
* @param array $files An array of form files
* @return array of error messages
*/
public function validation($data, $files) {
$errors = parent::validation($data, $files);
return $errors;
}
}

View File

@@ -0,0 +1,47 @@
<?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/>.
namespace auth_outage\forms\outage;
use moodleform;
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); // It must be included from a Moodle page.
}
require_once($CFG->libdir . '/formslib.php');
/**
* Outage finish confirmation form.
*
* @package auth_outage
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class finish extends moodleform {
/**
* Defines the form elements.
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$this->add_action_buttons(true, get_string('finish', 'auth_outage'));
}
}

View File

@@ -16,7 +16,7 @@
namespace auth_outage\models;
use auth_outage\outagelib;
use InvalidArgumentException;
/**
* Outage class with all information about one specific outage.
@@ -27,6 +27,31 @@ use auth_outage\outagelib;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class outage {
/**
* Outage is before warning period.
*/
const STAGE_WAITING = 1;
/**
* Outage not started but in warning period.
*/
const STAGE_WARNING = 2;
/**
* Outage ongoing, it has passed the warning period.
*/
const STAGE_ONGOING = 3;
/**
* Outage finished, it is after the marked finished time.
*/
const STAGE_FINISHED = 4;
/**
* Outage stopped, it is after the stop time and not marked as finished.
*/
const STAGE_STOPPED = 4;
/**
* @var int Outage ID (auto generated by the DB).
*/
@@ -47,6 +72,11 @@ class outage {
*/
public $warntime = null;
/**
* @var int|null Finished timestamp, null if not marked as finished yet.
*/
public $finished = null;
/**
* @var string Short description of the outage (no HTML).
*/
@@ -75,25 +105,59 @@ class outage {
/**
* outage constructor.
* @param object|array|null The data for the outage.
* @throws InvalidArgumentException
*/
public function __construct($data = null) {
if (is_null($data)) {
return;
}
if (is_object($data) || is_array($data)) {
outagelib::data2object($data, $this);
// Adjust field types as needed.
$fields = ['createdby', 'id', 'lastmodified', 'modifiedby', 'starttime', 'stoptime', 'warntime'];
foreach ($fields as $f) {
$this->$f = ($this->$f === null) ? null : (int)$this->$f;
}
return;
if (is_object($data)) {
$data = (array)$data;
}
if (!is_array($data)) {
throw new InvalidArgumentException('$data is not an object, an array or null.');
}
throw new \InvalidArgumentException('$data must be null (default), an array or an object.');
// Load data from array.
foreach ($data as $k => $v) {
if (property_exists(self::class, $k)) {
$this->$k = $v;
}
}
// Adjust int fields.
$fs = ['createdby', 'id', 'lastmodified', 'modifiedby', 'starttime', 'stoptime', 'warntime', 'finished'];
foreach ($fs as $f) {
$this->$f = ($this->$f === null) ? null : (int)$this->$f;
}
}
/**
* Gets at which stage is this outage.
* @param int|null $time Null to check the current stage or a timestamp to check for another time.
* @return int Stage, compare with STAGE_* constants.
*/
public function get_stage($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->finished) && ($time >= $this->finished)) {
return self::STAGE_FINISHED;
}
if ($time >= $this->stoptime) {
return self::STAGE_STOPPED;
}
if ($time < $this->warntime) {
return self::STAGE_WAITING;
}
if ($time < $this->starttime) {
return self::STAGE_WARNING;
}
return self::STAGE_ONGOING;
}
/**
@@ -102,17 +166,13 @@ class outage {
* @return bool True if outage is ongoing or during the warning period.
*/
public function is_active($time = null) {
if ($time === null) {
$time = time();
switch ($this->get_stage($time)) {
case self::STAGE_WARNING:
case self::STAGE_ONGOING:
return true;
default:
return false;
}
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));
}
/**
@@ -121,17 +181,22 @@ class outage {
* @return bool True if outage has started but not yet stopped. False otherwise including if in warning period.
*/
public function is_ongoing($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->starttime) || is_null($this->stoptime)) {
return false;
}
return ($this->get_stage($time) == self::STAGE_ONGOING);
}
return (($this->starttime <= $time) && ($time < $this->stoptime));
/**
* Checks if the outage has ended (either marked as finished or after stop time).
* @param int|null $time Null to check if the outage has already ended or another time to use as reference.
* @return bool True if outage has been marked as finished after the provided time or it has already stopped.
*/
public function has_ended($time = null) {
switch ($this->get_stage($time)) {
case self::STAGE_FINISHED:
case self::STAGE_STOPPED:
return true;
default:
return false;
}
}
/**

View File

@@ -171,10 +171,12 @@ class outagedb {
throw new InvalidArgumentException('$time must be null or an int.');
}
$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',
'(warntime <= :datetime1 AND stoptime >= :datetime2)',
['datetime1' => $time, 'datetime2' => $time],
$select,
['datetime1' => $time, 'datetime2' => $time, 'datetime3' => $time],
'starttime ASC, stoptime DESC, title ASC',
'*',
0,
@@ -187,11 +189,11 @@ class outagedb {
}
/**
* Gets all future outages not in warning period.
* Gets all outages that have not ended yet.
* @param int|null $time Timestamp considered to check for outages, null for current date/time.
* @return array An array of outages or an empty array if no future outage found.
* @return array An array of outages or an empty array if no unded outages were found.
*/
public static function get_all_future($time = null) {
public static function get_all_unended($time = null) {
global $DB;
if ($time === null) {
@@ -205,8 +207,8 @@ class outagedb {
$rs = $DB->get_recordset_select(
'auth_outage',
'stoptime >= :datetime',
['datetime' => $time],
':datetime1 < stoptime AND (finished IS NULL OR :datetime2 < finished)',
['datetime1' => $time, 'datetime2' => $time],
'starttime ASC, stoptime DESC, title ASC',
'*');
foreach ($rs as $r) {
@@ -218,11 +220,11 @@ class outagedb {
}
/**
* Gets all past outages.
* Gets all ended outages.
* @param int|null $time Timestamp considered to check for outages, null for current date/time.
* @return array An array of outages or an empty array if no past outage found.
* @return array An array of outages or an empty array if no ended outages found.
*/
public static function get_all_past($time = null) {
public static function get_all_ended($time = null) {
global $DB;
if ($time === null) {
@@ -236,8 +238,8 @@ class outagedb {
$rs = $DB->get_recordset_select(
'auth_outage',
'stoptime < :datetime',
['datetime' => $time],
':datetime1 >= stoptime OR (finished IS NOT NULL AND :datetime2 >= finished)',
['datetime1' => $time, 'datetime2' => $time],
'stoptime DESC, starttime DESC, title ASC',
'*');
foreach ($rs as $r) {
@@ -248,6 +250,34 @@ class outagedb {
return $outages;
}
/**
* Marks an outage as finished.
* @param int $id Outage id.
* @param int|null $time Timestamp to consider as finished date or null for current time.
*/
public static function finish($id, $time = null) {
if (is_null($time)) {
$time = time();
}
if (!is_int($time)) {
throw new InvalidArgumentException('$time must be an int or null.');
}
$outage = self::get_by_id($id);
if (is_null($outage)) {
debugging('Cannot finish outage #' . $id . ': outage not found.');
return;
}
if (!$outage->is_ongoing($time)) {
debugging('Cannot finish outage #' . $id . ': outage not ongoing.');
return;
}
$outage->finished = $time;
self::save($outage);
}
/**
* Create an event on the calendar for this outage.
* @param outage $outage Outage to be added to the calendar.

View File

@@ -17,6 +17,7 @@
namespace auth_outage;
use auth_outage_renderer;
use moodle_url;
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); // It must be included from a Moodle page.
@@ -40,7 +41,7 @@ class outagelib {
public static function pagesetup() {
global $PAGE;
admin_externalpage_setup('auth_outage_manage');
$PAGE->set_url(new \moodle_url('/auth/outage/manage.php'));
$PAGE->set_url(new moodle_url('/auth/outage/manage.php'));
return self::get_renderer();
}
@@ -87,31 +88,4 @@ class outagelib {
$CFG->additionalhtmltopofbody = self::get_renderer()->renderoutagebar($active, $time)
. $CFG->additionalhtmltopofbody;
}
/**
* Loads data from an object or array into another object. It ensures no new fields are created in the $obj.
*
* @param $data mixed An object or array.
* @param $obj object Destination object to write the properties.
*/
public static function data2object($data, $obj) {
if (is_object($data)) {
$data = get_object_vars($data);
}
if (!is_array($data)) {
throw new \InvalidArgumentException('$data must be an array or an object.');
}
if (!is_object($obj)) {
throw new \InvalidArgumentException('$obj must be an object.');
}
foreach ($data as $k => $v) {
if (property_exists($obj, $k)) {
if (method_exists($obj, $k)) {
throw new \InvalidArgumentException('$obj has a method called ' . $k);
}
$obj->$k = $v;
}
}
}
}

View File

@@ -18,6 +18,8 @@ namespace auth_outage\tables;
use auth_outage\models\outage;
use flexible_table;
use html_writer;
use moodle_url;
require_once($CFG->libdir . '/tablelib.php');
@@ -42,12 +44,13 @@ class manage extends flexible_table {
$id = (is_null($id) ? self::$autoid++ : $id);
parent::__construct('auth_outage_manage_' . $id);
$this->define_columns(['starttime', 'stopsafter', 'warnbefore', 'title', '']);
$this->define_columns(['starttime', 'stopsafter', 'warnbefore', 'finished', 'title', '']);
$this->define_headers([
get_string('tableheaderwarnbefore', 'auth_outage'),
get_string('tableheaderstarttime', 'auth_outage'),
get_string('tableheaderstopsafter', 'auth_outage'),
get_string('tableheaderfinishedat', 'auth_outage'),
get_string('tableheadertitle', 'auth_outage'),
get_string('actions'),
]
@@ -60,7 +63,7 @@ class manage extends flexible_table {
/**
* Sets the data of the table.
* @param array $outages An array with outage objects.
* @param outage[] $outages An array with outage objects.
* @param bool $editdelete If it should display the edit and delete button.
*/
public function set_data(array $outages, $editdelete) {
@@ -71,17 +74,21 @@ class manage extends flexible_table {
foreach ($outages as $outage) {
$title = $outage->get_title();
if ($editdelete) {
$title = \html_writer::link(
new \moodle_url('/auth/outage/edit.php', ['id' => $outage->id]),
$title = html_writer::link(
new moodle_url('/auth/outage/edit.php', ['id' => $outage->id]),
$title,
['title' => get_string('edit')]
);
}
$finished = $outage->finished;
$finished = is_null($finished) ? '-' : userdate($finished, get_string('datetimeformat', 'auth_outage'));
$this->add_data([
format_time($outage->get_warning_duration()),
userdate($outage->starttime, get_string('datetimeformat', 'auth_outage')),
format_time($outage->get_duration()),
$finished,
$title,
$this->set_data_buttons($outage, $editdelete),
]);
@@ -99,9 +106,9 @@ class manage extends flexible_table {
$buttons = '';
// View button.
$buttons .= \html_writer::link(
new \moodle_url('/auth/outage/info.php', ['id' => $outage->id]),
\html_writer::empty_tag('img', [
$buttons .= html_writer::link(
new moodle_url('/auth/outage/info.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->pix_url('t/preview'),
'alt' => get_string('view'),
'class' => 'iconsmall',
@@ -113,11 +120,11 @@ class manage extends flexible_table {
]
);
// Edit button.
// Edit button if required.
if ($editdelete) {
$buttons .= \html_writer::link(
new \moodle_url('/auth/outage/edit.php', ['id' => $outage->id]),
\html_writer::empty_tag('img', [
$buttons .= html_writer::link(
new moodle_url('/auth/outage/edit.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->pix_url('t/edit'),
'alt' => get_string('edit'),
'class' => 'iconsmall'
@@ -127,9 +134,9 @@ class manage extends flexible_table {
}
// Clone button.
$buttons .= \html_writer::link(
new \moodle_url('/auth/outage/clone.php', ['id' => $outage->id]),
\html_writer::empty_tag('img', [
$buttons .= html_writer::link(
new moodle_url('/auth/outage/clone.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->pix_url('t/copy'),
'alt' => get_string('clone', 'auth_outage'),
'class' => 'iconsmall',
@@ -138,11 +145,24 @@ class manage extends flexible_table {
['title' => get_string('clone', 'auth_outage')]
);
// Delete button.
// Finish button if ongoing.
if ($outage->is_ongoing()) {
$buttons .= html_writer::link(
new moodle_url('/auth/outage/finish.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->pix_url('t/check'),
'alt' => get_string('finish', 'auth_outage'),
'class' => 'iconsmall'
]),
['title' => get_string('finish', 'auth_outage')]
);
}
// Delete button if required.
if ($editdelete) {
$buttons .= \html_writer::link(
new \moodle_url('/auth/outage/delete.php', ['id' => $outage->id]),
\html_writer::empty_tag('img', [
$buttons .= html_writer::link(
new moodle_url('/auth/outage/delete.php', ['id' => $outage->id]),
html_writer::empty_tag('img', [
'src' => $OUTPUT->pix_url('t/delete'),
'alt' => get_string('delete'),
'class' => 'iconsmall'

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="auth/outage/db" VERSION="20160908" COMMENT="XMLDB file for Moodle auth/outage"
<XMLDB PATH="auth/outage/db" VERSION="20160915" COMMENT="XMLDB file for Moodle auth/outage"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@@ -15,6 +15,7 @@
<FIELD NAME="createdby" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Who created this entry."/>
<FIELD NAME="modifiedby" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Who last modified this entry."/>
<FIELD NAME="lastmodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="When was this entry last modified."/>
<FIELD NAME="finished" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Timestamp of when the outage really finished."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

59
finish.php Normal file
View File

@@ -0,0 +1,59 @@
<?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/>.
/**
* Mark an outage as finished.
*
* @package auth_outage
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use auth_outage\outagedb;
use auth_outage\outagelib;
require_once('../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->libdir . '/formslib.php');
$renderer = outagelib::pagesetup();
$mform = new \auth_outage\forms\outage\finish();
if ($mform->is_cancelled()) {
redirect('/auth/outage/manage.php');
} else if ($fromform = $mform->get_data()) {
outagedb::finish($fromform->id);
redirect('/auth/outage/manage.php');
}
$id = required_param('id', PARAM_INT);
$outage = outagedb::get_by_id($id);
if ($outage == null) {
throw new invalid_parameter_exception('Outage #' . $id . ' not found.');
}
$dataid = new stdClass();
$dataid->id = $outage->id;
$mform->set_data($dataid);
echo $OUTPUT->header();
echo $renderer->renderfinishconfirmation($outage);
$mform->display();
echo $OUTPUT->footer();

View File

@@ -40,6 +40,7 @@ $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['finish'] = 'Finish';
$string['info15secondsbefore'] = '15 seconds before';
$string['infoendofoutage'] = 'end of outage';
$string['infofrom'] = 'From:';
@@ -59,11 +60,14 @@ $string['outagedeletewarning'] = 'You are about to permanently delete the outage
$string['outageduration'] = 'Outage Duration';
$string['outagedurationerrorinvalid'] = 'Outage duration must be positive.';
$string['outageduration_help'] = 'How long the outage lasts after it starts.';
$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['pluginname'] = 'Outage manager';
$string['starttime'] = 'Start date and time';
$string['starttime_help'] = 'At which date and time the outage starts, preventing general access to the system.';
$string['tableheaderfinishedat'] = 'Finished at';
$string['tableheaderstarttime'] = 'Starts on';
$string['tableheaderstopsafter'] = 'Stops after';
$string['tableheaderwarnbefore'] = 'Warns before';

View File

@@ -33,6 +33,6 @@ $renderer = outagelib::pagesetup();
echo $OUTPUT->header();
$renderer->renderoutagelist(outagedb::get_all_future(), outagedb::get_all_past());
$renderer->renderoutagelist(outagedb::get_all_unended(), outagedb::get_all_ended());
echo $OUTPUT->footer();

View File

@@ -15,7 +15,6 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
use auth_outage\models\outage;
use auth_outage\models\outageform;
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); // It must be included from a Moodle page.
@@ -53,9 +52,21 @@ class auth_outage_renderer extends plugin_renderer_base {
. $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 array $outages Outages to list.
* @param array $future Outages to list as planned.
* @param array $past Outages to list as history.
*/
public function renderoutagelist(array $future, array $past) {
global $OUTPUT;
@@ -91,6 +102,12 @@ class auth_outage_renderer extends plugin_renderer_base {
}
}
/**
* 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;
@@ -120,30 +137,37 @@ class auth_outage_renderer extends plugin_renderer_base {
);
$linkdelete = html_writer::link($url, $img, ['title' => get_string('delete')]);
// TODO use language pack below, solve together with Issue #12.
$finished = $outage->finished;
$finished = is_null($finished) ? '-' : userdate($finished, get_string('datetimeformat', 'auth_outage'));
return html_writer::div(
html_writer::span(
html_writer::tag('b', $outage->title, ['data-id' => $outage->id])
. html_writer::empty_tag('br')
. html_writer::tag('i', $outage->description)
. html_writer::empty_tag('br')
. html_writer::tag('b', 'Warning: ')
. userdate($outage->warntime, '%d %h %Y %l:%M%P')
. html_writer::empty_tag('br')
. html_writer::tag('b', 'Starts: ')
. userdate($outage->starttime, '%d %h %Y %l:%M%P')
. html_writer::empty_tag('br')
. html_writer::tag('b', 'Stops: ')
. userdate($outage->stoptime, '%d %h %Y %l:%M%P')
. html_writer::empty_tag('br')
. html_writer::tag('small',
'Created by ' . $created
. ', modified by ' . $modified . ' on '
. userdate($outage->lastmodified, '%d %h %Y %l:%M%P')
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::empty_tag('br')
. ($buttons ? $linkedit . $linkdelete . html_writer::empty_tag('br') : '')
. html_writer::empty_tag('br')
. 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('tableheaderstopsafter', 'auth_outage') . ': ')
. format_time($outage->get_duration())
)
. html_writer::div(
html_writer::tag('b', get_string('tableheaderfinishedat', '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) : '')
)
);
}

View File

@@ -114,4 +114,70 @@ class outage_test extends basic_testcase {
]);
self::assertFalse($outage->is_active($now));
}
public function test_stages() {
$now = time();
$outage = new outage([
'warntime' => $now + 10,
'starttime' => $now + 20,
'stoptime' => $now + 30,
'title' => 'Outage Waiting',
]);
self::assertSame(outage::STAGE_WAITING, $outage->get_stage($now));
self::assertFalse($outage->is_active($now));
self::assertFalse($outage->is_ongoing($now));
$outage = new outage([
'warntime' => $now - 10,
'starttime' => $now + 20,
'stoptime' => $now + 30,
'title' => 'Outage Warning',
]);
self::assertSame(outage::STAGE_WARNING, $outage->get_stage($now));
self::assertTrue($outage->is_active($now));
self::assertFalse($outage->is_ongoing($now));
$outage = new outage([
'warntime' => $now - 20,
'starttime' => $now - 10,
'stoptime' => $now + 30,
'title' => 'Outage Ongoing',
]);
self::assertSame(outage::STAGE_ONGOING, $outage->get_stage($now));
self::assertTrue($outage->is_active($now));
self::assertTrue($outage->is_ongoing($now));
$outage = new outage([
'warntime' => $now - 50,
'starttime' => $now - 40,
'stoptime' => $now - 30,
'title' => 'Outage Stopped',
]);
self::assertSame(outage::STAGE_STOPPED, $outage->get_stage($now));
self::assertFalse($outage->is_active($now));
self::assertFalse($outage->is_ongoing($now));
$outage = new outage([
'warntime' => $now - 50,
'starttime' => $now - 40,
'finishtime' => $now - 30,
'stoptime' => $now - 20,
'title' => 'Outage Finished before Stop',
]);
self::assertSame(outage::STAGE_FINISHED, $outage->get_stage($now));
self::assertFalse($outage->is_active($now));
self::assertFalse($outage->is_ongoing($now));
$outage = new outage([
'warntime' => $now - 50,
'starttime' => $now - 40,
'stoptime' => $now - 30,
'finishtime' => $now - 20,
'title' => 'Outage Finished after Stop',
]);
self::assertSame(outage::STAGE_FINISHED, $outage->get_stage($now));
self::assertFalse($outage->is_active($now));
self::assertFalse($outage->is_ongoing($now));
}
}

View File

@@ -92,6 +92,26 @@ class outagedb_test extends advanced_testcase {
self::assertNull(outagedb::get_by_id($id));
}
/**
* Make sure we can finish outages.
*/
public function test_finish() {
$now = time();
$this->resetAfterTest(true);
// Create it.
$id = self::saveoutage($now, -3, -2, 2, 'An ongoing outage.');
$outage = outagedb::get_by_id($id);
self::assertTrue($outage->is_active($now));
self::assertTrue($outage->is_ongoing($now));
self::assertSame(null, $outage->finished);
// Finish it.
outagedb::finish($id, $now);
$outage = outagedb::get_by_id($id);
self::assertSame($now, $outage->finished);
self::assertFalse($outage->is_active($now));
self::assertFalse($outage->is_ongoing($now));
}
/**
* Make sure getall brings all entries.
*/
@@ -176,6 +196,9 @@ class outagedb_test extends advanced_testcase {
'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.');
self::saveoutage($now, -3, -2, 2, 'An finished outage.', -1);
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
$activeid = self::saveoutage($now, -3, -2, 2,
'An ongoing outage.');
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
@@ -189,97 +212,106 @@ class outagedb_test extends advanced_testcase {
self::assertSame($activeid, outagedb::get_active($now)->id, 'Wrong active outage picked.');
}
public function test_getallfuture() {
public function test_getallunended() {
$this->resetAfterTest(true);
// Have a consistent time for now (no seconds variation), helps debugging.
$now = time();
self::assertEquals([], outagedb::get_all(), 'Ensure there are no other outages that can affect the test.');
self::assertEquals([], outagedb::get_all_future($now), 'There should be no future outages at this point.');
self::assertEquals([], outagedb::get_all_unended($now), 'There should be no future outages at this point.');
self::saveoutage($now, -3, -2, -1, 'A past outage.');
self::assertEquals([], outagedb::get_all_future($now), 'No future outages yet.');
self::assertEquals([], outagedb::get_all_unended($now), 'No future outages yet.');
self::saveoutage($now, -3, -2, 2, 'A finished outage.', -1);
self::assertEquals([], outagedb::get_all_unended($now), 'No future outages yet.');
$id1 = self::saveoutage($now, 2, 3, 4, 'A future outage.');
self::assertEquals([$id1],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id2 = self::saveoutage($now, 1, 4, 5, 'Another future outage.');
self::assertEquals([$id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id3 = self::saveoutage($now, 1, 3, 5, 'Yet another future outage.');
self::assertEquals([$id3, $id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id4 = self::saveoutage($now, -2, 1, 2, 'An outage in warning period.');
self::assertEquals([$id4, $id3, $id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id5 = self::saveoutage($now, -1, 2, 3, 'Another outage in warning period.');
self::assertEquals([$id4, $id5, $id3, $id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id6 = self::saveoutage($now, -3, -2, 2, 'An ongoing outage.');
self::assertEquals([$id6, $id4, $id5, $id3, $id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id7 = self::saveoutage($now, -3, -1, 1, 'Another ongoing outage.');
self::assertEquals([$id6, $id7, $id4, $id5, $id3, $id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
$id8 = self::saveoutage($now, -3, -2, 1, 'Yet another ongoing outage.');
self::assertEquals([$id6, $id8, $id7, $id4, $id5, $id3, $id1, $id2],
self::createidarray(outagedb::get_all_future($now)), 'Wrong future data.');
self::createidarray(outagedb::get_all_unended($now)), 'Wrong future data.');
}
public function test_getallpast() {
public function test_getallended() {
$this->resetAfterTest(true);
// Have a consistent time for now (no seconds variation), helps debugging.
$now = time();
self::assertEquals([], outagedb::get_all(), 'Ensure there are no other outages that can affect the test.');
self::assertEquals([], outagedb::get_all_past($now), 'There should be no future outages at this point.');
self::assertEquals([], outagedb::get_all_ended($now), 'There should be no future outages at this point.');
self::saveoutage($now, -2, 1, 2, 'An outage in warning period.');
self::assertEquals([], outagedb::get_all_past($now), 'No past outages yet.');
self::assertEquals([], outagedb::get_all_ended($now), 'No past outages yet.');
self::saveoutage($now, -3, -2, 2, 'An ongoing outage.');
self::assertEquals([], outagedb::get_all_past($now), 'No past outages yet.');
self::assertEquals([], outagedb::get_all_ended($now), 'No past outages yet.');
self::saveoutage($now, 2, 3, 4, 'A future outage.');
self::assertEquals([], outagedb::get_all_past($now), 'No past outages yet.');
self::assertEquals([], outagedb::get_all_ended($now), 'No past outages yet.');
$id1 = self::saveoutage($now, -8, -6, -4, 'A past outage.');
self::assertEquals([$id1],
self::createidarray(outagedb::get_all_past($now)), 'Wrong past data.');
self::createidarray(outagedb::get_all_ended($now)), 'Wrong past data.');
$id2 = self::saveoutage($now, -8, -7, -5, 'Another past outage.');
self::assertEquals([$id1, $id2],
self::createidarray(outagedb::get_all_past($now)), 'Wrong past data.');
self::createidarray(outagedb::get_all_ended($now)), 'Wrong past data.');
$id3 = self::saveoutage($now, -8, -5, -3, 'Yet another past outage.');
self::assertEquals([$id3, $id1, $id2],
self::createidarray(outagedb::get_all_past($now)), 'Wrong past data.');
self::createidarray(outagedb::get_all_ended($now)), 'Wrong past data.');
$id4 = self::saveoutage($now, -3, -2, 2, 'A finished outage.', -1);
self::assertEquals([$id4, $id3, $id1, $id2],
self::createidarray(outagedb::get_all_ended($now)), 'Wrong past data.');
}
/**
* Helper function to create an outage then save it to the database.
*
* @param $now int Timestamp for now, such as time().
* @param $warning int In how many hours the warning starts. Can be negative.
* @param $start int In how many hours this outage starts. Can be negative.
* @param $stop int In how many hours this outage finishes. Can be negative.
* @param $title string Title for the outage.
* @param int $now Timestamp for now, such as time().
* @param int $warning In how many hours the warning starts. Can be negative.
* @param int $start In how many hours this outage starts. Can be negative.
* @param int $stop In how many hours this outage finishes. Can be negative.
* @param string $title Title for the outage.
* @param int|null $finished In how many hours this outage is marked as finished. Can be negative or null.
* @return int Id the of created outage.
*/
private static function saveoutage($now, $warning, $start, $stop, $title) {
private static function saveoutage($now, $warning, $start, $stop, $title, $finished = null) {
return outagedb::save(new outage([
'warntime' => $now + ($warning * 60 * 60),
'starttime' => $now + ($start * 60 * 60),
'stoptime' => $now + ($stop * 60 * 60),
'warntime' => $now + ($warning * 60 * 60),
'finished' => is_null($finished) ? null : ($now + ($finished * 60 * 60)),
'title' => $title,
'description' => 'Test Outage Description.'
]));

View File

@@ -1,50 +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/>.
use auth_outage\outagelib;
defined('MOODLE_INTERNAL') || die();
/**
* Tests performed on outageutils class.
*
* @package auth_outage
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
* @copyright Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class outagelib_test extends basic_testcase
{
public function test_data2object() {
// Using object data, no new fields.
$obj = new stdClass();
$obj->foo = 'bar';
$obj->number = 42;
$data = new stdClass();
$data->foo = 'not bar';
outagelib::data2object($data, $obj);
self::assertEquals(get_object_vars($obj), ['foo' => 'not bar', 'number' => 42], 'Invalid result.');
self::assertEquals(get_object_vars($data), ['foo' => 'not bar'], 'Data should not change.');
// Using array data, with new fields.
$obj = new stdClass();
$obj->foo = 'bar';
$obj->number = 42;
$data = ['foo' => 'foobar', 'flag' => false];
outagelib::data2object($data, $obj);
self::assertEquals(get_object_vars($obj), ['foo' => 'foobar', 'number' => 42], 'Invalid result.');
}
}

View File

@@ -29,7 +29,7 @@ if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); // It must be included from a Moodle page.
}
$plugin->version = 2016090900; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2016091500; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = $plugin->version; // Same as version
$plugin->requires = 2014051200; // Requires Moodle 2.7 or later.
$plugin->component = "auth_outage";

View File

@@ -34,10 +34,27 @@ If you need to make changes here, remember to update your settings inside Moodle
margin: 10px 0;
}
.auth_outage_warningbar_box_message A {
A.auth_outage_warningbar_box_title {
color: white;
}
A.auth_outage_warningbar_box_finish {
background-color: white;
border: 1px solid black;
border-radius: 5px;
color: darkgray;
font-weight: bold;
margin-left: 10px;
padding-left: 5px;
padding-right: 10px;
text-decoration: none;
transition: background-color 200ms linear;
}
A.auth_outage_warningbar_box_finish:hover {
background-color: black;
}
.navbar.navbar-fixed-top {
top: 90px;
}

View File

@@ -27,6 +27,8 @@ if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); // It must be included from a Moodle page.
}
global $OUTPUT;
$infolink = new moodle_url('/auth/outage/info.php', ['id' => $outage->id]);
echo html_writer::tag('style', get_config('auth_outage', 'css'));
@@ -35,8 +37,28 @@ echo html_writer::tag('style', get_config('auth_outage', 'css'));
<div id="auth_outage_warningbar_box">
<div class="auth_outage_warningbar_center">
<div id="auth_outage_warningbar_countdown"><?php echo $countdown; ?></div>
<div class="auth_outage_warningbar_box_message">
<?php echo html_writer::link($infolink, $outage->get_title(), ['target' => '_blank']); ?>
<div>
<?php
echo html_writer::link(
$infolink,
$outage->get_title(),
['target' => '_blank', 'class' => 'auth_outage_warningbar_box_title']
);
if (is_siteadmin() && $outage->is_ongoing()) {
$url = new moodle_url('/auth/outage/finish.php', ['id' => $outage->id]);
$text = html_writer::empty_tag('img', [
'src' => $OUTPUT->pix_url('t/check'),
'alt' => get_string('finish', 'auth_outage'),
'class' => 'iconsmall'
]) . ' ' . get_string('finish', 'auth_outage');
$attr = [
'title' => get_string('finish', 'auth_outage'),
'class' => 'auth_outage_warningbar_box_finish'
];
echo html_writer::link($url, $text, $attr);
}
?>
</div>
</div>
</div>