Skip to content

Commit e2abb5c

Browse files
authored
Fix broken command transport fallback handling (#983)
fixes #950
2 parents 83af168 + e924ab8 commit e2abb5c

22 files changed

+230
-327
lines changed

application/forms/Command/CommandForm.php

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Icinga\Module\Icingadb\Forms\Command;
66

77
use ArrayIterator;
8+
use Countable;
89
use Exception;
9-
use Generator;
1010
use Icinga\Application\Logger;
1111
use Icinga\Module\Icingadb\Command\IcingaCommand;
1212
use Icinga\Module\Icingadb\Command\Transport\CommandTransport;
@@ -16,6 +16,8 @@
1616
use ipl\Html\Form;
1717
use ipl\Orm\Model;
1818
use ipl\Web\Common\CsrfCounterMeasure;
19+
use Iterator;
20+
use IteratorIterator;
1921
use Traversable;
2022

2123
abstract class CommandForm extends Form
@@ -25,7 +27,7 @@ abstract class CommandForm extends Form
2527

2628
protected $defaultAttributes = ['class' => 'icinga-form icinga-controls'];
2729

28-
/** @var mixed */
30+
/** @var (Traversable<Model>&Countable)|array<Model> */
2931
protected $objects;
3032

3133
/** @var bool */
@@ -43,7 +45,7 @@ abstract class CommandForm extends Form
4345
/**
4446
* Set the objects to issue the command for
4547
*
46-
* @param mixed $objects A traversable that is also countable
48+
* @param (Traversable<Model>&Countable)|array<Model> $objects A traversable that is also countable
4749
*
4850
* @return $this
4951
*/
@@ -57,7 +59,7 @@ public function setObjects($objects): self
5759
/**
5860
* Get the objects to issue the command for
5961
*
60-
* @return mixed
62+
* @return (Traversable<Model>&Countable)|array<Model>
6163
*/
6264
public function getObjects()
6365
{
@@ -105,11 +107,11 @@ abstract protected function assembleSubmitButton();
105107
/**
106108
* Get the commands to issue for the given objects
107109
*
108-
* @param Traversable<Model> $objects
110+
* @param Iterator<Model> $objects
109111
*
110112
* @return Traversable<IcingaCommand>
111113
*/
112-
abstract protected function getCommands(Traversable $objects): Traversable;
114+
abstract protected function getCommands(Iterator $objects): Traversable;
113115

114116
protected function assemble()
115117
{
@@ -123,10 +125,15 @@ protected function assemble()
123125

124126
protected function onSuccess()
125127
{
126-
$errors = [];
127128
$objects = $this->getObjects();
129+
if (is_array($objects)) {
130+
$objects = new ArrayIterator($objects);
131+
} else {
132+
$objects = new IteratorIterator($objects);
133+
}
128134

129-
foreach ($this->getCommands(is_array($objects) ? new ArrayIterator($objects) : $objects) as $command) {
135+
$errors = [];
136+
foreach ($this->getCommands($objects) as $command) {
130137
try {
131138
$this->sendCommand($command);
132139
} catch (Exception $e) {
@@ -159,21 +166,4 @@ protected function sendCommand(IcingaCommand $command)
159166
{
160167
(new CommandTransport())->send($command);
161168
}
162-
163-
/**
164-
* Yield the $objects the currently logged in user has the permission $permission for
165-
*
166-
* @param string $permission
167-
* @param Traversable $objects
168-
*
169-
* @return Generator
170-
*/
171-
protected function filterGrantedOn(string $permission, Traversable $objects): Generator
172-
{
173-
foreach ($objects as $object) {
174-
if ($this->isGrantedOn($permission, $object)) {
175-
yield $object;
176-
}
177-
}
178-
}
179169
}

application/forms/Command/Instance/ToggleInstanceFeaturesForm.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
99
use Icinga\Web\Notification;
1010
use ipl\Web\FormDecorator\IcingaFormDecorator;
11+
use Iterator;
1112
use Traversable;
1213

1314
class ToggleInstanceFeaturesForm extends CommandForm
@@ -133,7 +134,7 @@ protected function assembleSubmitButton()
133134
{
134135
}
135136

136-
protected function getCommands(Traversable $objects): Traversable
137+
protected function getCommands(Iterator $objects): Traversable
137138
{
138139
foreach ($this->features as $feature => $spec) {
139140
$featureState = $this->getElement($feature)->isChecked();

application/forms/Command/Object/AcknowledgeProblemForm.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7+
use CallbackFilterIterator;
78
use DateInterval;
89
use DateTime;
910
use Icinga\Application\Config;
@@ -14,9 +15,11 @@
1415
use ipl\Html\Attributes;
1516
use ipl\Html\HtmlElement;
1617
use ipl\Html\Text;
18+
use ipl\Orm\Model;
1719
use ipl\Validator\CallbackValidator;
1820
use ipl\Web\FormDecorator\IcingaFormDecorator;
1921
use ipl\Web\Widget\Icon;
22+
use Iterator;
2023
use Traversable;
2124

2225
use function ipl\Stdlib\iterable_value_first;
@@ -186,10 +189,13 @@ protected function assembleSubmitButton()
186189
(new IcingaFormDecorator())->decorate($this->getElement('btn_submit'));
187190
}
188191

189-
protected function getCommands(Traversable $objects): Traversable
192+
protected function getCommands(Iterator $objects): Traversable
190193
{
191-
$granted = $this->filterGrantedOn('icingadb/command/acknowledge-problem', $objects);
194+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
195+
return $this->isGrantedOn('icingadb/command/acknowledge-problem', $object);
196+
});
192197

198+
$granted->rewind(); // Forwards the pointer to the first element
193199
if ($granted->valid()) {
194200
$command = new AcknowledgeProblemCommand();
195201
$command->setObjects($granted);

application/forms/Command/Object/AddCommentForm.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7+
use CallbackFilterIterator;
78
use DateInterval;
89
use DateTime;
910
use Icinga\Application\Config;
@@ -14,9 +15,11 @@
1415
use ipl\Html\Attributes;
1516
use ipl\Html\HtmlElement;
1617
use ipl\Html\Text;
18+
use ipl\Orm\Model;
1719
use ipl\Validator\CallbackValidator;
1820
use ipl\Web\FormDecorator\IcingaFormDecorator;
1921
use ipl\Web\Widget\Icon;
22+
use Iterator;
2023
use Traversable;
2124

2225
use function ipl\Stdlib\iterable_value_first;
@@ -141,10 +144,13 @@ protected function assembleSubmitButton()
141144
(new IcingaFormDecorator())->decorate($this->getElement('btn_submit'));
142145
}
143146

144-
protected function getCommands(Traversable $objects): Traversable
147+
protected function getCommands(Iterator $objects): Traversable
145148
{
146-
$granted = $this->filterGrantedOn('icingadb/command/comment/add', $objects);
149+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
150+
return $this->isGrantedOn('icingadb/command/comment/add', $object);
151+
});
147152

153+
$granted->rewind(); // Forwards the pointer to the first element
148154
if ($granted->valid()) {
149155
$command = new AddCommentCommand();
150156
$command->setObjects($granted);

application/forms/Command/Object/CheckNowForm.php

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7-
use Generator;
7+
use CallbackFilterIterator;
88
use Icinga\Module\Icingadb\Command\Object\ScheduleCheckCommand;
99
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
1010
use Icinga\Web\Notification;
11+
use ipl\Orm\Model;
1112
use ipl\Web\Widget\Icon;
13+
use Iterator;
1214
use Traversable;
1315

1416
class CheckNowForm extends CommandForm
@@ -44,22 +46,17 @@ protected function assembleSubmitButton()
4446
);
4547
}
4648

47-
protected function getCommands(Traversable $objects): Traversable
49+
protected function getCommands(Iterator $objects): Traversable
4850
{
49-
$granted = (function () use ($objects): Generator {
50-
foreach ($objects as $object) {
51-
if (
52-
$this->isGrantedOn('icingadb/command/schedule-check', $object)
53-
|| (
54-
$object->active_checks_enabled
55-
&& $this->isGrantedOn('icingadb/command/schedule-check/active-only', $object)
56-
)
57-
) {
58-
yield $object;
59-
}
60-
}
61-
})();
51+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
52+
return $this->isGrantedOn('icingadb/command/schedule-check', $object)
53+
|| (
54+
$object->active_checks_enabled
55+
&& $this->isGrantedOn('icingadb/command/schedule-check/active-only', $object)
56+
);
57+
});
6258

59+
$granted->rewind(); // Forwards the pointer to the first element
6360
if ($granted->valid()) {
6461
$command = new ScheduleCheckCommand();
6562
$command->setObjects($granted);

application/forms/Command/Object/DeleteCommentForm.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7-
use Generator;
7+
use CallbackFilterIterator;
88
use Icinga\Module\Icingadb\Command\Object\DeleteCommentCommand;
99
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
1010
use Icinga\Web\Notification;
11+
use ipl\Orm\Model;
1112
use ipl\Web\Common\RedirectOption;
1213
use ipl\Web\Widget\Icon;
14+
use Iterator;
1315
use Traversable;
1416

1517
class DeleteCommentForm extends CommandForm
@@ -54,16 +56,13 @@ protected function assembleSubmitButton()
5456
);
5557
}
5658

57-
protected function getCommands(Traversable $objects): Traversable
59+
protected function getCommands(Iterator $objects): Traversable
5860
{
59-
$granted = (function () use ($objects): Generator {
60-
foreach ($objects as $object) {
61-
if ($this->isGrantedOn('icingadb/command/comment/delete', $object->{$object->object_type})) {
62-
yield $object;
63-
}
64-
}
65-
})();
61+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
62+
return $this->isGrantedOn('icingadb/command/comment/delete', $object->{$object->object_type});
63+
});
6664

65+
$granted->rewind(); // Forwards the pointer to the first element
6766
if ($granted->valid()) {
6867
$command = new DeleteCommentCommand();
6968
$command->setObjects($granted);

application/forms/Command/Object/DeleteDowntimeForm.php

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7-
use Generator;
7+
use CallbackFilterIterator;
88
use Icinga\Module\Icingadb\Command\Object\DeleteDowntimeCommand;
99
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
1010
use Icinga\Web\Notification;
11+
use ipl\Orm\Model;
1112
use ipl\Web\Common\RedirectOption;
1213
use ipl\Web\Widget\Icon;
14+
use Iterator;
1315
use Traversable;
1416

1517
class DeleteDowntimeForm extends CommandForm
@@ -66,19 +68,14 @@ protected function assembleSubmitButton()
6668
);
6769
}
6870

