Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make command actions easier to use with curl #863

Merged
merged 2 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions application/forms/Command/CommandForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ abstract class CommandForm extends Form
/** @var mixed */
protected $objects;

/** @var bool */
protected $isApiTarget = false;

/**
* Whether an error occurred while sending the command
*
Expand Down Expand Up @@ -61,6 +64,30 @@ public function getObjects()
return $this->objects;
}

/**
* Set whether this form is an API target
*
* @param bool $state
*
* @return $this
*/
public function setIsApiTarget(bool $state = true): self
{
$this->isApiTarget = $state;

return $this;
}

/**
* Get whether this form is an API target
*
* @return bool
*/
public function isApiTarget(): bool
{
return $this->isApiTarget;
}

/**
* Create and add form elements representing the command's options
*
Expand All @@ -87,8 +114,11 @@ abstract protected function getCommands(Traversable $objects): Traversable;
protected function assemble()
{
$this->assembleElements();
$this->assembleSubmitButton();
$this->addElement($this->createCsrfCounterMeasure(Session::getSession()->getId()));

if (! $this->isApiTarget()) {
$this->assembleSubmitButton();
$this->addElement($this->createCsrfCounterMeasure(Session::getSession()->getId()));
}
}

protected function onSuccess()
Expand Down
61 changes: 57 additions & 4 deletions library/Icingadb/Common/CommandActions.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Icinga\Module\Icingadb\Common;

use GuzzleHttp\Psr7\ServerRequest;
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
use Icinga\Module\Icingadb\Forms\Command\Object\AcknowledgeProblemForm;
use Icinga\Module\Icingadb\Forms\Command\Object\AddCommentForm;
Expand All @@ -17,6 +16,7 @@
use Icinga\Module\Icingadb\Forms\Command\Object\SendCustomNotificationForm;
use Icinga\Module\Icingadb\Forms\Command\Object\ToggleObjectFeaturesForm;
use Icinga\Security\SecurityException;
use Icinga\Web\Notification;
use ipl\Orm\Model;
use ipl\Orm\Query;
use ipl\Web\Url;
Expand Down Expand Up @@ -138,11 +138,35 @@ protected function assertIsGrantedOnCommandTargets(string $permission)
*/
protected function handleCommandForm($form)
{
$isXhr = $this->getRequest()->isXmlHttpRequest();
if ($isXhr && $this->getRequest()->isApiRequest()) {
// Prevents the framework already, this is just a fail-safe
$this->httpBadRequest('Responding with JSON during a Web request is not supported');
}

if (is_string($form)) {
/** @var \Icinga\Module\Icingadb\Forms\Command\CommandForm $form */
/** @var CommandForm $form */
$form = new $form();
}

$form->setObjects($this->getCommandTargets());

if ($isXhr) {
$this->handleWebRequest($form);
} else {
$this->handleApiRequest($form);
}
}

/**
* Handle a Web request for the given form
*
* @param CommandForm $form
*
* @return void
*/
protected function handleWebRequest(CommandForm $form): void
{
$actionUrl = $this->getRequest()->getUrl();
if ($this->view->compact) {
$actionUrl = clone $actionUrl;
Expand All @@ -153,7 +177,6 @@ protected function handleCommandForm($form)
}

$form->setAction($actionUrl->getAbsoluteUrl());
$form->setObjects($this->getCommandTargets());
$form->on($form::ON_SUCCESS, function () {
// This forces the column to reload nearly instantly after the redirect
// and ensures the effect of the command is visible to the user asap
Expand All @@ -162,11 +185,41 @@ protected function handleCommandForm($form)
$this->redirectNow($this->getCommandTargetsUrl());
});

$form->handleRequest(ServerRequest::fromGlobals());
$form->handleRequest($this->getServerRequest());

$this->addContent($form);
}

/**
* Handle an API request for the given form
*
* @param CommandForm $form
*
* @return never
*/
protected function handleApiRequest(CommandForm $form)
{
$form->setIsApiTarget();
$form->on($form::ON_SUCCESS, function () {
$this->getResponse()
->json()
->setSuccessData(Notification::getInstance()->popMessages())
->sendResponse();
});

$form->handleRequest($this->getServerRequest());

$errors = [];
foreach ($form->getElements() as $element) {
$errors[$element->getName()] = $element->getMessages();
}

$response = $this->getResponse()->json();
$response->setHttpResponseCode(422);
$response->setFailData($errors)
->sendResponse();
}

public function acknowledgeAction()
{
$this->assertIsGrantedOnCommandTargets('icingadb/command/acknowledge-problem');
Expand Down