|
7 | 7 |
|
8 | 8 | use DateTime; |
9 | 9 | use DateTimeZone; |
| 10 | +use Icinga\Module\Notifications\Common\Database; |
10 | 11 | use Icinga\Module\Notifications\Model\Schedule; |
11 | 12 | use Icinga\Web\Session; |
12 | 13 | use IntlTimeZone; |
13 | 14 | use ipl\Html\Attributes; |
14 | 15 | use ipl\Html\HtmlDocument; |
15 | 16 | use ipl\Html\HtmlElement; |
16 | 17 | use ipl\Html\Text; |
| 18 | +use ipl\Stdlib\Filter; |
17 | 19 | use ipl\Validator\CallbackValidator; |
18 | 20 | use ipl\Web\Common\CsrfCounterMeasure; |
19 | 21 | use ipl\Web\Compat\CompatForm; |
@@ -73,6 +75,16 @@ public function hasBeenRemoved(): bool |
73 | 75 | return $csrf !== null && $csrf->isValid() && $btn !== null && $btn->getName() === 'delete'; |
74 | 76 | } |
75 | 77 |
|
| 78 | + /** |
| 79 | + * Get whether the duplicate button was pressed |
| 80 | + * |
| 81 | + * @return bool |
| 82 | + */ |
| 83 | + public function hasBeenDuplicated(): bool |
| 84 | + { |
| 85 | + return $this->getPressedSubmitElement()?->getName() === 'duplicate'; |
| 86 | + } |
| 87 | + |
76 | 88 | public function __construct() |
77 | 89 | { |
78 | 90 | $this->schedule = new Schedule(); |
@@ -120,7 +132,25 @@ protected function assemble(): void |
120 | 132 | $this->addElement('text', 'name', [ |
121 | 133 | 'required' => true, |
122 | 134 | 'label' => $this->translate('Schedule Name'), |
123 | | - 'placeholder' => $this->translate('e.g. working hours, on call, etc ...') |
| 135 | + 'placeholder' => $this->translate('e.g. working hours, on call, etc ...'), |
| 136 | + 'validators' => [ |
| 137 | + new CallbackValidator(function ($value, $validator) { |
| 138 | + $schedules = Schedule::on(Database::get()) |
| 139 | + ->columns('id') |
| 140 | + ->filter(Filter::equal('name', $value)); |
| 141 | + if (! $this->hasBeenDuplicated()) { |
| 142 | + $schedules->filter(Filter::unequal('id', $this->schedule->id)); |
| 143 | + } |
| 144 | + |
| 145 | + if ($schedules->first() !== null) { |
| 146 | + $validator->addMessage($this->translate('A rotation with this name already exists')); |
| 147 | + |
| 148 | + return false; |
| 149 | + } |
| 150 | + |
| 151 | + return true; |
| 152 | + }) |
| 153 | + ] |
124 | 154 | ]); |
125 | 155 |
|
126 | 156 | if ($this->showTimezoneSuggestionInput) { |
@@ -165,17 +195,25 @@ protected function assemble(): void |
165 | 195 | 'label' => $this->getSubmitLabel() |
166 | 196 | ]); |
167 | 197 |
|
| 198 | + $additionalButtons = []; |
168 | 199 | if ($this->showRemoveButton) { |
169 | 200 | $removeBtn = $this->createElement('submit', 'delete', [ |
170 | 201 | 'label' => $this->translate('Delete'), |
171 | 202 | 'class' => 'btn-remove', |
172 | 203 | 'formnovalidate' => true |
173 | 204 | ]); |
174 | 205 | $this->registerElement($removeBtn); |
175 | | - |
176 | | - $this->getElement('submit')->prependWrapper((new HtmlDocument())->setHtmlContent($removeBtn)); |
| 206 | + $additionalButtons[] = $removeBtn; |
177 | 207 | } |
178 | 208 |
|
| 209 | + $duplicateBtn = $this->createElement('submit', 'duplicate', [ |
| 210 | + 'label' => $this->translate('Duplicate') |
| 211 | + ]); |
| 212 | + $this->registerElement($duplicateBtn); |
| 213 | + $additionalButtons[] = $duplicateBtn; |
| 214 | + |
| 215 | + $this->getElement('submit')->prependWrapper((new HtmlDocument())->setHtmlContent(...$additionalButtons)); |
| 216 | + |
179 | 217 | $this->addCsrfCounterMeasure(Session::getSession()->getId()); |
180 | 218 | } |
181 | 219 |
|
@@ -203,4 +241,9 @@ private function hasChanges(): bool |
203 | 241 |
|
204 | 242 | return $values !== $storedValues; |
205 | 243 | } |
| 244 | + |
| 245 | + public function hasBeenSubmitted() |
| 246 | + { |
| 247 | + return parent::hasBeenSubmitted() || ($this->hasBeenSent() && $this->hasBeenDuplicated()); |
| 248 | + } |
206 | 249 | } |
0 commit comments