From b27a3e4ba9dc1cf2580dcd932f16c59705f630f4 Mon Sep 17 00:00:00 2001 From: Bastian Lederer Date: Tue, 11 Nov 2025 15:42:15 +0100 Subject: [PATCH 1/4] Add input field for listener_username --- application/forms/SourceForm.php | 20 +++++++++++++++++++- library/Notifications/Model/Source.php | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/application/forms/SourceForm.php b/application/forms/SourceForm.php index a2dab60cb..30170c549 100644 --- a/application/forms/SourceForm.php +++ b/application/forms/SourceForm.php @@ -66,11 +66,24 @@ protected function assemble(): void 'type', [ 'required' => true, + 'class' => 'autosubmit', 'label' => $this->translate('Source Type'), 'options' => $types, 'disabledOptions' => [''] ] ); + + if ($this->getValue('type') !== 'icinga2') { + $this->addElement( + 'text', + 'listener_username', + [ + 'required' => true, + 'label' => $this->translate('Listener Username'), + ] + ); + } + $this->addElement( 'password', 'listener_password', @@ -183,6 +196,10 @@ public function editSource(): void return; } + if ($source['type'] === 'icinga2') { + $source['listener_username'] = null; + } + $source['changed_at'] = (int) (new DateTime())->format("Uv"); $this->db->update('source', $source, ['id = ?' => $this->sourceId]); } @@ -217,7 +234,8 @@ private function fetchDbValues(): array return [ 'name' => $source->name, - 'type' => $source->type + 'type' => $source->type, + 'listener_username' => $source->listener_username ]; } } diff --git a/library/Notifications/Model/Source.php b/library/Notifications/Model/Source.php index cc4f939c5..4d8d323b7 100644 --- a/library/Notifications/Model/Source.php +++ b/library/Notifications/Model/Source.php @@ -48,6 +48,7 @@ public function getColumns(): array return [ 'type', 'name', + 'listener_username', 'listener_password_hash', 'changed_at', 'deleted' @@ -59,6 +60,7 @@ public function getColumnDefinitions(): array return [ 'type' => t('Type'), 'name' => t('Name'), + 'listener_username' => t('Listener Username'), 'changed_at' => t('Changed At') ]; } From a6b6fefaf5b37165a84fdc638ca2e67c66d3a81e Mon Sep 17 00:00:00 2001 From: Bastian Lederer Date: Wed, 12 Nov 2025 09:25:16 +0100 Subject: [PATCH 2/4] remove unecessary guards, add validator to ensure unique listener username --- application/forms/SourceForm.php | 38 ++++++++++++++++---------- library/Notifications/Model/Source.php | 7 +++-- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/application/forms/SourceForm.php b/application/forms/SourceForm.php index 30170c549..7ddffd89e 100644 --- a/application/forms/SourceForm.php +++ b/application/forms/SourceForm.php @@ -66,23 +66,35 @@ protected function assemble(): void 'type', [ 'required' => true, - 'class' => 'autosubmit', 'label' => $this->translate('Source Type'), 'options' => $types, 'disabledOptions' => [''] ] ); - if ($this->getValue('type') !== 'icinga2') { - $this->addElement( - 'text', - 'listener_username', - [ - 'required' => true, - 'label' => $this->translate('Listener Username'), - ] - ); - } + $this->addElement( + 'text', + 'listener_username', + [ + 'required' => true, + 'label' => $this->translate('Listener Username'), + 'validators' => [new CallbackValidator( + function ($value, CallbackValidator $validator) { + // Deleted rows are included to avoid integrity constraint violations + $source = Source::on($this->db) + ->filter(Filter::equal('listener_username', $value)) + ->filter(Filter::any(Filter::equal('deleted', 'y'), Filter::equal('deleted', 'n'))) + ->execute(); + if ($source->hasResult()) { + $validator->addMessage($this->translate('This listener username already exists.')); + return false; + } + + return true; + } + )] + ] + ); $this->addElement( 'password', @@ -196,10 +208,6 @@ public function editSource(): void return; } - if ($source['type'] === 'icinga2') { - $source['listener_username'] = null; - } - $source['changed_at'] = (int) (new DateTime())->format("Uv"); $this->db->update('source', $source, ['id = ?' => $this->sourceId]); } diff --git a/library/Notifications/Model/Source.php b/library/Notifications/Model/Source.php index 4d8d323b7..175e060f5 100644 --- a/library/Notifications/Model/Source.php +++ b/library/Notifications/Model/Source.php @@ -21,6 +21,7 @@ * @property int $id The primary key * @property string $type Type identifier * @property string $name The user-defined name + * @property string $listener_username The username for HTTP authentication * @property ?string $listener_password_hash * @property DateTime $changed_at * @property bool $deleted @@ -58,10 +59,10 @@ public function getColumns(): array public function getColumnDefinitions(): array { return [ - 'type' => t('Type'), - 'name' => t('Name'), + 'type' => t('Type'), + 'name' => t('Name'), 'listener_username' => t('Listener Username'), - 'changed_at' => t('Changed At') + 'changed_at' => t('Changed At') ]; } From fcf625189d11dac5c06dd28104378e69c19a98bb Mon Sep 17 00:00:00 2001 From: Bastian Lederer Date: Wed, 12 Nov 2025 12:30:15 +0100 Subject: [PATCH 3/4] adjust to use null as username for deleted rows --- application/forms/DeleteSourceForm.php | 2 +- application/forms/SourceForm.php | 9 ++++----- library/Notifications/Model/Source.php | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/application/forms/DeleteSourceForm.php b/application/forms/DeleteSourceForm.php index f8dab03f0..4c7ba9b62 100644 --- a/application/forms/DeleteSourceForm.php +++ b/application/forms/DeleteSourceForm.php @@ -112,7 +112,7 @@ public function removeSource(Connection $db): void $db->update( 'source', - ['changed_at' => (int) (new DateTime())->format("Uv"), 'deleted' => 'y'], + ['changed_at' => (int) (new DateTime())->format("Uv"), 'deleted' => 'y', 'listener_username' => null], ['id = ?' => $this->source->id] ); } diff --git a/application/forms/SourceForm.php b/application/forms/SourceForm.php index 7ddffd89e..31e5d45af 100644 --- a/application/forms/SourceForm.php +++ b/application/forms/SourceForm.php @@ -80,13 +80,12 @@ protected function assemble(): void 'label' => $this->translate('Listener Username'), 'validators' => [new CallbackValidator( function ($value, CallbackValidator $validator) { - // Deleted rows are included to avoid integrity constraint violations + // Username must be unique $source = Source::on($this->db) ->filter(Filter::equal('listener_username', $value)) - ->filter(Filter::any(Filter::equal('deleted', 'y'), Filter::equal('deleted', 'n'))) - ->execute(); - if ($source->hasResult()) { - $validator->addMessage($this->translate('This listener username already exists.')); + ->first(); + if ($source !== null) { + $validator->addMessage($this->translate('This username is already in use.')); return false; } diff --git a/library/Notifications/Model/Source.php b/library/Notifications/Model/Source.php index 175e060f5..1dc16b355 100644 --- a/library/Notifications/Model/Source.php +++ b/library/Notifications/Model/Source.php @@ -21,7 +21,7 @@ * @property int $id The primary key * @property string $type Type identifier * @property string $name The user-defined name - * @property string $listener_username The username for HTTP authentication + * @property ?string $listener_username The username for HTTP authentication * @property ?string $listener_password_hash * @property DateTime $changed_at * @property bool $deleted @@ -61,7 +61,7 @@ public function getColumnDefinitions(): array return [ 'type' => t('Type'), 'name' => t('Name'), - 'listener_username' => t('Listener Username'), + 'listener_username' => t('Username'), 'changed_at' => t('Changed At') ]; } From 83d7e4c66951892c6f27873210b5abd51f39da07 Mon Sep 17 00:00:00 2001 From: Bastian Lederer Date: Wed, 12 Nov 2025 13:00:16 +0100 Subject: [PATCH 4/4] adjust username label --- application/forms/SourceForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/forms/SourceForm.php b/application/forms/SourceForm.php index 31e5d45af..565797f51 100644 --- a/application/forms/SourceForm.php +++ b/application/forms/SourceForm.php @@ -77,7 +77,7 @@ protected function assemble(): void 'listener_username', [ 'required' => true, - 'label' => $this->translate('Listener Username'), + 'label' => $this->translate('Username'), 'validators' => [new CallbackValidator( function ($value, CallbackValidator $validator) { // Username must be unique