Merge branch 'bugfix/error-prone-generictts-9611'

fixes #9611
This commit is contained in:
Eric Lippmann 2015-08-03 15:07:25 +02:00
commit 096a8cdd69
6 changed files with 208 additions and 154 deletions

View File

@ -0,0 +1,23 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
/**
* Helper for creating ticket links from ticket hooks
*/
class Zend_View_Helper_CreateTicketLinks extends Zend_View_Helper_Abstract
{
/**
* Create ticket links form ticket hooks
*
* @param string $text
*
* @return string
* @see \Icinga\Web\Hook\TicketHook::createLinks()
*/
public function createTicketLinks($text)
{
$tickets = $this->view->tickets;
/** @var \Icinga\Web\Hook\TicketHook $tickets */
return isset($tickets) ? $tickets->createLinks($text) : $text;
}
}

View File

@ -3,23 +3,29 @@
namespace Icinga\Web\Hook;
use ErrorException;
use Exception;
use Icinga\Application\Logger;
use Icinga\Exception\IcingaException;
/**
* Icinga Web Ticket Hook base class
* Base class for ticket hooks
*
* Extend this class if you want to integrate your ticketing solution nicely into
* Icinga Web
*
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
* @author Icinga-Web Team <info@icinga.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
* Extend this class if you want to integrate your ticketing solution Icinga Web 2
*/
abstract class TicketHook
{
/**
* Constructor must live without arguments right now
* Last error, if any
*
* Therefore the constructor is final, we might change our opinion about
* this one far day
* @var string|null
*/
protected $lastError;
/**
* Create a new ticket hook
*
* @see init() For hook initialization.
*/
final public function __construct()
{
@ -27,16 +33,92 @@ abstract class TicketHook
}
/**
* Overwrite this function if you want to do some initialization stuff
*
* @return void
* Overwrite this function for hook initialization, e.g. loading the hook's config
*/
protected function init()
{
}
/**
* Set the hook as failed w/ the given message
*
* @param string $message Error message or error format string
* @param mixed ...$arg Format string argument
*/
private function fail($message)
{
$args = array_slice(func_get_args(), 1);
$lastError = vsprintf($message, $args);
Logger::debug($lastError);
$this->lastError = $lastError;
}
/**
* Get the last error, if any
*
* @return string|null
*/
public function getLastError()
{
return $this->lastError;
}
/**
* Get the pattern
*
* @return string
*/
abstract public function getPattern();
/**
* Create a link for each matched element in the subject text
*
* @param array $match Array of matched elements according to {@link getPattern()}
*
* @return string Replacement string
*/
abstract public function createLink($match);
/**
* Create links w/ {@link createLink()} in the given text that matches to the subject from {@link getPattern()}
*
* In case of errors a debug message is recorded to the log and any subsequent call to {@link createLinks()} will
* be a no-op.
*
* @param string $text
*
* @return string
*/
final public function createLinks($text)
{
if ($this->lastError !== null) {
return $text;
}
try {
$pattern = $this->getPattern();
} catch (Exception $e) {
$this->fail('Can\'t create ticket links: Retrieving the pattern failed: %s', IcingaException::describe($e));
return $text;
}
if (empty($pattern)) {
$this->fail('Can\'t create ticket links: Pattern is empty');
return $text;
}
try {
$text = preg_replace_callback(
$pattern,
array($this, 'createLink'),
$text
);
} catch (ErrorException $e) {
$this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e));
return $text;
} catch (Exception $e) {
$this->fail('Can\'t create ticket links: %s', IcingaException::describe($e));
return $text;
}
return $text;
}
}

View File

