44
55namespace Icinga \Module \Notifications \Controllers ;
66
7+ use Icinga \Application \Hook ;
8+ use Icinga \Application \Logger ;
79use Icinga \Exception \Http \HttpNotFoundException ;
810use Icinga \Module \Notifications \Common \Auth ;
911use Icinga \Module \Notifications \Common \Database ;
1012use Icinga \Module \Notifications \Common \Links ;
1113use Icinga \Module \Notifications \Forms \EventRuleConfigElements \NotificationConfigProvider ;
1214use Icinga \Module \Notifications \Forms \EventRuleConfigForm ;
1315use Icinga \Module \Notifications \Forms \EventRuleForm ;
16+ use Icinga \Module \Notifications \Hook \V1 \SourceHook ;
1417use Icinga \Module \Notifications \Model \Rule ;
18+ use Icinga \Module \Notifications \Model \Source ;
1519use Icinga \Module \Notifications \Web \Control \SearchBar \ExtraTagSuggestions ;
1620use Icinga \Web \Notification ;
1721use Icinga \Web \Session ;
18- use ipl \Html \Form ;
22+ use ipl \Html \Contract \ Form ;
1923use ipl \Html \Html ;
2024use ipl \Stdlib \Filter ;
2125use ipl \Web \Compat \CompatController ;
22- use ipl \Web \Control \SearchEditor ;
23- use ipl \Web \Filter \Renderer ;
26+ use ipl \Web \Compat \CompatForm ;
2427use ipl \Web \Url ;
2528use ipl \Web \Widget \Icon ;
2629use ipl \Web \Widget \Link ;
2730use Psr \Http \Message \ServerRequestInterface ;
31+ use Throwable ;
2832
2933class EventRuleController extends CompatController
3034{
@@ -55,7 +59,7 @@ public function indexAction(): void
5559 ))->setCsrfCounterMeasureId (Session::getSession ()->getId ());
5660
5761 $ eventRuleConfig
58- ->on (Form::ON_SUCCESS , function (EventRuleConfigForm $ form ) use ($ ruleId ) {
62+ ->on (Form::ON_SUBMIT , function (EventRuleConfigForm $ form ) use ($ ruleId ) {
5963 if ($ ruleId !== -1 ) {
6064 $ rule = $ this ->fetchRule ($ ruleId );
6165 } else {
@@ -72,7 +76,9 @@ public function indexAction(): void
7276 })
7377 ->on (Form::ON_SENT , function (EventRuleConfigForm $ form ) use ($ ruleId ) {
7478 if ($ form ->hasBeenRemoved ()) {
75- $ form ->removeRule (Database::get (), $ this ->fetchRule ($ ruleId ));
79+ Database::get ()->transaction (
80+ fn () => $ form ::removeRule (Database::get (), $ this ->fetchRule ($ ruleId ))
81+ );
7682 Notification::success (sprintf (
7783 $ this ->translate ('Successfully deleted event rule %s ' ),
7884 $ form ->getValue ('name ' )
@@ -95,7 +101,10 @@ public function indexAction(): void
95101
96102 if ($ nameOnly ) {
97103 $ this ->addPart ($ form ->prepareObjectFilterUpdate ($ this ->session ->get ('object_filter ' )));
98- $ this ->addPart ($ form ->prepareNameUpdate ($ this ->session ->get ('name ' )));
104+ $ this ->addPart ($ form ->prepareConfigUpdate (
105+ $ this ->session ->get ('name ' ),
106+ $ this ->session ->get ('source ' )
107+ ));
99108 $ this ->addPart (Html::tag ('div ' , ['id ' => 'event-rule-config-name ' ], [
100109 Html::tag ('h2 ' , $ this ->session ->get ('name ' )),
101110 (new Link (
@@ -105,7 +114,10 @@ public function indexAction(): void
105114 ))->openInModal ()
106115 ]));
107116 } else {
108- $ this ->addPart ($ form ->prepareNameUpdate ($ this ->session ->get ('name ' )));
117+ $ this ->addPart ($ form ->prepareConfigUpdate (
118+ $ this ->session ->get ('name ' ),
119+ $ this ->session ->get ('source ' )
120+ ));
109121 $ this ->addPart ($ form ->prepareObjectFilterUpdate ($ this ->session ->get ('object_filter ' )));
110122 }
111123
@@ -116,12 +128,15 @@ public function indexAction(): void
116128 $ form ->load ($ rule );
117129
118130 $ this ->session ->set ('name ' , $ rule ->name );
131+ $ this ->session ->set ('source ' , $ rule ->source_id );
119132 $ this ->session ->set ('object_filter ' , $ rule ->object_filter ?? '' );
120133 } else {
121134 $ name = $ this ->params ->getRequired ('name ' );
122- $ form ->populate (['id ' => $ ruleId , 'name ' => $ name ]);
135+ $ source = $ this ->params ->getRequired ('source ' );
136+ $ form ->populate (['id ' => $ ruleId , 'name ' => $ name , 'source ' => $ source ]);
123137
124138 $ this ->session ->set ('name ' , $ name );
139+ $ this ->session ->set ('source ' , $ source );
125140 $ this ->session ->set ('object_filter ' , '' );
126141 }
127142 })
@@ -172,31 +187,93 @@ public function completeAction(): void
172187 public function searchEditorAction (): void
173188 {
174189 $ ruleId = (int ) $ this ->params ->getRequired ('id ' );
190+ $ filter = $ this ->params ->get ('object_filter ' , $ this ->session ->get ('object_filter ' ));
191+
192+ $ source = null ;
193+ if ($ ruleId !== -1 ) {
194+ $ source = Rule::on (Database::get ())
195+ ->columns (['id ' => 'source.id ' , 'type ' => 'source.type ' ])
196+ ->filter (Filter::all (
197+ Filter::equal ('id ' , $ ruleId ),
198+ Filter::equal ('deleted ' , 'n ' )
199+ ))
200+ ->first ();
201+ } elseif (isset ($ this ->session ->source )) {
202+ $ source = Source::on (Database::get ())
203+ ->columns (['id ' , 'type ' ])
204+ ->filter (Filter::equal ('id ' , $ this ->session ->source ))
205+ ->first ();
206+ }
175207
176- $ editor = new SearchEditor ();
208+ if ($ source === null ) {
209+ $ this ->httpNotFound ($ this ->translate ('Rule not found ' ));
210+ }
211+
212+ $ hook = null ;
213+ foreach (Hook::all ('Notifications/v1/Source ' ) as $ h ) {
214+ /** @var SourceHook $h */
215+ try {
216+ if ($ h ->getSourceType () === $ source ->type ) {
217+ $ hook = $ h ;
218+
219+ break ;
220+ }
221+ } catch (Throwable $ e ) {
222+ Logger::error ('Failed to load source integration %s: %s ' , $ h ::class, $ e );
223+ }
224+ }
225+
226+ if ($ hook === null ) {
227+ $ this ->httpNotFound (sprintf ($ this ->translate (
228+ 'No source integration available. Either the module supporting sources of type "%s" is not '
229+ . ' enabled or you have insufficient privileges. Please contact your system administrator. '
230+ ), $ source ->type ));
231+ }
232+
233+ if (! $ filter ) {
234+ $ targets = $ hook ->getRuleFilterTargets ($ source ->id );
235+ if (count ($ targets ) === 1 && ! is_array (reset ($ targets ))) {
236+ $ filter = key ($ targets );
237+ } else {
238+ $ target = null ;
239+ $ form = (new CompatForm ())
240+ ->applyDefaultElementDecorators ()
241+ ->setAction (Url::fromRequest ()->getAbsoluteUrl ())
242+ ->addElement ('select ' , 'target ' , [
243+ 'required ' => true ,
244+ 'label ' => $ this ->translate ('Filter Target ' ),
245+ 'options ' => ['' => ' - ' . $ this ->translate ('Please choose ' ) . ' - ' ] + $ targets ,
246+ 'disabledOptions ' => ['' ]
247+ ])
248+ ->addElement ('submit ' , 'btn_submit ' , [
249+ // translators: shown on a submit button to proceed to the next step of a form wizard
250+ 'label ' => $ this ->translate ('Next ' )
251+ ])
252+ ->on (Form::ON_SUBMIT , function (CompatForm $ form ) use (&$ target ) {
253+ $ target = $ form ->getValue ('target ' );
254+ })
255+ ->handleRequest ($ this ->getServerRequest ());
256+
257+ if ($ target !== null ) {
258+ $ filter = $ target ;
259+ } else {
260+ $ this ->addContent ($ form );
261+ }
262+ }
263+ }
264+
265+ if ($ filter ) {
266+ $ form = $ hook ->getRuleFilterEditor ($ filter )
267+ ->setAction (Url::fromRequest ()->with ('object_filter ' , $ filter )->getAbsoluteUrl ())
268+ ->on (Form::ON_SUBMIT , function (Form $ form ) use ($ ruleId , $ hook ) {
269+ $ this ->session ->set ('object_filter ' , $ hook ->serializeRuleFilter ($ form ));
270+ $ this ->redirectNow (Links::eventRule ($ ruleId )->setParam ('_filterOnly ' ));
271+ })
272+ ->handleRequest ($ this ->getServerRequest ());
273+
274+ $ this ->getDocument ()->addHtml ($ form );
275+ }
177276
178- $ editor ->setQueryString ($ this ->session ->get ('object_filter ' ))
179- ->setAction (Url::fromRequest ()->getAbsoluteUrl ())
180- ->setSuggestionUrl (
181- Url::fromPath ('notifications/event-rule/complete ' , [
182- 'id ' => $ ruleId ,
183- '_disableLayout ' => true ,
184- 'showCompact ' => true
185- ])
186- );
187-
188- $ editor ->on (Form::ON_SUCCESS , function (SearchEditor $ form ) use ($ ruleId ) {
189- $ filter = (new Renderer ($ form ->getFilter ()))->render ();
190- // TODO: Should not be needed for the new filter implementation
191- $ filter = preg_replace ('/(?:=|~|!|%3[EC])(?=[|&]|$)/ ' , '' , $ filter );
192-
193- $ this ->session ->set ('object_filter ' , $ filter );
194- $ this ->redirectNow (Links::eventRule ($ ruleId )->setParam ('_filterOnly ' ));
195- });
196-
197- $ editor ->handleRequest ($ this ->getServerRequest ());
198-
199- $ this ->getDocument ()->addHtml ($ editor );
200277 $ this ->setTitle ($ this ->translate ('Adjust Filter ' ));
201278 }
202279
@@ -206,10 +283,25 @@ public function editAction(): void
206283
207284 $ eventRuleForm = (new EventRuleForm ())
208285 ->setCsrfCounterMeasureId (Session::getSession ()->getId ())
209- ->populate (['name ' => $ this ->session ->get ('name ' )])
286+ ->setAvailableSources (
287+ Database::get ()->fetchPairs (
288+ Source::on (Database::get ())->columns (['id ' , 'name ' ])->assembleSelect ()
289+ )
290+ )
291+ ->populate ([
292+ 'name ' => $ this ->session ->get ('name ' ),
293+ 'source ' => $ this ->session ->get ('source ' )
294+ ])
210295 ->setAction (Url::fromRequest ()->getAbsoluteUrl ())
211- ->on (Form::ON_SUCCESS , function ($ form ) use ($ ruleId ) {
296+ ->on (Form::ON_SUBMIT , function ($ form ) use ($ ruleId ) {
212297 $ this ->session ->set ('name ' , $ form ->getValue ('name ' ));
298+
299+ $ newSource = $ form ->getValue ('source ' );
300+ if ($ newSource !== $ this ->session ->get ('source ' )) {
301+ $ this ->session ->set ('source ' , $ newSource );
302+ $ this ->session ->set ('object_filter ' , '' );
303+ }
304+
213305 $ this ->redirectNow (Links::eventRule ($ ruleId )->setParam ('_nameOnly ' ));
214306 })->handleRequest ($ this ->getServerRequest ());
215307
0 commit comments