Merge branch 'feature/api-9606'

refs #9606
This commit is contained in:
Eric Lippmann 2015-09-07 13:57:21 +02:00
commit c0f39de200
19 changed files with 637 additions and 137 deletions

View File

@ -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;
}
}

View File

@ -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()

View File

@ -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)
{

View File

@ -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
{
}

View File

@ -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
*

View File

@ -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();

View File

@ -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

View File

@ -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';
}
/**

View File

@ -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
*/

View File

@ -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;
}
}

View File

@ -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().
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
)
)
));

View File

@ -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
*

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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(),