commit
c0f39de200
|
@ -3,9 +3,11 @@
|
|||
|
||||
namespace Icinga\Controllers;
|
||||
|
||||
use Icinga\Web\Response\JsonResponse;
|
||||
use Zend_Controller_Plugin_ErrorHandler;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\Http\HttpBadRequestException;
|
||||
use Icinga\Exception\Http\HttpMethodNotAllowedException;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Exception\MissingParameterException;
|
||||
|
@ -17,6 +19,9 @@ use Icinga\Web\Controller\ActionController;
|
|||
*/
|
||||
class ErrorController extends ActionController
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requiresAuthentication = false;
|
||||
|
||||
/**
|
||||
|
@ -26,7 +31,7 @@ class ErrorController extends ActionController
|
|||
{
|
||||
$error = $this->_getParam('error_handler');
|
||||
$exception = $error->exception;
|
||||
|
||||
/** @var \Exception $exception */
|
||||
Logger::error($exception);
|
||||
Logger::error('Stacktrace: %s', $exception->getTraceAsString());
|
||||
|
||||
|
@ -64,6 +69,9 @@ class ErrorController extends ActionController
|
|||
'Missing parameter ' . $exception->getParameter()
|
||||
);
|
||||
break;
|
||||
case $exception instanceof HttpBadRequestException:
|
||||
$this->getResponse()->setHttpResponseCode(400);
|
||||
break;
|
||||
case $exception instanceof SecurityException:
|
||||
$this->getResponse()->setHttpResponseCode(403);
|
||||
break;
|
||||
|
@ -77,6 +85,13 @@ class ErrorController extends ActionController
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->getRequest()->isApiRequest()) {
|
||||
$this->getResponse()->json()
|
||||
->setErrorMessage($this->view->message)
|
||||
->sendResponse();
|
||||
}
|
||||
|
||||
$this->view->request = $error->request;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ class Web extends EmbeddedWeb
|
|||
->setupNotifications()
|
||||
->setupRequest()
|
||||
->setupResponse()
|
||||
->setupUserBackendFactory()
|
||||
->setupUser()
|
||||
->setupTimezone()
|
||||
->setupLogger()
|
||||
|
@ -91,7 +92,6 @@ class Web extends EmbeddedWeb
|
|||
->setupZendMvc()
|
||||
->setupNamespaces()
|
||||
->setupModuleManager()
|
||||
->setupUserBackendFactory()
|
||||
->loadSetupModuleIfNecessary()
|
||||
->loadEnabledModules()
|
||||
->setupRoute()
|
||||
|
|
|
@ -227,6 +227,8 @@ abstract class Filter
|
|||
* Create filter from queryString
|
||||
*
|
||||
* This is still pretty basic, need improvement
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function fromQueryString($query)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Exception\Http;
|
||||
|
||||
/**
|
||||
* Exception thrown for sending a HTTP 400 response w/ a custom message
|
||||
*/
|
||||
class HttpBadRequestException extends HttpException
|
||||
{
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ namespace Icinga\Web;
|
|||
use Icinga\Data\Filterable;
|
||||
use Icinga\Data\Sortable;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Exception\Http\HttpBadRequestException;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Web\Controller\ModuleActionController;
|
||||
use Icinga\Web\Widget\Limiter;
|
||||
|
@ -51,6 +52,19 @@ class Controller extends ModuleActionController
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately respond w/ HTTP 400
|
||||
*
|
||||
* @param string $message Exception message or exception format string
|
||||
* @param mixed ...$arg Format string argument
|
||||
*
|
||||
* @throws HttpBadRequestException
|
||||
*/
|
||||
public function httpBadRequest($message)
|
||||
{
|
||||
throw HttpBadRequestException::create(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately respond w/ HTTP 404
|
||||
*
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
namespace Icinga\Web\Controller;
|
||||
|
||||
use Zend_Controller_Action;
|
||||
use Zend_Controller_Action_HelperBroker;
|
||||
use Zend_Controller_Request_Abstract;
|
||||
use Zend_Controller_Response_Abstract;
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Authentication\Auth;
|
||||
|
@ -19,15 +23,21 @@ use Icinga\Web\Url;
|
|||
use Icinga\Web\UrlParams;
|
||||
use Icinga\Web\Widget\Tabs;
|
||||
use Icinga\Web\Window;
|
||||
use Zend_Controller_Action;
|
||||
use Zend_Controller_Action_HelperBroker as ActionHelperBroker;
|
||||
use Zend_Controller_Request_Abstract as Request;
|
||||
use Zend_Controller_Response_Abstract as Response;
|
||||
|
||||
/**
|
||||
* Base class for all core action controllers
|
||||
*
|
||||
* All Icinga Web core controllers should extend this class
|
||||
*
|
||||
* @method \Icinga\Web\Request getRequest() {
|
||||
* {@inheritdoc}
|
||||
* @return \Icinga\Web\Request
|
||||
* }
|
||||
*
|
||||
* @method \Icinga\Web\Response getResponse() {
|
||||
* {@inheritdoc}
|
||||
* @return \Icinga\Web\Response
|
||||
* }
|
||||
*/
|
||||
class ActionController extends Zend_Controller_Action
|
||||
{
|
||||
|
@ -80,13 +90,13 @@ class ActionController extends Zend_Controller_Action
|
|||
* The constructor starts benchmarking, loads the configuration and sets
|
||||
* other useful controller properties
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param array $invokeArgs Any additional invocation arguments
|
||||
* @param Zend_Controller_Request_Abstract $request
|
||||
* @param Zend_Controller_Response_Abstract $response
|
||||
* @param array $invokeArgs Any additional invocation arguments
|
||||
*/
|
||||
public function __construct(
|
||||
Request $request,
|
||||
Response $response,
|
||||
Zend_Controller_Request_Abstract $request,
|
||||
Zend_Controller_Response_Abstract $response,
|
||||
array $invokeArgs = array()
|
||||
) {
|
||||
$this->params = UrlParams::fromQueryString();
|
||||
|
@ -94,7 +104,7 @@ class ActionController extends Zend_Controller_Action
|
|||
$this->setRequest($request)
|
||||
->setResponse($response)
|
||||
->_setInvokeArgs($invokeArgs);
|
||||
$this->_helper = new ActionHelperBroker($this);
|
||||
$this->_helper = new Zend_Controller_Action_HelperBroker($this);
|
||||
|
||||
$this->handlerBrowserWindows();
|
||||
$moduleName = $this->getModuleName();
|
||||
|
|
|
@ -30,6 +30,11 @@ use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
|||
*
|
||||
* @return $this
|
||||
* }
|
||||
*
|
||||
* @method \Zend_Form_Element[] getElements() {
|
||||
* {@inheritdoc}
|
||||
* @return \Zend_Form_Element[]
|
||||
* }
|
||||
*/
|
||||
class Form extends Zend_Form
|
||||
{
|
||||
|
@ -60,6 +65,17 @@ class Form extends Zend_Form
|
|||
*/
|
||||
protected $created = false;
|
||||
|
||||
/**
|
||||
* Whether the form is an API target
|
||||
*
|
||||
* When the form is an API target, the form evaluates as submitted if the request method equals the form method.
|
||||
* That means, that the submit button and form identification are not taken into account. In addition, the CSRF
|
||||
* counter measure will not be added to the form's elements.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isApiTarget = false;
|
||||
|
||||
/**
|
||||
* The request associated with this form
|
||||
*
|
||||
|
@ -687,6 +703,29 @@ class Form extends Zend_Form
|
|||
return $this->useFormAutosubmit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the form is an API target
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsApiTarget()
|
||||
{
|
||||
return $this->isApiTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the form is an API target
|
||||
*
|
||||
* @param bool $isApiTarget
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIsApiTarget($isApiTarget = true)
|
||||
{
|
||||
$this->isApiTarget = (bool) $isApiTarget;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create this form
|
||||
*
|
||||
|
@ -997,7 +1036,7 @@ class Form extends Zend_Form
|
|||
if (! $this->tokenDisabled) {
|
||||
$request = $this->getRequest();
|
||||
if (! $request->isXmlHttpRequest()
|
||||
&& $request->getIsApiRequest()
|
||||
&& ($this->getIsApiTarget() || $request->isApiRequest())
|
||||
) {
|
||||
return $this;
|
||||
}
|
||||
|
@ -1064,21 +1103,40 @@ class Form extends Zend_Form
|
|||
}
|
||||
|
||||
$formData = $this->getRequestData();
|
||||
if ($this->getUidDisabled() || $this->wasSent($formData)) {
|
||||
if ($this->getIsApiTarget() || $this->getUidDisabled() || $this->wasSent($formData)) {
|
||||
if (($frameUpload = (bool) $request->getUrl()->shift('_frameUpload', false))) {
|
||||
$this->getView()->layout()->setLayout('wrapped');
|
||||
}
|
||||
|
||||
$this->populate($formData); // Necessary to get isSubmitted() to work
|
||||
if (! $this->getSubmitLabel() || $this->isSubmitted()) {
|
||||
if ($this->isValid($formData)
|
||||
&& (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this))
|
||||
|| ($this->onSuccess === null && false !== $this->onSuccess()))) {
|
||||
if (! $frameUpload) {
|
||||
|| ($this->onSuccess === null && false !== $this->onSuccess()))
|
||||
) {
|
||||
if ($this->getIsApiTarget() || $this->getRequest()->isApiRequest()) {
|
||||
// API targets and API requests will never redirect but immediately respond w/ JSON-encoded
|
||||
// notifications
|
||||
$notifications = Notification::getInstance()->popMessages();
|
||||
$message = null;
|
||||
foreach ($notifications as $notification) {
|
||||
if ($notification->type === Notification::SUCCESS) {
|
||||
$message = $notification->message;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->getResponse()->json()
|
||||
->setSuccessData($message !== null ? array('message' => $message) : null)
|
||||
->sendResponse();
|
||||
} elseif (! $frameUpload) {
|
||||
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
|
||||
} else {
|
||||
$this->getView()->layout()->redirectUrl = $this->getRedirectUrl()->getAbsoluteUrl();
|
||||
}
|
||||
} elseif ($this->getIsApiTarget()) {
|
||||
$this->getResponse()->sendJson(array(
|
||||
'status' => 'fail',
|
||||
'data' => array_merge($this->getMessages(), $this->getErrorMessages())
|
||||
));
|
||||
}
|
||||
} elseif ($this->getValidatePartial()) {
|
||||
// The form can't be processed but we may want to show validation errors though
|
||||
|
@ -1100,6 +1158,12 @@ class Form extends Zend_Form
|
|||
*/
|
||||
public function isSubmitted()
|
||||
{
|
||||
if (strtolower($this->getRequest()->getMethod()) !== $this->getMethod()) {
|
||||
return false;
|
||||
}
|
||||
if ($this->getIsApiTarget()) {
|
||||
return true;
|
||||
}
|
||||
if ($this->getSubmitLabel()) {
|
||||
return $this->getElement('btn_submit')->isChecked();
|
||||
}
|
||||
|
@ -1190,7 +1254,7 @@ class Form extends Zend_Form
|
|||
* Load the default decorators
|
||||
*
|
||||
* Overwrites Zend_Form::loadDefaultDecorators to avoid having
|
||||
* the HtmlTag-Decorator added and to provide viewscript usage
|
||||
* the HtmlTag-Decorator added and to provide view script usage
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -1332,6 +1396,19 @@ class Form extends Zend_Form
|
|||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current Response
|
||||
*
|
||||
|
@ -1464,7 +1541,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Add a error notification and prevent the form from being successfully validated
|
||||
*
|
||||
* @param string|array $message The notfication's message
|
||||
* @param string|array $message The notification message
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -1478,7 +1555,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Add a warning notification and prevent the form from being successfully validated
|
||||
*
|
||||
* @param string|array $message The notfication's message
|
||||
* @param string|array $message The notification message
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -1492,7 +1569,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Add a info notification
|
||||
*
|
||||
* @param string|array $message The notfication's message
|
||||
* @param string|array $message The notification message
|
||||
* @param bool $markAsError Whether to prevent the form from being successfully validated or not
|
||||
*
|
||||
* @return $this
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
namespace Icinga\Web;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Zend_Controller_Request_Http;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\User;
|
||||
|
||||
/**
|
||||
|
@ -13,11 +13,11 @@ use Icinga\User;
|
|||
class Request extends Zend_Controller_Request_Http
|
||||
{
|
||||
/**
|
||||
* User if authenticated
|
||||
* Response
|
||||
*
|
||||
* @var User|null
|
||||
* @var Response
|
||||
*/
|
||||
protected $user;
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Unique identifier
|
||||
|
@ -34,20 +34,24 @@ class Request extends Zend_Controller_Request_Http
|
|||
protected $url;
|
||||
|
||||
/**
|
||||
* Response
|
||||
* User if authenticated
|
||||
*
|
||||
* @var Response
|
||||
* @var User|null
|
||||
*/
|
||||
protected $response;
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Get whether the request seems to be an API request
|
||||
* Get the response
|
||||
*
|
||||
* @return bool
|
||||
* @return Response
|
||||
*/
|
||||
public function getIsApiRequest()
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->getHeader('Accept') === 'application/json';
|
||||
if ($this->response === null) {
|
||||
$this->response = Icinga::app()->getResponse();
|
||||
}
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,17 +91,13 @@ class Request extends Zend_Controller_Request_Http
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the response
|
||||
* Get whether the request seems to be an API request
|
||||
*
|
||||
* @return Response
|
||||
* @return bool
|
||||
*/
|
||||
public function getResponse()
|
||||
public function isApiRequest()
|
||||
{
|
||||
if ($this->response === null) {
|
||||
$this->response = Icinga::app()->getResponse();
|
||||
}
|
||||
|
||||
return $this->response;
|
||||
return $this->getHeader('Accept') === 'application/json';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Icinga\Web;
|
|||
|
||||
use Zend_Controller_Response_Http;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Response\JsonResponse;
|
||||
|
||||
class Response extends Zend_Controller_Response_Http
|
||||
{
|
||||
|
@ -96,6 +97,16 @@ class Response extends Zend_Controller_Response_Http
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for HTTP responses in JSON format
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public static function json()
|
||||
{
|
||||
return new JsonResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the request before sending
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Response;
|
||||
|
||||
use Zend_Controller_Action_HelperBroker;
|
||||
use Icinga\Web\Response;
|
||||
|
||||
/**
|
||||
* HTTP response in JSON format
|
||||
*/
|
||||
class JsonResponse extends Response
|
||||
{
|
||||
/**
|
||||
* Status identifier for failed API calls due to an error on the server
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STATUS_ERROR = 'error';
|
||||
|
||||
/**
|
||||
* Status identifier for rejected API calls most due to invalid data or call conditions
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STATUS_FAIL = 'fail';
|
||||
|
||||
/**
|
||||
* Status identifier for successful API requests
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const STATUS_SUCCESS = 'success';
|
||||
|
||||
/**
|
||||
* JSON encoding options
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $encodingOptions = 0;
|
||||
|
||||
/**
|
||||
* Error message if the API call failed due to a server error
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $errorMessage;
|
||||
|
||||
/**
|
||||
* Fail data for rejected API calls
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $failData;
|
||||
|
||||
/**
|
||||
* API request status
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Success data for successful API requests
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $successData;
|
||||
|
||||
/**
|
||||
* Get the JSON encoding options
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getEncodingOptions()
|
||||
{
|
||||
return $this->encodingOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSON encoding options
|
||||
*
|
||||
* @param int $encodingOptions
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setEncodingOptions($encodingOptions)
|
||||
{
|
||||
$this->encodingOptions = (int) $encodingOptions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error message if the API call failed due to a server error
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the error message if the API call failed due to a server error
|
||||
*
|
||||
* @param string $errorMessage
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setErrorMessage($errorMessage)
|
||||
{
|
||||
$this->errorMessage = (string) $errorMessage;
|
||||
$this->status = static::STATUS_ERROR;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fail data for rejected API calls
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFailData()
|
||||
{
|
||||
return $this->failData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fail data for rejected API calls
|
||||
*
|
||||
* @param array $failData
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFailData(array $failData)
|
||||
{
|
||||
$this->failData = $failData;
|
||||
$this->status = static::STATUS_FAIL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for successful API requests
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getSuccessData()
|
||||
{
|
||||
return (! is_array($this->successData) || empty($this->successData)) ? null : $this->successData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data for successful API requests
|
||||
*
|
||||
* @param array $successData
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSuccessData(array $successData = null)
|
||||
{
|
||||
$this->successData = $successData;
|
||||
$this->status = static::STATUS_SUCCESS;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function outputBody()
|
||||
{
|
||||
$body = array(
|
||||
'status' => $this->status
|
||||
);
|
||||
switch ($this->status) {
|
||||
case static::STATUS_ERROR:
|
||||
$body['message'] = $this->getErrorMessage();
|
||||
break;
|
||||
case static::STATUS_FAIL:
|
||||
$body['data'] = $this->getFailData();
|
||||
break;
|
||||
case static::STATUS_SUCCESS:
|
||||
$body['data'] = $this->getSuccessData();
|
||||
break;
|
||||
}
|
||||
echo json_encode($body, $this->getEncodingOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sendHeaders()
|
||||
{
|
||||
$this->setHeader('Content-Type', 'application/json', true);
|
||||
parent::sendHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sendResponse()
|
||||
{
|
||||
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true);
|
||||
parent::sendResponse();
|
||||
exit;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Module\Monitoring\Controller;
|
||||
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimesCommandForm;
|
||||
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm;
|
||||
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm;
|
||||
use Icinga\Module\Monitoring\Object\HostList;
|
||||
use Icinga\Module\Monitoring\Object\ServiceList;
|
||||
|
||||
/**
|
||||
* Monitoring API
|
||||
*/
|
||||
class Monitoring_ActionsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get the filter from URL parameters or exit immediately if the filter is empty
|
||||
*
|
||||
* @return Filter
|
||||
*/
|
||||
protected function getFilterOrExitIfEmpty()
|
||||
{
|
||||
$filter = Filter::fromQueryString((string) $this->params);
|
||||
if ($filter->isEmpty()) {
|
||||
$this->getResponse()->json()
|
||||
->setFailData(array('filter' => 'Filter is required and must not be empty'))
|
||||
->sendResponse();
|
||||
}
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule host downtimes
|
||||
*/
|
||||
public function scheduleHostDowntimeAction()
|
||||
{
|
||||
$filter = $this->getFilterOrExitIfEmpty();
|
||||
$hostList = new HostList($this->backend);
|
||||
$hostList
|
||||
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||
->applyFilter($filter);
|
||||
if (! $hostList->count()) {
|
||||
$this->getResponse()->json()
|
||||
->setFailData(array('filter' => 'No hosts found matching the filter'))
|
||||
->sendResponse();
|
||||
}
|
||||
$form = new ScheduleHostDowntimeCommandForm();
|
||||
$form
|
||||
->setIsApiTarget(true)
|
||||
->setObjects($hostList->fetch())
|
||||
->handleRequest($this->getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove host downtimes
|
||||
*/
|
||||
public function removeHostDowntimeAction()
|
||||
{
|
||||
$filter = $this->getFilterOrExitIfEmpty();
|
||||
$downtimes = $this->backend
|
||||
->select()
|
||||
->from('downtime', array('host_name', 'id' => 'downtime_internal_id'))
|
||||
->where('object_type', 'host')
|
||||
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||
->applyFilter($filter);
|
||||
if (! $downtimes->count()) {
|
||||
$this->getResponse()->json()
|
||||
->setFailData(array('filter' => 'No downtimes found matching the filter'))
|
||||
->sendResponse();
|
||||
}
|
||||
$form = new DeleteDowntimesCommandForm();
|
||||
$form
|
||||
->setIsApiTarget(true)
|
||||
->setDowntimes($downtimes->fetchAll())
|
||||
->handleRequest($this->getRequest());
|
||||
// @TODO(el): Respond w/ the downtimes deleted instead of the notifiaction added by
|
||||
// DeleteDowntimesCommandForm::onSuccess().
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule service downtimes
|
||||
*/
|
||||
public function scheduleServiceDowntimeAction()
|
||||
{
|
||||
$filter = $this->getFilterOrExitIfEmpty();
|
||||
$serviceList = new ServiceList($this->backend);
|
||||
$serviceList
|
||||
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||
->applyFilter($filter);
|
||||
if (! $serviceList->count()) {
|
||||
$this->getResponse()->json()
|
||||
->setFailData(array('filter' => 'No services found matching the filter'))
|
||||
->sendResponse();
|
||||
}
|
||||
$form = new ScheduleServiceDowntimeCommandForm();
|
||||
$form
|
||||
->setIsApiTarget(true)
|
||||
->setObjects($serviceList->fetch())
|
||||
->handleRequest($this->getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove service downtimes
|
||||
*/
|
||||
public function removeServiceDowntimeAction()
|
||||
{
|
||||
$filter = $this->getFilterOrExitIfEmpty();
|
||||
$downtimes = $this->backend
|
||||
->select()
|
||||
->from('downtime', array('host_name', 'service_description', 'id' => 'downtime_internal_id'))
|
||||
->where('object_type', 'service')
|
||||
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||
->applyFilter($filter);
|
||||
if (! $downtimes->count()) {
|
||||
$this->getResponse()->json()
|
||||
->setFailData(array('filter' => 'No downtimes found matching the filter'))
|
||||
->sendResponse();
|
||||
}
|
||||
$form = new DeleteDowntimesCommandForm();
|
||||
$form
|
||||
->setIsApiTarget(true)
|
||||
->setDowntimes($downtimes->fetchAll())
|
||||
->handleRequest($this->getRequest());
|
||||
// @TODO(el): Respond w/ the downtimes deleted instead of the notifiaction added by
|
||||
// DeleteDowntimesCommandForm::onSuccess().
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ use Icinga\Web\Notification;
|
|||
class DeleteCommentsCommandForm extends CommandForm
|
||||
{
|
||||
/**
|
||||
* The comments deleted on success
|
||||
* The comments to delete
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -27,6 +27,19 @@ class DeleteCommentsCommandForm extends CommandForm
|
|||
$this->setAttrib('class', 'inline');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the comments to delete
|
||||
*
|
||||
* @param array $comments
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setComments(array $comments)
|
||||
{
|
||||
$this->comments = $comments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -47,7 +60,7 @@ class DeleteCommentsCommandForm extends CommandForm
|
|||
*/
|
||||
public function getSubmitLabel()
|
||||
{
|
||||
return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
|
||||
return $this->translatePlural('Remove', 'Remove All', count($this->comments));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +70,8 @@ class DeleteCommentsCommandForm extends CommandForm
|
|||
{
|
||||
foreach ($this->comments as $comment) {
|
||||
$cmd = new DeleteCommentCommand();
|
||||
$cmd->setCommentId($comment->id)
|
||||
$cmd
|
||||
->setCommentId($comment->id)
|
||||
->setIsService(isset($comment->service_description));
|
||||
$this->getTransport($this->request)->send($cmd);
|
||||
}
|
||||
|
@ -65,20 +79,9 @@ class DeleteCommentsCommandForm extends CommandForm
|
|||
if (! empty($redirect)) {
|
||||
$this->setRedirectUrl($redirect);
|
||||
}
|
||||
Notification::success($this->translate('Deleting comment..'));
|
||||
Notification::success(
|
||||
$this->translatePlural('Deleting comment..', 'Deleting comments..', count($this->comments))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the comments to be deleted upon success
|
||||
*
|
||||
* @param array $comments
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setComments(array $comments)
|
||||
{
|
||||
$this->comments = $comments;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use Icinga\Web\Notification;
|
|||
class DeleteDowntimesCommandForm extends CommandForm
|
||||
{
|
||||
/**
|
||||
* The downtimes to delete on success
|
||||
* The downtimes to delete
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -27,6 +27,19 @@ class DeleteDowntimesCommandForm extends CommandForm
|
|||
$this->setAttrib('class', 'inline');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the downtimes to delete
|
||||
*
|
||||
* @param array $downtimes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDowntimes(array $downtimes)
|
||||
{
|
||||
$this->downtimes = $downtimes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -57,28 +70,18 @@ class DeleteDowntimesCommandForm extends CommandForm
|
|||
{
|
||||
foreach ($this->downtimes as $downtime) {
|
||||
$delDowntime = new DeleteDowntimeCommand();
|
||||
$delDowntime->setDowntimeId($downtime->id);
|
||||
$delDowntime->setIsService(isset($downtime->service_description));
|
||||
$delDowntime
|
||||
->setDowntimeId($downtime->id)
|
||||
->setIsService(isset($downtime->service_description));
|
||||
$this->getTransport($this->request)->send($delDowntime);
|
||||
}
|
||||
$redirect = $this->getElement('redirect')->getValue();
|
||||
if (! empty($redirect)) {
|
||||
$this->setRedirectUrl($redirect);
|
||||
}
|
||||
Notification::success($this->translate('Deleting downtime.'));
|
||||
Notification::success(
|
||||
$this->translatePlural('Deleting downtime..', 'Deleting downtimes..', count($this->downtimes))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the downtimes to be deleted upon success
|
||||
*
|
||||
* @param array $downtimes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDowntimes(array $downtimes)
|
||||
{
|
||||
$this->downtimes = $downtimes;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,26 +25,27 @@ class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm
|
|||
'checkbox',
|
||||
'all_services',
|
||||
array(
|
||||
'label' => $this->translate('All Services'),
|
||||
'description' => $this->translate(
|
||||
'Schedule downtime for all services on the hosts and the hosts themselves.'
|
||||
)
|
||||
),
|
||||
'label' => $this->translate('All Services'),
|
||||
'value' => false
|
||||
)
|
||||
),
|
||||
array(
|
||||
'select',
|
||||
'child_hosts',
|
||||
array(
|
||||
'description' => $this->translate(
|
||||
'Define what should be done with the child hosts of the hosts.'
|
||||
),
|
||||
'label' => $this->translate('Child Hosts'),
|
||||
'required' => true,
|
||||
'multiOptions' => array(
|
||||
0 => $this->translate('Do nothing with child hosts'),
|
||||
1 => $this->translate('Schedule triggered downtime for all child hosts'),
|
||||
2 => $this->translate('Schedule non-triggered downtime for all child hosts')
|
||||
),
|
||||
'description' => $this->translate(
|
||||
'Define what should be done with the child hosts of the hosts.'
|
||||
)
|
||||
'value' => 0
|
||||
)
|
||||
)
|
||||
));
|
||||
|
|
|
@ -18,12 +18,22 @@ class DeleteCommentCommand extends IcingaCommand
|
|||
protected $commentId;
|
||||
|
||||
/**
|
||||
* The type of the comment, either 'host' or 'service'
|
||||
* Whether the command affects a service comment
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $isService = false;
|
||||
|
||||
/**
|
||||
* Get the ID of the comment that is to be deleted
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCommentId()
|
||||
{
|
||||
return $this->commentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ID of the comment that is to be deleted
|
||||
*
|
||||
|
@ -38,17 +48,7 @@ class DeleteCommentCommand extends IcingaCommand
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the comment that is to be deleted
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCommentId()
|
||||
{
|
||||
return $this->commentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the command affects a service comment
|
||||
* Get whether the command affects a service comment
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -58,7 +58,7 @@ class DeleteCommentCommand extends IcingaCommand
|
|||
}
|
||||
|
||||
/**
|
||||
* Set whether the command affects a service
|
||||
* Set whether the command affects a service comment
|
||||
*
|
||||
* @param bool $isService
|
||||
*
|
||||
|
|
|
@ -18,33 +18,20 @@ class DeleteDowntimeCommand extends IcingaCommand
|
|||
protected $downtimeId;
|
||||
|
||||
/**
|
||||
* If the command affects a service downtime
|
||||
* Whether the command affects a service downtime
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $isService = false;
|
||||
|
||||
/**
|
||||
* Set if this command affects a service
|
||||
* Get the ID of the downtime that is to be deleted
|
||||
*
|
||||
* @param bool $isService
|
||||
*
|
||||
* @return $this
|
||||
* @return int
|
||||
*/
|
||||
public function setIsService($isService = true)
|
||||
public function getDowntimeId()
|
||||
{
|
||||
$this->isService = (bool) $isService;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the command affects a service
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsService()
|
||||
{
|
||||
return $this->isService;
|
||||
return $this->downtimeId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,12 +48,25 @@ class DeleteDowntimeCommand extends IcingaCommand
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the downtime that is to be deleted
|
||||
* Get whether the command affects a service
|
||||
*
|
||||
* @return int
|
||||
* @return bool
|
||||
*/
|
||||
public function getDowntimeId()
|
||||
public function getIsService()
|
||||
{
|
||||
return $this->downtimeId;
|
||||
return $this->isService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the command affects a service
|
||||
*
|
||||
* @param bool $isService
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIsService($isService = true)
|
||||
{
|
||||
$this->isService = (bool) $isService;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,39 +51,52 @@ class Controller extends IcingaWebController
|
|||
}
|
||||
|
||||
/**
|
||||
* Apply a restriction on the given data view
|
||||
* Apply a restriction of the authenticated on the given filterable
|
||||
*
|
||||
* @param string $restriction The name of restriction
|
||||
* @param Filterable $view The filterable to restrict
|
||||
* @param string $name Name of the restriction
|
||||
* @param Filterable $filterable Filterable to restrict
|
||||
*
|
||||
* @return Filterable The filterable
|
||||
* @return Filterable The filterable having the restriction applied
|
||||
*/
|
||||
protected function applyRestriction($restriction, Filterable $view)
|
||||
protected function applyRestriction($name, Filterable $filterable)
|
||||
{
|
||||
$restrictions = Filter::matchAny();
|
||||
$restrictions->setAllowedFilterColumns(array(
|
||||
'instance_name',
|
||||
$filterable->applyFilter($this->getRestriction($name));
|
||||
return $filterable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a restriction of the authenticated
|
||||
*
|
||||
* @param string $name Name of the restriction
|
||||
*
|
||||
* @return Filter|null Filter object or null if the authenticated user is not restricted
|
||||
* @throws ConfigurationError If the restriction contains invalid filter columns
|
||||
*/
|
||||
protected function getRestriction($name)
|
||||
{
|
||||
$restriction = Filter::matchAny();
|
||||
$restriction->setAllowedFilterColumns(array(
|
||||
'host_name',
|
||||
'hostgroup_name',
|
||||
'instance_name',
|
||||
'service_description',
|
||||
'servicegroup_name',
|
||||
function ($c) {
|
||||
return preg_match('/^_(?:host|service)_/', $c);
|
||||
}
|
||||
));
|
||||
|
||||
foreach ($this->getRestrictions($restriction) as $filter) {
|
||||
foreach ($this->getRestrictions($name) as $filter) {
|
||||
if ($filter === '*') {
|
||||
return $view;
|
||||
return Filter::matchAny();
|
||||
}
|
||||
try {
|
||||
$restrictions->addFilter(Filter::fromQueryString($filter));
|
||||
$restriction->addFilter(Filter::fromQueryString($filter));
|
||||
} catch (QueryException $e) {
|
||||
throw new ConfigurationError(
|
||||
$this->translate(
|
||||
'Cannot apply restriction %s using the filter %s. You can only use the following columns: %s'
|
||||
),
|
||||
$restriction,
|
||||
$name,
|
||||
$filter,
|
||||
implode(', ', array(
|
||||
'instance_name',
|
||||
|
@ -97,9 +110,7 @@ class Controller extends IcingaWebController
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
$view->applyFilter($restrictions);
|
||||
return $view;
|
||||
return $restriction;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
namespace Icinga\Module\Monitoring\DataView;
|
||||
|
||||
use IteratorAggregate;
|
||||
use Icinga\Data\FilterColumns;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Data\SortRules;
|
||||
use Icinga\Data\ConnectionInterface;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Filter\FilterMatch;
|
||||
use Icinga\Data\FilterColumns;
|
||||
use Icinga\Data\PivotTable;
|
||||
use Icinga\Data\ConnectionInterface;
|
||||
use Icinga\Data\QueryInterface;
|
||||
use Icinga\Data\SortRules;
|
||||
use Icinga\Exception\QueryException;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\IdoQuery;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* A read-only view of an underlying query
|
||||
|
|
|
@ -8,6 +8,14 @@ use Icinga\Web\Form;
|
|||
use Icinga\Web\Request;
|
||||
use Icinga\Test\BaseTestCase;
|
||||
|
||||
class PostRequest extends Request
|
||||
{
|
||||
public function getMethod()
|
||||
{
|
||||
return 'POST';
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessfulForm extends Form
|
||||
{
|
||||
public function onSuccess()
|
||||
|
@ -58,6 +66,7 @@ class FormTest extends BaseTestCase
|
|||
$form->setTokenDisabled();
|
||||
$form->setSubmitLabel('test');
|
||||
$form->populate(array('btn_submit' => true));
|
||||
$form->setRequest(new PostRequest());
|
||||
|
||||
$this->assertTrue(
|
||||
$form->isSubmitted(),
|
||||
|
|
Loading…
Reference in New Issue