@ -116,15 +116,7 @@ function contactsLink($match, $view) {
<br>
<?= date('d.m. H:i', $event->timestamp); ?>
</td>
<td><?php
$output = $this->tickets ? preg_replace_callback(
$this->tickets->getPattern(),
array($this->tickets, 'createLink'),
$msg
) : $msg;
?>
<td>
<?php if ($isService): ?>
<?= sprintf(
$this->translate('%s on %s', 'Service running on host'),
@ -148,7 +140,7 @@ $output = $this->tickets ? preg_replace_callback(
<?php endif ?>
<br>
<div>
<?= $this->icon($icon, $title); ?> <?= empty($msg) ? '' : $msg; ?>
<?= $this->icon($icon, $title); ?> <?= $this->createTicketLinks($msg) ?>
</div>
</td>
</tr>

View File

@ -114,15 +114,7 @@ function contactsLink($match, $view) {
<br>
<?= date('d.m. H:i', $event->timestamp); ?>
</td>
<td><?php
$output = $this->tickets ? preg_replace_callback(
$this->tickets->getPattern(),
array($this->tickets, 'createLink'),
$msg
) : $msg;
?>
<td>
<?= sprintf(
$this->translate('%s on %s', 'Service running on host'),
$this->escape($event->service_display_name),
@ -130,11 +122,11 @@ $output = $this->tickets ? preg_replace_callback(
) ?>
<br>
<div>
<?= $this->icon($icon, $title); ?> <?= empty($msg) ? '' : $msg; ?>
<?= $this->icon($icon, $title); ?> <?= $this->createTicketLinks($msg) ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>

View File

@ -1,7 +1,5 @@
<?php
$addLink = '';
$addLink = false;
if ($this->hasPermission('monitoring/command/comment/add')) {
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
if ($object->getType() === $object::TYPE_HOST) {
@ -28,63 +26,49 @@ if ($this->hasPermission('monitoring/command/comment/add')) {
);
}
}
if (empty($object->comments) && ! $addLink) {
return;
}
?>
<tr>
<th><?php
echo $this->translate('Comments');
if (! empty($object->comments) && $addLink) {
echo '<br />' . $addLink;
}
?></th>
<td data-base-target="_self">
<?php if (empty($object->comments)): ?>
<?= $addLink ?>
<?php else: ?>
<ul class="inline-comments">
<?php foreach ($object->comments as $comment): ?>
<?php
// Ticket hook sample
$commentText = $this->tickets ? preg_replace_callback(
$this->tickets->getPattern(),
array($this->tickets, 'createLink'),
$this->escape($comment->comment)
) : $this->escape($comment->comment);
// Form is unset if the current user lacks the respective permission
if (isset($delCommentForm)) {
$deleteButton = clone($delCommentForm);
$deleteButton->populate(
array(
'comment_id' => $comment->id,
'comment_is_service' => isset($comment->service_description)
)
);
} else {
$deleteButton = '';
}
?>
<li class="comment-item">
<h3>
<span class="author"><?= $this->escape($comment->author) ?></span>
<?= $this->timeAgo($comment->timestamp) ?>
<?= $deleteButton ?>
</h3>
<p><span class="sr-only">(<?= $this->translate('Comment'); ?>): </span><?= str_replace(array('\r\n', '\n'), '<br>', $commentText) ?></p>
</li>
<?php endforeach ?>
</ul>
<?php endif ?>
<?php if (empty($object->comments)):
echo $addLink;
else: ?>
<ul class="inline-comments">
<?php foreach ($object->comments as $comment):
// Form is unset if the current user lacks the respective permission
if (isset($delCommentForm)) {
$deleteButton = clone($delCommentForm);
$deleteButton->populate(
array(
'comment_id' => $comment->id,
'comment_is_service' => isset($comment->service_description)
)
);
} else {
$deleteButton = '';
}
?>
<li class="comment-item">
<h3>
<span class="author"><?= $this->escape($comment->author) ?></span>
<?= $this->timeAgo($comment->timestamp) ?>
<?= $deleteButton ?>
</h3>
<p>
<span class="sr-only">(<?= $this->translate('Comment') ?>): </span>
<?= str_replace(array('\r\n', '\n'), '<br>', $this->createTicketLinks($comment->comment)) ?>
</p>
</li>
<?php endforeach ?>
</ul>
<?php endif ?>
</td>
</tr>

View File

@ -1,7 +1,5 @@
<?php
$addLink = '';
$addLink = false;
if ($this->hasPermission('monitoring/command/downtime/schedule')) {
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
if ($object->getType() === $object::TYPE_HOST) {
@ -32,85 +30,68 @@ if ($this->hasPermission('monitoring/command/downtime/schedule')) {
);
}
}
if (empty($object->comments) && ! $addLink) {
return;
}
?>
<tr>
<th><?php
echo $this->translate('Downtimes');
if (! empty($object->downtimes) && $addLink) {
echo '<br />' . $addLink;
}
?></th>
<td data-base-target="_self">
<?php if (empty($object->downtimes)): ?>
<?= $addLink ?>
<?php else: ?>
<ul class="inline-comments">
<?php foreach ($object->downtimes as $downtime): ?>
<?php
// Ticket hook sample
$commentText = $this->tickets ? preg_replace_callback(
$this->tickets->getPattern(),
array($this->tickets, 'createLink'),
$this->escape($downtime->comment)
) : $this->escape($downtime->comment);
if ((bool) $downtime->is_in_effect) {
$state = sprintf(
$this->translate('expires %s', 'Last format parameter represents the downtime expire time'),
$this->timeUntil($downtime->end)
);
} else {
if ((bool) $downtime->is_fixed) {
$state = sprintf(
$this->translate('scheduled %s', 'Last format parameter represents the time scheduled'),
$this->timeUntil($downtime->start)
);
} else {
$state = sprintf(
$this->translate('scheduled flexible %s', 'Last format parameter represents the time scheduled'),
$this->timeUntil($downtime->start)
);
}
}
// Form is unset if the current user lacks the respective permission
if (isset($delDowntimeForm)) {
$deleteButton = clone($delDowntimeForm);
$deleteButton->populate(
array(
'downtime_id' => $downtime->id,
'downtime_is_service' => $object->getType() === $object::TYPE_SERVICE
)
);
} else {
$deleteButton = '';
}
?>
<li class="comment-item">
<h3>
<span class="author"><?= $this->escape($downtime->author_name) ?></span>
<?= $this->timeAgo($downtime->entry_time) ?>
<?= $deleteButton ?>
</h3>
<p> <span class="sr-only"><?= $this->translate('Downtime'); ?></span><?= $state; ?> - <?= str_replace(array('\r\n', '\n'), '<br>', $commentText); ?></p>
</li>
<?php endforeach ?>
</ul>
<?php endif ?>
<?php if (empty($object->downtimes)):
echo $addLink;
else: ?>
<ul class="inline-comments">
<?php foreach ($object->downtimes as $downtime):
if ((bool) $downtime->is_in_effect) {
$state = sprintf(
$this->translate('expires %s', 'Last format parameter represents the downtime expire time'),
$this->timeUntil($downtime->end)
);
} else {
if ((bool) $downtime->is_fixed) {
$state = sprintf(
$this->translate('scheduled %s', 'Last format parameter represents the time scheduled'),
$this->timeUntil($downtime->start)
);
} else {
$state = sprintf(
$this->translate('scheduled flexible %s', 'Last format parameter represents the time scheduled'),
$this->timeUntil($downtime->start)
);
}
}
// Form is unset if the current user lacks the respective permission
if (isset($delDowntimeForm)) {
$deleteButton = clone($delDowntimeForm);
$deleteButton->populate(
array(
'downtime_id' => $downtime->id,
'downtime_is_service' => $object->getType() === $object::TYPE_SERVICE
)
);
} else {
$deleteButton = '';
}
?>
<li class="comment-item">
<h3>
<span class="author"><?= $this->escape($downtime->author_name) ?></span>
<?= $this->timeAgo($downtime->entry_time) ?>
<?= $deleteButton ?>
</h3>
<p>
<span class="sr-only"><?= $this->translate('Downtime') ?></span>
<?= $state ?> -
<?= str_replace(array('\r\n', '\n'), '<br>', $this->createTicketLinks($downtime->comment)) ?>
</p>
</li>
<?php endforeach ?>
</ul>
<?php endif ?>
</td>
</tr>