From b4faa0142bbdbf8090e8dd6b877086e4106cf9f9 Mon Sep 17 00:00:00 2001
From: Eric Lippmann <eric.lippmann@netways.de>
Date: Thu, 11 Sep 2014 17:20:20 +0200
Subject: [PATCH] monitoring/commands: Add object command forms

refs #6593
---
 .../Object/AcknowledgeProblemCommandForm.php  | 166 ++++++++++++++
 .../Command/Object/AddCommentCommandForm.php  |  91 ++++++++
 .../Command/Object/CheckNowCommandForm.php    |  51 +++++
 .../Object/DeleteCommentCommandForm.php       |  61 ++++++
 .../Object/DeleteDowntimeCommandForm.php      |  61 ++++++
 .../Command/Object/ObjectsCommandForm.php     |  48 ++++
 .../RemoveAcknowledgementCommandForm.php      |  41 ++++
 .../ScheduleServiceCheckCommandForm.php       |  91 ++++++++
 .../ScheduleServiceDowntimeCommandForm.php    | 206 ++++++++++++++++++
 .../ToggleObjectFeaturesCommandForm.php       | 123 +++++++++++
 10 files changed, 939 insertions(+)
 create mode 100644 modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
 create mode 100644 modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php

diff --git a/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
new file mode 100644
index 000000000..8da595a0d
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
@@ -0,0 +1,166 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use DateTime;
+use DateInterval;
+use Icinga\Module\Monitoring\Command\Object\AcknowledgeProblemCommand;
+use Icinga\Web\Form\Element\DateTimePicker;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for acknowledging host or service problems
+ */
+class AcknowledgeProblemCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'Acknowledge Problem'));
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $this->addElements(array(
+            array(
+                'note',
+                'command-info',
+                array(
+                    'value' => mt(
+                        'monitoring',
+                        'This command is used to acknowledge host or service problems. When a problem is acknowledged,'
+                            . ' future notifications about problems are temporarily disabled until the host or service'
+                            . ' recovers.'
+                    )
+                )
+            ),
+            array(
+                'textarea',
+                'comment',
+                array(
+                    'required'      => true,
+                    'label'         => mt('monitoring', 'Comment'),
+                    'description'   => mt(
+                        'monitoring',
+                        'If you work with other administrators, you may find it useful to share information about the'
+                            . ' the host or service that is having problems. Make sure you enter a brief description of'
+                            . ' what you are doing.'
+                    )
+                )
+            ),
+            array(
+                'checkbox',
+                'persistent',
+                array(
+                    'label'         => mt('monitoring', 'Persistent Comment'),
+                    'description'   => mt(
+                        'monitoring',
+                        'If you would like the comment to remain even when the acknowledgement is removed, check this'
+                            . ' option.'
+                    )
+                )
+            ),
+            array(
+                'checkbox',
+                'expire',
+                array(
+                    'label'         => mt('monitoring', 'Use Expire Time'),
+                    'description'   => mt('monitoring', 'If the acknowledgement should expire, check this option.'),
+                    'autosubmit'    => true
+                )
+            )
+        ));
+        if (isset($formData['expire']) && (bool) $formData['expire'] === true) {
+            $expireTime = new DateTime();
+            $expireTime->add(new DateInterval('PT1H'));
+            $this->addElement(
+                new DateTimePicker(
+                    'expire_time',
+                    array(
+                        'label'         => mt('monitoring', 'Expire Time'),
+                        'value'         => $expireTime,
+                        'description'   => mt(
+                            'monitoring',
+                            'Enter the expire date and time for this acknowledgement here. Icinga will delete the'
+                                . ' acknowledgement after this time expired.'
+                        )
+                    )
+                )
+            );
+            $this->addDisplayGroup(
+                array('expire', 'expire_time'),
+                'expire-expire_time',
+                array(
+                    'decorators' => array(
+                        'FormElements',
+                        array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
+                    )
+                )
+            );
+        }
+        $this->addElements(array(
+            array(
+                'checkbox',
+                'sticky',
+                array(
+                    'label'         => mt('monitoring', 'Sticky Acknowledgement'),
+                    'value'         => true,
+                    'description'   => mt(
+                        'monitoring',
+                        'If you want the acknowledgement to disable notifications until the host or service recovers,'
+                            . 'check this option.'
+                    )
+                )
+            ),
+            array(
+                'checkbox',
+                'notify',
+                array(
+                    'label'         => mt('monitoring', 'Send Notification'),
+                    'value'         => true,
+                    'description'   => mt(
+                        'monitoring',
+                        'If you do not want an acknowledgement notification to be sent out to the appropriate contacts,'
+                            . 'uncheck this option.'
+                    )
+                )
+            )
+        ));
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            $ack = new AcknowledgeProblemCommand();
+            $ack
+                ->setObject($object)
+                ->setComment($this->getElement('comment')->getValue())
+                ->setAuthor($request->getUser()->getUsername())
+                ->setPersistent($this->getElement('persistent')->isChecked())
+                ->setSticky($this->getElement('sticky')->isChecked())
+                ->setNotify($this->getElement('notify')->isChecked());
+            if ($this->getElement('expire')->isChecked()) {
+                $ack->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
+            }
+            $this->getTransport($request)->send($ack);
+        }
+        Notification::success(mt('monitoring', 'Acknowledging problem..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php
new file mode 100644
index 000000000..777d96868
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php
@@ -0,0 +1,91 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\AddCommentCommand;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for adding host or service comments
+ */
+class AddCommentCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'Add Comment'));
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $this->addElements(array(
+            array(
+                'note',
+                'command-info',
+                array(
+                    'value' => mt(
+                        'monitoring',
+                        'This command is used to add host or service comments.'
+                    )
+                )
+            ),
+            array(
+                'textarea',
+                'comment',
+                array(
+                    'required'      => true,
+                    'label'         => mt('monitoring', 'Comment'),
+                    'description'   => mt(
+                        'monitoring',
+                        'If you work with other administrators, you may find it useful to share information about the'
+                            . ' the host or service that is having problems. Make sure you enter a brief description of'
+                            . ' what you are doing.'
+                    )
+                )
+            ),
+            array(
+                'checkbox',
+                'persistent',
+                array(
+                    'label'         => mt('monitoring', 'Persistent'),
+                    'value'         => true,
+                    'description'   => mt(
+                        'monitoring',
+                        'If you uncheck this option, the comment will automatically be deleted the next time Icinga is'
+                            . ' restarted.'
+                    )
+                )
+            )
+        ));
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            $comment = new AddCommentCommand();
+            $comment->setObject($object);
+            $comment->setComment($this->getElement('comment')->getValue());
+            $comment->setAuthor($request->getUser()->getUsername());
+            $comment->setPersistent((bool) $this->getElement('persistent')->getValue());
+            $this->getTransport($request)->send($comment);
+        }
+        Notification::success(mt('monitoring', 'Adding comment..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php
new file mode 100644
index 000000000..ecf933102
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php
@@ -0,0 +1,51 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
+use Icinga\Module\Monitoring\Form\Command\Object\ObjectsCommandForm;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for immediately checking hosts or services
+ */
+class CheckNowCommandForm extends ObjectsCommandForm
+{
+
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'Check Now'));
+        $this->setAttrib('class', 'inline link-like');
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            if ($object->getType() === $object::TYPE_HOST) {
+                $check = new ScheduleHostCheckCommand();
+            } else {
+                $check = new ScheduleServiceCheckCommand();
+            }
+            $check
+                ->setObject($object)
+                ->setForced()
+                ->setCheckTime(time());
+            $this->getTransport($request)->send($check);
+        }
+        Notification::success(mt('monitoring', 'Scheduling check..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php
new file mode 100644
index 000000000..c1a24ef50
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php
@@ -0,0 +1,61 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for deleting host or service comments
+ */
+class DeleteCommentCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'X'));
+        $this->setAttrib('class', 'inline link-like');
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $this->addElements(array(
+            array(
+                'hidden',
+                'comment_id',
+                array(
+                    'required' => true
+                )
+            )
+        ));
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            $delComment = new DeleteCommentCommand();
+            $delComment
+                ->setObject($object)
+                ->setCommentId($this->getElement('comment_id')->getValue());
+            $this->getTransport($request)->send($delComment);
+        }
+        Notification::success(mt('monitoring', 'Deleting comment..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php
new file mode 100644
index 000000000..4558b71da
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php
@@ -0,0 +1,61 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for deleting host or service downtimes
+ */
+class DeleteDowntimeCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'X'));
+        $this->setAttrib('class', 'inline link-like');
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $this->addElements(array(
+            array(
+                'hidden',
+                'downtime_id',
+                array(
+                    'required' => true
+                )
+            )
+        ));
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            $delDowntime = new DeleteDowntimeCommand();
+            $delDowntime
+                ->setObject($object)
+                ->setDowntimeId($this->getElement('downtime_id')->getValue());
+            $this->getTransport($request)->send($delDowntime);
+        }
+        Notification::success(mt('monitoring', 'Deleting downtime..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php b/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php
new file mode 100644
index 000000000..bf603a7b5
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php
@@ -0,0 +1,48 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Form\Command\CommandForm;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+
+/**
+ * Base class for Icinga object command forms
+ */
+abstract class ObjectsCommandForm extends CommandForm
+{
+    /**
+     * Involved Icinga objects
+     *
+     * @var array|\Traversable|\ArrayAccess
+     */
+    protected $objects;
+
+    /**
+     * Set the involved Icinga objects
+     *
+     * @param   $objects MonitoredObject|array|\Traversable|\ArrayAccess
+     *
+     * @return  $this
+     */
+    public function setObjects($objects)
+    {
+        if ($objects instanceof MonitoredObject) {
+            $this->objects = array($objects);
+        } else {
+            $this->objects = $objects;
+        }
+        return $this;
+    }
+
+    /**
+     * Get the involved Icinga objects
+     *
+     * @return array|\ArrayAccess|\Traversable
+     */
+    public function getObjects()
+    {
+        return $this->objects;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php b/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php
new file mode 100644
index 000000000..c76cca19c
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php
@@ -0,0 +1,41 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\RemoveAcknowledgementCommand;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for removing host or service problem acknowledgements
+ */
+class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'Remove Problem Acknowledgement'));
+        $this->setAttrib('class', 'inline link-like');
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            $removeAck = new RemoveAcknowledgementCommand();
+            $removeAck->setObject($object);
+            $this->getTransport($request)->send($removeAck);
+        }
+        Notification::success(mt('monitoring', 'Removing problem acknowledgement..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php
new file mode 100644
index 000000000..a93fcf4ae
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php
@@ -0,0 +1,91 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use DateTime;
+use DateInterval;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
+use Icinga\Web\Form\Element\DateTimePicker;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for scheduling service checks
+ */
+class ScheduleServiceCheckCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'Schedule Check'));
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $checkTime = new DateTime();
+        $checkTime->add(new DateInterval('PT1H'));
+        $this->addElements(array(
+            array(
+                'note',
+                'command-info',
+                array(
+                    'value' => mt(
+                        'monitoring',
+                        'This command is used to schedule the next check of hosts or services. Icinga will re-queue the'
+                            . ' hosts or services to be checked at the time you specify.'
+                    )
+                )
+            ),
+            new DateTimePicker(
+                'check_time',
+                array(
+                    'required'      => true,
+                    'label'         => mt('monitoring', 'Check Time'),
+                    'description'   => mt('monitoring', 'Set the date and time when the check should be scheduled.'),
+                    'value'         => $checkTime
+                )
+            ),
+            array(
+                'checkbox',
+                'force_check',
+                array(
+                    'label'         => mt('monitoring', 'Force Check'),
+                    'description'   => mt(
+                        'monitoring',
+                        'If you select this option, Icinga will force a check regardless of both what time the'
+                            . 'scheduled check occurs and whether or not checks are enabled.'
+                    )
+                )
+            )
+        ));
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\Service $object */
+            $check = new ScheduleServiceCheckCommand();
+            $check
+                ->setObject($object)
+                ->setForced((bool) $this->getElement('force_check')->getValue())
+                ->setCheckTime($this->getElement('check_time')->getValue());
+            $this->getTransport($request)->send($check);
+        }
+        Notification::success(mt('monitoring', 'Scheduling service check..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
new file mode 100644
index 000000000..76d36d214
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
@@ -0,0 +1,206 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use DateTime;
+use DateInterval;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
+use Icinga\Web\Form\Element\DateTimePicker;
+use Icinga\Web\Form\Element\Number;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for scheduling service downtimes
+ */
+class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
+{
+    /**
+     * Fixed downtime
+     */
+    const FIXED = 'fixed';
+
+    /**
+     * Flexible downtime
+     */
+    const FLEXIBLE = 'flexible';
+
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setSubmitLabel(mt('monitoring', 'Schedule Downtime'));
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $start = new DateTime;
+        $end = clone $start;
+        $end->add(new DateInterval('PT1H'));
+        $this->addElements(array(
+            array(
+                'note',
+                'command-info',
+                array(
+                    'value' => mt(
+                        'monitoring',
+                        'This command is used to schedule host and service downtimes. During the specified downtime,'
+                            . ' Icinga will not send notifications out about the hosts and services. When the scheduled'
+                            . ' downtime expires, Icinga will send out notifications for the hosts and services as it'
+                            . ' normally would. Scheduled downtimes are preserved across program shutdowns and'
+                            . ' restarts.'
+                    )
+                )
+            ),
+            array(
+                'textarea',
+                'comment',
+                array(
+                    'required'      => true,
+                    'label'         => mt('monitoring', 'Comment'),
+                    'description'   => mt(
+                        'monitoring',
+                        'If you work with other administrators, you may find it useful to share information about the'
+                            . ' the host or service that is having problems. Make sure you enter a brief description of'
+                            . ' what you are doing.'
+                    )
+                )
+            ),
+            new DateTimePicker(
+                'start',
+                array(
+                    'required'      => true,
+                    'label'         => mt('monitoring', 'Start Time'),
+                    'description'   => mt('monitoring', 'Set the start date and time for the downtime.'),
+                    'value'         => $start
+                )
+            ),
+            new DateTimePicker(
+                'end',
+                array(
+                    'required'      => true,
+                    'label'         => mt('monitoring', 'End Time'),
+                    'description'   => mt('monitoring', 'Set the end date and time for the downtime.'),
+                    'value'         => $end
+                )
+            ),
+            array(
+                'select',
+                'type',
+                array(
+                    'required'      => true,
+                    'autosubmit'    => true,
+                    'label'         => mt('monitoring', 'Type'),
+                    'description'   => mt(
+                        'monitoring',
+                        'If you select the fixed option, the downtime will be in effect between the start and end'
+                            . ' times you specify whereas a flexible downtime starts when the host or service enters a'
+                            . ' problem state sometime between the start and end times you specified and lasts as long'
+                            . ' as the duration time you enter. The duration fields do not apply for fixed downtimes.'
+                    ),
+                    'multiOptions' => array(
+                        self::FIXED     => mt('monitoring', 'Fixed'),
+                        self::FLEXIBLE  => mt('monitoring', 'Flexible')
+                    ),
+                    'validators' => array(
+                        array(
+                            'InArray',
+                            true,
+                            array(array(self::FIXED, self::FLEXIBLE))
+                        )
+                    )
+                )
+            )
+        ));
+        $this->addDisplayGroup(
+            array('start', 'end'),
+            'start-end',
+            array(
+                'decorators' => array(
+                    'FormElements',
+                    array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
+                )
+            )
+        );
+        if (isset($formData['type']) && $formData['type'] === self::FLEXIBLE) {
+            $this->addElements(array(
+                new Number(
+                    'hours',
+                    array(
+                        'required'  => true,
+                        'label'     => mt('monitoring', 'Hours'),
+                        'value'     => 2,
+                        'min'       => -1
+                    )
+                ),
+                new Number(
+                    'minutes',
+                    array(
+                        'required'  => true,
+                        'label'     => mt('monitoring', 'Minutes'),
+                        'value'     => 0,
+                        'min'       => -1
+                    )
+                )
+            ));
+            $this->addDisplayGroup(
+                array('hours', 'minutes'),
+                'duration',
+                array(
+                    'legend'        => mt('monitoring', 'Flexible Duration'),
+                    'description'   => mt(
+                        'monitoring',
+                        'Enter here the duration of the downtime. The downtime will be automatically deleted after this'
+                            . ' time expired.'
+                    ),
+                    'decorators' => array(
+                        'FormElements',
+                        array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')),
+                        array(
+                            'Description',
+                            array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
+                        ),
+                        'Fieldset'
+                    )
+                )
+            );
+        }
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\Service $object */
+            $downtime = new ScheduleServiceDowntimeCommand();
+            $downtime
+                ->setObject($object)
+                ->setComment($this->getElement('comment')->getValue())
+                ->setAuthor($request->getUser()->getUsername())
+                ->setStart($this->getElement('start')->getValue()->getTimestamp())
+                ->setEnd($this->getElement('end')->getValue()->getTimestamp());
+            if ($this->getElement('type')->getValue() === self::FLEXIBLE) {
+                $downtime->setFixed(false);
+                $downtime->setDuration(
+                    (float) $this->getElement('hours')->getValue() * 3600
+                    + (float) $this->getElement('minutes')->getValue() * 60
+                );
+            }
+            $this->getTransport($request)->send($downtime);
+        }
+        Notification::success(mt('monitoring', 'Scheduling service downtime..'));
+        return true;
+    }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php
new file mode 100644
index 000000000..146fd7001
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php
@@ -0,0 +1,123 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+namespace Icinga\Module\Monitoring\Form\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\ToggleObjectFeatureCommand;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for enabling or disabling features of Icinga objects, i.e. hosts or services
+ */
+class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
+{
+    /**
+     * (non-PHPDoc)
+     * @see \Zend_Form::init() For the method documentation.
+     */
+    public function init()
+    {
+        $this->setAttrib('class', 'inline');
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::createElements() For the method documentation.
+     */
+    public function createElements(array $formData = array())
+    {
+        $this->addElements(array(
+            array(
+                'checkbox',
+                ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS,
+                array(
+                    'label'         => mt('monitoring', 'Active Checks'),
+                    'autosubmit'    => true
+                )
+            ),
+            array(
+                'checkbox',
+                ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS,
+                array(
+                    'label'         => mt('monitoring', 'Passive Checks'),
+                    'autosubmit'    => true
+                )
+            ),
+            array(
+                'checkbox',
+                ToggleObjectFeatureCommand::FEATURE_OBSESSING,
+                array(
+                    'label'         => mt('monitoring', 'Obsessing'),
+                    'autosubmit'    => true
+                )
+            ),
+            array(
+                'checkbox',
+                ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS,
+                array(
+                    'label'         => mt('monitoring', 'Notifications'),
+                    'autosubmit'    => true
+                )
+            ),
+            array(
+                'checkbox',
+                ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER,
+                array(
+                    'label'         => mt('monitoring', 'Event Handler'),
+                    'autosubmit'    => true
+                )
+            ),
+            array(
+                'checkbox',
+                ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION,
+                array(
+                    'label'         => mt('monitoring', 'Flap Detection'),
+                    'autosubmit'    => true
+                )
+            )
+        ));
+        return $this;
+    }
+
+    /**
+     * Load feature status
+     *
+     * @param   MonitoredObject $object
+     *
+     * @return  $this
+     */
+    public function load(MonitoredObject $object)
+    {
+        $this->create();
+        foreach ($this->getValues() as $feature => $enabled) {
+            $this->getElement($feature)->setChecked($object->{$feature});
+        }
+        return $this;
+    }
+
+    /**
+     * (non-PHPDoc)
+     * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+     */
+    public function onSuccess(Request $request)
+    {
+        foreach ($this->objects as $object) {
+            /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+            foreach ($this->getValues() as $feature => $enabled) {
+                if ((bool) $object->{$feature} !== (bool) $enabled) {
+                    $toggleFeature = new ToggleObjectFeatureCommand();
+                    $toggleFeature
+                        ->setFeature($feature)
+                        ->setObject($object)
+                        ->setEnabled($enabled);
+                    $this->getTransport($request)->send($toggleFeature);
+                }
+            }
+        }
+        Notification::success(mt('monitoring', 'Toggling feature..'));
+        return true;
+    }
+}