69-
protected function getCommands(Traversable $objects): Traversable
71+
protected function getCommands(Iterator $objects): Traversable
7072
{
71-
$granted = (function () use ($objects): Generator {
72-
foreach ($objects as $object) {
73-
if (
74-
$this->isGrantedOn('icingadb/command/downtime/delete', $object->{$object->object_type})
75-
&& $object->scheduled_by === null
76-
) {
77-
yield $object;
78-
}
79-
}
80-
})();
73+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
74+
return $object->scheduled_by === null
75+
&& $this->isGrantedOn('icingadb/command/downtime/delete', $object->{$object->object_type});
76+
});
8177

78+
$granted->rewind(); // Forwards the pointer to the first element
8279
if ($granted->valid()) {
8380
$command = new DeleteDowntimeCommand();
8481
$command->setObjects($granted);

application/forms/Command/Object/ProcessCheckResultForm.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7-
use Generator;
7+
use CallbackFilterIterator;
88
use Icinga\Module\Icingadb\Command\Object\ProcessCheckResultCommand;
99
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
1010
use Icinga\Module\Icingadb\Model\Host;
@@ -15,6 +15,7 @@
1515
use ipl\Orm\Model;
1616
use ipl\Web\FormDecorator\IcingaFormDecorator;
1717
use ipl\Web\Widget\Icon;
18+
use Iterator;
1819
use Traversable;
1920

2021
use function ipl\Stdlib\iterable_value_first;
@@ -133,16 +134,14 @@ protected function assembleSubmitButton()
133134
(new IcingaFormDecorator())->decorate($this->getElement('btn_submit'));
134135
}
135136

