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'