summaryrefslogtreecommitdiffstats
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/controllers/IntegrationsController.php118
-rw-r--r--application/forms/Config/TtsIntegrationConfigForm.php249
-rw-r--r--application/views/scripts/integrations/index.phtml56
-rw-r--r--application/views/scripts/integrations/new.phtml6
-rw-r--r--application/views/scripts/integrations/remove.phtml6
-rw-r--r--application/views/scripts/integrations/update.phtml6
6 files changed, 441 insertions, 0 deletions
diff --git a/application/controllers/IntegrationsController.php b/application/controllers/IntegrationsController.php
new file mode 100644
index 0000000..340e15d
--- /dev/null
+++ b/application/controllers/IntegrationsController.php
@@ -0,0 +1,118 @@
+<?php
+
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Generictts\Controllers;
+
+use Icinga\Exception\NotFoundError;
+use Icinga\Forms\ConfirmRemovalForm;
+use Icinga\Module\Generictts\Forms\Config\TtsIntegrationConfigForm;
+use Icinga\Web\Controller;
+use Icinga\Web\Notification;
+
+/**
+ * Manage trouble ticket system integrations
+ */
+class IntegrationsController extends Controller
+{
+ /**
+ * List trouble ticket system integrations
+ */
+ public function indexAction()
+ {
+ $this->getTabs()->add('integrations', array(
+ 'active' => true,
+ 'label' => $this->translate('Integrations'),
+ 'url' => $this->getRequest()->getUrl()
+ ));
+ $this->view->integrations = $this->Config();
+ }
+
+ /**
+ * Integrate a new trouble ticket system
+ */
+ public function newAction()
+ {
+ $this->getTabs()->add('new-integration', array(
+ 'active' => true,
+ 'label' => $this->translate('New Integration'),
+ 'url' => $this->getRequest()->getUrl()
+ ));
+
+ $integrations = new TtsIntegrationConfigForm();
+ $integrations
+ ->setIniConfig($this->Config())
+ ->setRedirectUrl('generictts/integrations')
+ ->handleRequest();
+
+ $this->view->form = $integrations;
+ }
+
+ /**
+ * Remove a trouble ticket system integration
+ */
+ public function removeAction()
+ {
+ $integration = $this->params->getRequired('integration');
+
+ $this->getTabs()->add('remove-integration', array(
+ 'active' => true,
+ 'label' => $this->translate('Remove Integration'),
+ 'url' => $this->getRequest()->getUrl()
+ ));
+
+ $integrations = new TtsIntegrationConfigForm();
+ try {
+ $integrations
+ ->setIniConfig($this->Config())
+ ->bind($integration);
+ } catch (NotFoundError $e) {
+ $this->httpNotFound($e->getMessage());
+ }
+
+ $confirmation = new ConfirmRemovalForm(array(
+ 'onSuccess' => function (ConfirmRemovalForm $confirmation) use ($integration, $integrations) {
+ $integrations->remove($integration);
+ if ($integrations->save()) {
+ Notification::success(mt('generictts', 'TTS integration removed'));
+ return true;
+ }
+ return false;
+ }
+ ));
+ $confirmation
+ ->setRedirectUrl('generictts/integrations')
+ ->setSubmitLabel($this->translate('Remove Integration'))
+ ->handleRequest();
+
+ $this->view->form = $confirmation;
+ }
+
+ /**
+ * Update a trouble ticket system integration
+ */
+ public function updateAction()
+ {
+ $integration = $this->params->getRequired('integration');
+
+ $this->getTabs()->add('update-integration', array(
+ 'active' => true,
+ 'label' => $this->translate('Update Integration'),
+ 'url' => $this->getRequest()->getUrl()
+ ));
+
+ $integrations = new TtsIntegrationConfigForm();
+ try {
+ $integrations
+ ->setIniConfig($this->Config())
+ ->bind($integration);
+ } catch (NotFoundError $e) {
+ $this->httpNotFound($e->getMessage());
+ }
+ $integrations
+ ->setRedirectUrl('generictts/integrations')
+ ->handleRequest();
+
+ $this->view->form = $integrations;
+ }
+}
diff --git a/application/forms/Config/TtsIntegrationConfigForm.php b/application/forms/Config/TtsIntegrationConfigForm.php
new file mode 100644
index 0000000..2bdb562
--- /dev/null
+++ b/application/forms/Config/TtsIntegrationConfigForm.php
@@ -0,0 +1,249 @@
+<?php
+
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Generictts\Forms\Config;
+
+use Zend_Validate_Callback;
+use Icinga\Exception\AlreadyExistsException;
+use Icinga\Exception\IcingaException;
+use Icinga\Exception\NotFoundError;
+use Icinga\Forms\ConfigForm;
+use Icinga\Web\Form\Validator\UrlValidator;
+use Icinga\Web\Notification;
+
+/**
+ * Form for managing trouble ticket system integrations
+ */
+class TtsIntegrationConfigForm extends ConfigForm
+{
+ /**
+ * Name of the integration if the form is bound to one
+ *
+ * @var string
+ */
+ protected $boundIntegration;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setName('form_config_generictts_tts_integrations');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'text',
+ 'name',
+ array(
+ 'description' => $this->translate('The name of the TTS integration'),
+ 'label' => $this->translate('Name'),
+ 'required' => true
+ )
+ );
+
+ $patternValidator = new Zend_Validate_Callback(function ($value) {
+ return @preg_match($value, '') !== false;
+ });
+ $patternValidator->setMessage(
+ $this->translate('"%value%" is not a valid regular expression.'),
+ Zend_Validate_Callback::INVALID_VALUE
+ );
+ $this->addElement(
+ 'text',
+ 'pattern',
+ array(
+ 'value' => '/this-will-not-match(\d{3-6})/',
+ 'label' => $this->translate('Ticket Pattern'),
+ 'description' => $this->translate(
+ 'The pattern to extract ticket IDs from comments.'
+ . ' The ticket pattern must be a valid regular expression'
+ ),
+ 'required' => true,
+ 'validators' => array($patternValidator)
+ )
+ );
+
+ $urlValidator = new Zend_Validate_Callback(function ($value) {
+ return strpos($value, '$1') !== false;
+ });
+ $urlValidator->setMessage(
+ $this->translate('The URL must contain the placeholder $1 to be substituted with a ticket ID.'),
+ Zend_Validate_Callback::INVALID_VALUE
+ );
+ $this->addElement(
+ 'text',
+ 'url',
+ array(
+ 'value' => 'http://no-such-domain.example.com/ticket?id=$1',
+ 'label' => $this->translate('TTS Ticket URL'),
+ 'description' => $this->translate(
+ 'The URL pointing to the TTS with $1 as the placeholder for the ticket ID'
+ ),
+ 'required' => true,
+ 'validators' => array($urlValidator, new UrlValidator())
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSubmitLabel()
+ {
+ if (($submitLabel = parent::getSubmitLabel()) === null) {
+ if ($this->boundIntegration === null) {
+ $submitLabel = $this->translate('Integrate');
+ } else {
+ $submitLabel = $this->translate('Update Integration');
+ }
+ }
+ return $submitLabel;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onRequest()
+ {
+ // The base class implementation does not make sense here. We're not populating the whole configuration but
+ // only a section
+ return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ $name = $this->getElement('name')->getValue();
+ $values = array(
+ 'pattern' => $this->getElement('pattern')->getValue(),
+ 'url' => $this->getElement('url')->getValue()
+ );
+ if ($this->boundIntegration === null) {
+ $successNotification = $this->translate('TTS integrated');
+ try {
+ $this->add($name, $values);
+ } catch (AlreadyExistsException $e) {
+ $this->addError($e->getMessage());
+ return false;
+ }
+ } else {
+ $successNotification = $this->translate('TTS integration updated');
+ try {
+ $this->update($name, $values, $this->boundIntegration);
+ } catch (IcingaException $e) {
+ // Exception may be AlreadyExistsException or NotFoundError
+ $this->addError($e->getMessage());
+ return false;
+ }
+ }
+ if ($this->save()) {
+ Notification::success($successNotification);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Add a TTS integration
+ *
+ * @param string $name The name of the integration
+ * @param array $values
+ *
+ * @return $this
+ *
+ * @throws AlreadyExistsException If the integration to add already exists
+ */
+ public function add($name, array $values)
+ {
+ if ($this->config->hasSection($name)) {
+ throw new AlreadyExistsException(
+ $this->translate('Can\'t add integration \'%s\'. Integration already exists'),
+ $name
+ );
+ }
+ $this->config->setSection($name, $values);
+ return $this;
+ }
+
+ /**
+ * Bind integration to this form
+ *
+ * @param string $name The name of the integration
+ *
+ * @return $this
+ *
+ * @throws NotFoundError If the given integration does not exist
+ */
+ public function bind($name)
+ {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError(
+ $this->translate('Can\'t load integration \'%s\'. Integration does not exist'),
+ $name
+ );
+ }
+ $this->boundIntegration = $name;
+ $integration = $this->config->getSection($name)->toArray();
+ $integration['name'] = $name;
+ $this->populate($integration);
+ return $this;
+ }
+
+ /**
+ * Remove a TTS integration
+ *
+ * @param string $name The name of the integration
+ *
+ * @return $this
+ *
+ * @throws NotFoundError If the role does not exist
+ */
+ public function remove($name)
+ {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError(
+ $this->translate('Can\'t remove integration \'%s\'. Integration does not exist'),
+ $name
+ );
+ }
+ $this->config->removeSection($name);
+ return $this;
+ }
+
+ /**
+ * Update a TTS integration
+ *
+ * @param string $name The possibly new name of the integration
+ * @param array $values
+ * @param string $oldName The name of the integration to update
+ *
+ * @return $this
+ *
+ * @throws NotFoundError If the integration to update does not exist
+ */
+ public function update($name, array $values, $oldName)
+ {
+ if ($name !== $oldName) {
+ // The integration got a new name
+ $this->remove($oldName);
+ $this->add($name, $values);
+ } else {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError(
+ $this->translate('Can\'t update integration \'%s\'. Integration does not exist'),
+ $name
+ );
+ }
+ $this->config->setSection($name, $values);
+ }
+ return $this;
+ }
+}
diff --git a/application/views/scripts/integrations/index.phtml b/application/views/scripts/integrations/index.phtml
new file mode 100644
index 0000000..0f657ce
--- /dev/null
+++ b/application/views/scripts/integrations/index.phtml
@@ -0,0 +1,56 @@
+<div class="controls">
+ <?= $tabs ?>
+ <?= $this->qlink(
+ $this->translate('Integrate New Ticket System') ,
+ 'generictts/integrations/new',
+ null,
+ array(
+ 'class' => 'action-link',
+ 'data-base-target' => '_next',
+ 'icon' => 'plus',
+ 'title' => $this->translate('Integrate a new trouble ticket system')
+ )
+ ) ?>
+</div>
+<div class="content">
+<?php /** @var \Icinga\Application\Config $integrations */ if ($integrations->isEmpty()): ?>
+ <p><?= $this->translate('No ticket system has been integrated yet.') ?></p>
+<?php return; endif ?>
+ <table class="tts-integrations-table common-table table-row-selectable" data-base-target="_next">
+ <thead>
+ <tr>
+ <th><?= $this->translate('Name') ?></th>
+ <th><?= $this->translate('Pattern') ?></th>
+ <th><?= $this->translate('URL') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($integrations as $name => $integration): /** @var object $role */ ?>
+ <tr>
+ <td>
+ <?= $this->qlink(
+ $name,
+ 'generictts/integrations/update',
+ array('integration' => $name),
+ array('title' => sprintf($this->translate('Update integration %s'), $name))
+ ) ?>
+ </td>
+ <td><?= $this->escape($integration->pattern) ?></td>
+ <td><?= $this->escape($integration->url) ?></td>
+ <td class="icon-col text-right">
+ <?= $this->qlink(
+ '',
+ 'generictts/integrations/remove',
+ array('integration' => $name),
+ array(
+ 'class' => 'action-link',
+ 'icon' => 'cancel',
+ 'title' => sprintf($this->translate('Remove integration %s'), $name)
+ )
+ ) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </tbody>
+ </table>
+</div>
diff --git a/application/views/scripts/integrations/new.phtml b/application/views/scripts/integrations/new.phtml
new file mode 100644
index 0000000..13a8ed9
--- /dev/null
+++ b/application/views/scripts/integrations/new.phtml
@@ -0,0 +1,6 @@
+<div class="controls">
+ <?= $tabs ?>
+</div>
+<div class="content">
+ <?= $form ?>
+</div>
diff --git a/application/views/scripts/integrations/remove.phtml b/application/views/scripts/integrations/remove.phtml
new file mode 100644
index 0000000..13a8ed9
--- /dev/null
+++ b/application/views/scripts/integrations/remove.phtml
@@ -0,0 +1,6 @@
+<div class="controls">
+ <?= $tabs ?>
+</div>
+<div class="content">
+ <?= $form ?>
+</div>
diff --git a/application/views/scripts/integrations/update.phtml b/application/views/scripts/integrations/update.phtml
new file mode 100644
index 0000000..13a8ed9
--- /dev/null
+++ b/application/views/scripts/integrations/update.phtml
@@ -0,0 +1,6 @@
+<div class="controls">
+ <?= $tabs ?>
+</div>
+<div class="content">
+ <?= $form ?>
+</div>