Skip to content

Commit 7c5957f

Browse files
ContactForm: Show suggestions while typing in user element
ContactControler: Add suggestion action and cleanup code
1 parent 7866a6e commit 7c5957f

File tree

3 files changed

+114
-37
lines changed

3 files changed

+114
-37
lines changed

application/controllers/ContactController.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@
44

55
namespace Icinga\Module\Notifications\Controllers;
66

7+
use Exception;
8+
use Icinga\Application\Config;
9+
use Icinga\Authentication\User\DomainAwareInterface;
10+
use Icinga\Authentication\User\UserBackend;
11+
use Icinga\Data\Selectable;
712
use Icinga\Module\Notifications\Common\Database;
813
use Icinga\Module\Notifications\Web\Form\ContactForm;
14+
use Icinga\Repository\Repository;
915
use Icinga\Web\Notification;
1016
use ipl\Web\Compat\CompatController;
17+
use ipl\Web\FormElement\SearchSuggestions;
1118

1219
class ContactController extends CompatController
1320
{
@@ -44,4 +51,59 @@ public function indexAction(): void
4451

4552
$this->addContent($form);
4653
}
54+
55+
public function suggestIcingaWebUserAction(): void
56+
{
57+
$suggestions = new SearchSuggestions((function () use (&$suggestions) {
58+
$userBackends = [];
59+
foreach (Config::app('authentication') as $backendName => $backendConfig) {
60+
$candidate = UserBackend::create($backendName, $backendConfig);
61+
if ($candidate instanceof Selectable) {
62+
$userBackends[] = $candidate;
63+
}
64+
}
65+
66+
$limit = 10;
67+
while ($limit > 0 && ! empty($userBackends)) {
68+
/** @var Repository $backend */
69+
$backend = array_shift($userBackends);
70+
$query = $backend->select()
71+
->from('user', ['user_name'])
72+
->where('user_name', $suggestions->getSearchTerm())
73+
->limit($limit);
74+
75+
try {
76+
$names = $query->fetchColumn();
77+
} catch (Exception) {
78+
continue;
79+
}
80+
81+
if (empty($names)) {
82+
continue;
83+
}
84+
85+
$domain = null;
86+
if ($backend instanceof DomainAwareInterface && $backend->getDomain()) {
87+
$domain = '@' . $backend->getDomain();
88+
}
89+
90+
foreach ($names as $name) {
91+
yield [
92+
'search' => $name . $domain,
93+
'label' => $name . $domain,
94+
'backend' => $backend->getName(),
95+
];
96+
}
97+
98+
$limit -= count($names);
99+
}
100+
})());
101+
102+
$suggestions->setGroupingCallback(function (array $data) {
103+
return $data['backend'];
104+
});
105+
106+
$suggestions->forRequest($this->getServerRequest());
107+
$this->getDocument()->addHtml($suggestions);
108+
}
47109
}

library/Notifications/Web/Form/ContactForm.php

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
use ipl\Validator\StringLengthValidator;
2626
use ipl\Web\Common\CsrfCounterMeasure;
2727
use ipl\Web\Compat\CompatForm;
28+
use ipl\Web\FormElement\SuggestionElement;
29+
use ipl\Web\Url;
2830

2931
class ContactForm extends CompatForm
3032
{
@@ -94,40 +96,51 @@ protected function assemble()
9496
'label' => $this->translate('Contact Name'),
9597
'required' => true
9698
]
97-
)->addElement(
98-
'text',
99-
'username',
100-
[
101-
'label' => $this->translate('Icinga Web User'),
102-
'validators' => [
103-
new StringLengthValidator(['max' => 254]),
104-
new CallbackValidator(function ($value, $validator) {
105-
$contact = Contact::on($this->db)
106-
->filter(Filter::equal('username', $value));
107-
if ($this->contactId) {
108-
$contact->filter(Filter::unequal('id', $this->contactId));
109-
}
110-
111-
if ($contact->first() !== null) {
112-
$validator->addMessage($this->translate(
113-
'A contact with the same username already exists.'
114-
));
115-
116-
return false;
117-
}
118-
119-
return true;
120-
})
121-
]
122-
]
123-
)->addHtml(new HtmlElement(
124-
'p',
125-
new Attributes(['class' => 'description']),
126-
new Text($this->translate(
127-
'Add an Icinga Web user to associate with this contact.'
128-
. " Users from external authentication backends won't be suggested and must be entered manually."
129-
))
130-
));
99+
);
100+
101+
$contact
102+
->addElement(
103+
new SuggestionElement(
104+
'username',
105+
Url::fromPath(
106+
'notifications/contact/suggest-icinga-web-user',
107+
['showCompact' => true, '_disableLayout' => 1]
108+
),
109+
[
110+
'label' => $this->translate('Icinga Web User'),
111+
'validators' => [
112+
new StringLengthValidator(['max' => 254]),
113+
new CallbackValidator(function ($value, $validator) {
114+
$contact = Contact::on($this->db)
115+
->filter(Filter::equal('username', $value));
116+
if ($this->contactId) {
117+
$contact->filter(Filter::unequal('id', $this->contactId));
118+
}
119+
120+
if ($contact->first() !== null) {
121+
$validator->addMessage($this->translate(
122+
'A contact with the same username already exists.'
123+
));
124+
125+
return false;
126+
}
127+
128+
return true;
129+
})
130+
]
131+
]
132+
)
133+
)
134+
->addHtml(
135+
new HtmlElement(
136+
'p',
137+
new Attributes(['class' => 'description']),
138+
new Text($this->translate(
139+
'Add an Icinga Web user to associate with this contact.'
140+
. " Users from external authentication backends won't be suggested and must be entered manually."
141+
))
142+
)
143+
);
131144

132145
$channelQuery = Channel::on($this->db)
133146
->columns(['id', 'name', 'type']);

public/css/form.less

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@
172172
}
173173
}
174174

175-
.contact-form hr {
176-
border: none;
177-
border-top: 1px solid @gray-light;
175+
.contact-form {
176+
hr {
177+
border: none;
178+
border-top: 1px solid var(--gray-light, @gray-light);
179+
}
178180
}

0 commit comments

Comments
 (0)