summaryrefslogtreecommitdiffstats
path: root/library/Icinga/Web/Announcement
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/Icinga/Web/Announcement.php158
-rw-r--r--library/Icinga/Web/Announcement/AnnouncementCookie.php138
-rw-r--r--library/Icinga/Web/Announcement/AnnouncementIniRepository.php152
3 files changed, 448 insertions, 0 deletions
diff --git a/library/Icinga/Web/Announcement.php b/library/Icinga/Web/Announcement.php
new file mode 100644
index 0000000..9835ce0
--- /dev/null
+++ b/library/Icinga/Web/Announcement.php
@@ -0,0 +1,158 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Web;
+
+/**
+ * An announcement to be displayed prominently in the web UI
+ */
+class Announcement
+{
+ /**
+ * @var string
+ */
+ protected $author;
+
+ /**
+ * @var string
+ */
+ protected $message;
+
+ /**
+ * @var int
+ */
+ protected $start;
+
+ /**
+ * @var int
+ */
+ protected $end;
+
+ /**
+ * Hash of the message
+ *
+ * @var string|null
+ */
+ protected $hash = null;
+
+ /**
+ * Announcement constructor
+ *
+ * @param array $properties
+ */
+ public function __construct(array $properties = array())
+ {
+ foreach ($properties as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ }
+ }
+ }
+
+ /**
+ * Get the author of the acknowledged
+ *
+ * @return string
+ */
+ public function getAuthor()
+ {
+ return $this->author;
+ }
+
+ /**
+ * Set the author of the acknowledged
+ *
+ * @param string $author
+ *
+ * @return $this
+ */
+ public function setAuthor($author)
+ {
+ $this->author = $author;
+ return $this;
+ }
+
+ /**
+ * Get the message of the acknowledged
+ *
+ * @return string
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * Set the message of the acknowledged
+ *
+ * @param string $message
+ *
+ * @return $this
+ */
+ public function setMessage($message)
+ {
+ $this->message = $message;
+ $this->hash = null;
+ return $this;
+ }
+
+ /**
+ * Get the start date and time of the acknowledged
+ *
+ * @return int
+ */
+ public function getStart()
+ {
+ return $this->start;
+ }
+
+ /**
+ * Set the start date and time of the acknowledged
+ *
+ * @param int $start
+ *
+ * @return $this
+ */
+ public function setStart($start)
+ {
+ $this->start = $start;
+ return $this;
+ }
+
+ /**
+ * Get the end date and time of the acknowledged
+ *
+ * @return int
+ */
+ public function getEnd()
+ {
+ return $this->end;
+ }
+
+ /**
+ * Set the end date and time of the acknowledged
+ *
+ * @param int $end
+ *
+ * @return $this
+ */
+ public function setEnd($end)
+ {
+ $this->end = $end;
+ return $this;
+ }
+
+ /**
+ * Get the hash of the acknowledgement
+ *
+ * @return string
+ */
+ public function getHash()
+ {
+ if ($this->hash === null) {
+ $this->hash = md5($this->message);
+ }
+ return $this->hash;
+ }
+}
diff --git a/library/Icinga/Web/Announcement/AnnouncementCookie.php b/library/Icinga/Web/Announcement/AnnouncementCookie.php
new file mode 100644
index 0000000..f4398ba
--- /dev/null
+++ b/library/Icinga/Web/Announcement/AnnouncementCookie.php
@@ -0,0 +1,138 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Web\Announcement;
+
+use Icinga\Util\Json;
+use Icinga\Web\Cookie;
+
+/**
+ * Handle acknowledged announcements via cookie
+ */
+class AnnouncementCookie extends Cookie
+{
+ /**
+ * Array of hashes representing acknowledged announcements
+ *
+ * @var string[]
+ */
+ protected $acknowledged = array();
+
+ /**
+ * ETag of the last known announcements.ini
+ *
+ * @var string
+ */
+ protected $etag;
+
+ /**
+ * Timestamp of the next active acknowledgement, if any
+ *
+ * @var int|null
+ */
+ protected $nextActive;
+
+ /**
+ * AnnouncementCookie constructor
+ */
+ public function __construct()
+ {
+ parent::__construct('icingaweb2-announcements');
+ $this->setExpire(2147483648);
+ if (isset($_COOKIE['icingaweb2-announcements'])) {
+ $cookie = json_decode($_COOKIE['icingaweb2-announcements'], true);
+ if ($cookie !== null) {
+ if (isset($cookie['acknowledged'])) {
+ $this->setAcknowledged($cookie['acknowledged']);
+ }
+ if (isset($cookie['etag'])) {
+ $this->setEtag($cookie['etag']);
+ }
+ if (isset($cookie['next'])) {
+ $this->setNextActive($cookie['next']);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the hashes of the acknowledged announcements
+ *
+ * @return string[]
+ */
+ public function getAcknowledged()
+ {
+ return $this->acknowledged;
+ }
+
+ /**
+ * Set the hashes of the acknowledged announcements
+ *
+ * @param string[] $acknowledged
+ *
+ * @return $this
+ */
+ public function setAcknowledged(array $acknowledged)
+ {
+ $this->acknowledged = $acknowledged;
+ return $this;
+ }
+
+ /**
+ * Get the ETag
+ *
+ * @return string
+ */
+ public function getEtag()
+ {
+ return $this->etag;
+ }
+
+ /**
+ * Set the ETag
+ *
+ * @param string $etag
+ *
+ * @return $this
+ */
+ public function setEtag($etag)
+ {
+ $this->etag = $etag;
+ return $this;
+ }
+
+ /**
+ * Get the timestamp of the next active announcement
+ *
+ * @return int
+ */
+ public function getNextActive()
+ {
+ return $this->nextActive;
+ }
+
+ /**
+ * Set the timestamp of the next active announcement
+ *
+ * @param int $nextActive
+ *
+ * @return $this
+ */
+ public function setNextActive($nextActive)
+ {
+ $this->nextActive = $nextActive;
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue()
+ {
+ return Json::encode(array(
+ 'acknowledged' => $this->getAcknowledged(),
+ 'etag' => $this->getEtag(),
+ 'next' => $this->getNextActive()
+ ));
+ }
+}
diff --git a/library/Icinga/Web/Announcement/AnnouncementIniRepository.php b/library/Icinga/Web/Announcement/AnnouncementIniRepository.php
new file mode 100644
index 0000000..d972a1d
--- /dev/null
+++ b/library/Icinga/Web/Announcement/AnnouncementIniRepository.php
@@ -0,0 +1,152 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Web\Announcement;
+
+use DateTime;
+use Icinga\Data\ConfigObject;
+use Icinga\Data\Filter\Filter;
+use Icinga\Data\Filter\FilterAnd;
+use Icinga\Data\SimpleQuery;
+use Icinga\Repository\IniRepository;
+use Icinga\Web\Announcement;
+
+/**
+ * A collection of announcements stored in an INI file
+ */
+class AnnouncementIniRepository extends IniRepository
+{
+ protected $queryColumns = array('announcement' => array('id', 'author', 'message', 'hash', 'start', 'end'));
+
+ protected $triggers = array('announcement');
+
+ protected $configs = array('announcement' => array(
+ 'name' => 'announcements',
+ 'keyColumn' => 'id'
+ ));
+
+ protected $conversionRules = array('announcement' => array(
+ 'start' => 'timestamp',
+ 'end' => 'timestamp'
+ ));
+
+ /**
+ * Get a DateTime's timestamp
+ *
+ * @param DateTime $datetime
+ *
+ * @return int|null
+ */
+ protected function persistTimestamp(DateTime $datetime)
+ {
+ return $datetime === null ? null : $datetime->getTimestamp();
+ }
+
+ /**
+ * Before-insert trigger (per row)
+ *
+ * @param ConfigObject $new The original data to insert
+ *
+ * @return ConfigObject The eventually modified data to insert
+ */
+ protected function onInsertAnnouncement(ConfigObject $new)
+ {
+ if (! isset($new->id)) {
+ $new->id = uniqid();
+ }
+
+ if (! isset($new->hash)) {
+ $announcement = new Announcement($new->toArray());
+ $new->hash = $announcement->getHash();
+ }
+
+ return $new;
+ }
+
+ /**
+ * Before-update trigger (per row)
+ *
+ * @param ConfigObject $old The original data as currently stored
+ * @param ConfigObject $new The original data to update
+ *
+ * @return ConfigObject The eventually modified data to update
+ */
+ protected function onUpdateAnnouncement(ConfigObject $old, ConfigObject $new)
+ {
+ if ($new->message !== $old->message) {
+ $announcement = new Announcement($new->toArray());
+ $new->hash = $announcement->getHash();
+ }
+
+ return $new;
+ }
+
+ /**
+ * Get the ETag of the announcements.ini file
+ *
+ * @return string
+ */
+ public function getEtag()
+ {
+ $file = $this->getDataSource('announcement')->getConfigFile();
+
+ if (@is_readable($file)) {
+ $mtime = filemtime($file);
+ $size = filesize($file);
+
+ return hash('crc32', $mtime . $size);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the query for all active announcements
+ *
+ * @return SimpleQuery
+ */
+ public function findActive()
+ {
+ $now = new DateTime();
+
+ $query = $this
+ ->select(array('hash', 'message', 'start'))
+ ->setFilter(new FilterAnd(array(
+ Filter::expression('start', '<=', $now),
+ Filter::expression('end', '>=', $now)
+ )))
+ ->order('start');
+
+ return $query;
+ }
+
+ /**
+ * Get the timestamp of the next active announcement
+ *
+ * @return int|null
+ */
+ public function findNextActive()
+ {
+ $now = new DateTime();
+
+ $query = $this
+ ->select(array('start', 'end'))
+ ->setFilter(Filter::matchAny(array(
+ Filter::expression('start', '>', $now), Filter::expression('end', '>', $now)
+ )));
+
+ $refresh = null;
+
+ foreach ($query as $row) {
+ $min = min($row->start, $row->end);
+
+ if ($refresh === null) {
+ $refresh = $min;
+ } else {
+ $refresh = min($refresh, $min);
+ }
+ }
+
+ return $refresh;
+ }
+}