66
77use Icinga \Exception \Http \HttpBadRequestException ;
88use Icinga \Exception \Http \HttpException ;
9+ use Icinga \Exception \Http \HttpNotFoundException ;
910use Icinga \Module \Notifications \Common \Database ;
1011use Icinga \Util \Environment ;
1112use Icinga \Util \Json ;
@@ -164,13 +165,12 @@ function (Filter\Condition $condition) {
164165 $ db ->beginTransaction ();
165166
166167 if ($ identifier === null ) {
167- $ identifier = $ data ['id ' ];
168-
169- if ($ this ->getContactId ($ identifier ) !== null ) {
168+ if ($ this ->getContactId ($ data ['id ' ]) !== null ) {
170169 throw new HttpException ('422 ' , 'Contact already exists ' );
171170 }
172171
173172 $ this ->addContact ($ data );
173+ $ identifier = $ data ['id ' ];
174174 } else {
175175 $ contactId = $ this ->getContactId ($ identifier );
176176 if ($ contactId === null ) {
@@ -181,9 +181,10 @@ function (Filter\Condition $condition) {
181181 throw new HttpException ('422 ' , 'Contact already exists ' );
182182 }
183183
184- $ identifier = $ data ['id ' ];
185184 $ this ->removeContact ($ contactId );
186185 $ this ->addContact ($ data );
186+
187+ $ identifier = $ data ['id ' ];
187188 }
188189
189190 $ db ->commitTransaction ();
@@ -219,24 +220,11 @@ function (Filter\Condition $condition) {
219220 $ db ->delete ('contactgroup_member ' , ['contact_id = ? ' => $ contactId ]);
220221
221222 if (! empty ($ data ['addresses ' ])) {
222- foreach ($ data ['addresses ' ] as $ type => $ address ) {
223- $ db ->insert ('contact_address ' , [
224- 'contact_id ' => $ contactId ,
225- 'type ' => $ type ,
226- 'address ' => $ address
227- ]);
228- }
223+ $ this ->addAddresses ($ contactId , $ data ['addresses ' ]);
229224 }
230225
231226 if (! empty ($ data ['groups ' ])) {
232- $ this ->assertGroupsExist ($ data ['groups ' ]);
233-
234- foreach ($ data ['groups ' ] as $ group ) {
235- $ db ->insert ('contactgroup_member ' , [
236- 'contact_id ' => $ contactId ,
237- 'contactgroup_id ' => $ group
238- ]);
239- }
227+ $ this ->addGroups ($ contactId , $ data ['groups ' ]);
240228 }
241229
242230 $ responseCode = 204 ;
@@ -282,7 +270,8 @@ function (Filter\Condition $condition) {
282270 * @param string $channelName
283271 *
284272 * @return int
285- * @throws HttpException if the channel does not exist
273+ *
274+ * @throws HttpNotFoundException if the channel does not exist
286275 */
287276 private function getChannelId (string $ channelName ): int
288277 {
@@ -294,7 +283,7 @@ private function getChannelId(string $channelName): int
294283 );
295284
296285 if ($ channel === false ) {
297- throw new HttpException ( ' 404 ' , 'Channel not found ' );
286+ throw new HttpNotFoundException ( 'Channel not found ' );
298287 }
299288
300289 return $ channel ->id ;
@@ -341,24 +330,28 @@ private function fetchGroupIdentifiers(int $contactId): ?array
341330 }
342331
343332 /**
344- * Assert that the given group IDs exist
333+ * Get the group id with the given identifier
345334 *
346- * @param array $groupIds
335+ * @param string $identifier
347336 *
348- * @throws HttpException 404 if a group does not exist
337+ * @return int
338+ *
339+ * @throws HttpNotFoundException if the contactgroup with the given identifier does not exist
349340 */
350- private function assertGroupsExist ( array $ groupIds ): void
341+ private function getGroupId ( string $ identifier ): int
351342 {
352- $ existingGroupIds = Database::get ()->fetchCol (
343+ $ group = Database::get ()->fetchOne (
353344 (new Select ())
354345 ->from ('contactgroup ' )
355346 ->columns ('id ' )
356- ->where (['id IN (?) ' => $ groupIds ])
347+ ->where (['external_uuid = ? ' => $ identifier ])
357348 );
358349
359- if (count ( $ existingGroupIds ) !== count ( $ groupIds ) ) {
360- throw new HttpException ( ' 404 ' , 'Undefined group identifier given ' );
350+ if ($ group === false ) {
351+ throw new HttpNotFoundException ( 'Undefined group identifier given ' );
361352 }
353+
354+ return $ group ->id ;
362355 }
363356
364357 /**
@@ -385,12 +378,16 @@ protected function getContactId(string $identifier): ?int
385378 *
386379 * @param array $data
387380 *
388- * @throws HttpException if a group or default_channel does not exist
381+ * @return void
389382 */
390383 private function addContact (array $ data ): void
391384 {
392385 $ db = Database::get ();
393386
387+ if (isset ($ data ['username ' ])) {
388+ $ this ->assertUniqueUsername ($ data ['username ' ]);
389+ }
390+
394391 $ db ->insert ('contact ' , [
395392 'full_name ' => $ data ['full_name ' ],
396393 'username ' => $ data ['username ' ] ?? null ,
@@ -401,31 +398,108 @@ private function addContact(array $data): void
401398 $ contactId = $ db ->lastInsertId ();
402399
403400 if (! empty ($ data ['addresses ' ])) {
404- foreach ($ data ['addresses ' ] as $ type => $ address ) {
405- $ db ->insert ('contact_address ' , [
406- 'contact_id ' => $ contactId ,
407- 'type ' => $ type ,
408- 'address ' => $ address
409- ]);
410- }
401+ $ this ->addAddresses ($ contactId , $ data ['addresses ' ]);
411402 }
412403
413404 if (! empty ($ data ['groups ' ])) {
414- $ this ->assertGroupsExist ($ data ['groups ' ]);
415-
416- foreach ($ data ['groups ' ] as $ groupId ) {
417- $ db ->insert ('contactgroup_member ' , [
418- 'contact_id ' => $ contactId ,
419- 'contactgroup_id ' => $ groupId
420- ]);
421- }
405+ $ this ->addGroups ($ contactId , $ data ['groups ' ]);
406+ }
407+ }
408+
409+ /**
410+ * Assert that the username is unique
411+ *
412+ * @param string $username
413+ *
414+ * @return void
415+ *
416+ * @throws HttpBadRequestException if the username already exists
417+ */
418+ private function assertUniqueUsername (string $ username ): void
419+ {
420+ $ user = Database::get ()->fetchOne (
421+ (new Select ())
422+ ->from ('contact ' )
423+ ->columns (1 )
424+ ->where (['username = ? ' => $ username ])
425+ );
426+
427+ if ($ user !== false ) {
428+ $ this ->httpBadRequest ('Username already exists ' );
429+ }
430+ }
431+
432+ /**
433+ * Assert that the address type exists
434+ *
435+ * @param array $addressTypes
436+ *
437+ * @return void
438+ *
439+ * @throws HttpBadRequestException if the username already exists
440+ */
441+ private function assertAddressTypesExist (array $ addressTypes ): void
442+ {
443+ $ types = Database::get ()->fetchCol (
444+ (new Select ())
445+ ->from ('available_channel_type ' )
446+ ->columns (1 )
447+ ->where (['type IN (?) ' => $ addressTypes ])
448+ );
449+
450+ if (count ($ types ) !== count ($ addressTypes )) {
451+ $ this ->httpBadRequest ('An undefined address type given ' );
452+ }
453+ }
454+
455+ /**
456+ * Add the groups to the given contact
457+ *
458+ * @param int $contactId
459+ * @param array $groups
460+ *
461+ * @return void
462+ */
463+ private function addGroups (int $ contactId , array $ groups ): void
464+ {
465+ foreach ($ groups as $ groupIdentifier ) {
466+ $ groupId = $ this ->getGroupId ($ groupIdentifier );
467+
468+ Database::get ()->insert ('contactgroup_member ' , [
469+ 'contact_id ' => $ contactId ,
470+ 'contactgroup_id ' => $ groupId
471+ ]);
472+ }
473+ }
474+
475+ /**
476+ * Add the addresses to the given contact
477+ *
478+ * @param int $contactId
479+ * @param array $addresses
480+ *
481+ * @return void
482+ */
483+ private function addAddresses (int $ contactId , array $ addresses ): void
484+ {
485+ $ this ->assertAddressTypesExist (array_keys ($ addresses ));
486+
487+ foreach ($ addresses as $ type => $ address ) {
488+ //TODO: Check if type exists, db allows any type
489+ Database::get ()->insert ('contact_address ' , [
490+ 'contact_id ' => $ contactId ,
491+ 'type ' => $ type ,
492+ 'address ' => $ address
493+ ]);
422494 }
423495 }
424496
425497 /**
426498 * Remove the contact with the given id
427499 *
428500 * @param int $id
501+ *
502+ * @return void
429503 */
430504 private function removeContact (int $ id ): void
431505 {
@@ -441,6 +515,8 @@ private function removeContact(int $id): void
441515 *
442516 * @param array $data
443517 *
518+ * @return void
519+ *
444520 * @throws HttpBadRequestException
445521 */
446522 private function assertValidData (array $ data ): void
0 commit comments