136-
protected function getCommands(Traversable $objects): Traversable
137+
protected function getCommands(Iterator $objects): Traversable
137138
{
138-
$granted = (function () use ($objects): Generator {
139-
foreach ($this->filterGrantedOn('icingadb/command/process-check-result', $objects) as $object) {
140-
if ($object->passive_checks_enabled) {
141-
yield $object;
142-
}
143-
}
144-
})();
139+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
140+
return $object->passive_checks_enabled
141+
&& $this->isGrantedOn('icingadb/command/process-check-result', $object);
142+
});
145143

144+
$granted->rewind(); // Forwards the pointer to the first element
146145
if ($granted->valid()) {
147146
$command = new ProcessCheckResultCommand();
148147
$command->setObjects($granted);

application/forms/Command/Object/RemoveAcknowledgementForm.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
namespace Icinga\Module\Icingadb\Forms\Command\Object;
66

7+
use CallbackFilterIterator;
78
use Icinga\Module\Icingadb\Command\Object\RemoveAcknowledgementCommand;
89
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
910
use Icinga\Module\Icingadb\Model\Host;
1011
use Icinga\Web\Notification;
12+
use ipl\Orm\Model;
1113
use ipl\Web\Widget\Icon;
14+
use Iterator;
1215
use Traversable;
1316

1417
use function ipl\Stdlib\iterable_value_first;
@@ -62,10 +65,13 @@ protected function assembleSubmitButton()
6265
);
6366
}
6467

65-
protected function getCommands(Traversable $objects): Traversable
68+
protected function getCommands(Iterator $objects): Traversable
6669
{
67-
$granted = $this->filterGrantedOn('icingadb/command/remove-acknowledgement', $objects);
70+
$granted = new CallbackFilterIterator($objects, function (Model $object): bool {
71+
return $this->isGrantedOn('icingadb/command/remove-acknowledgement', $object);
72+
});
6873

74+
$granted->rewind(); // Forwards the pointer to the first element
6975
if ($granted->valid()) {
7076
$command = new RemoveAcknowledgementCommand();
7177
$command->setObjects($granted);

0 commit comments

Comments
 (0)