-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,350 @@ | ||
<?php | ||
|
||
/* Icinga Notifications Web | (c) 2024 Icinga GmbH | GPLv2 */ | ||
|
||
namespace Icinga\Module\Notifications\Controllers; | ||
|
||
use Icinga\Exception\Http\HttpBadRequestException; | ||
use Icinga\Exception\Http\HttpException; | ||
use Icinga\Module\Notifications\Common\Database; | ||
use Icinga\Util\Environment; | ||
use Icinga\Util\Json; | ||
use ipl\Sql\Compat\FilterProcessor; | ||
use ipl\Sql\Select; | ||
use ipl\Web\Compat\CompatController; | ||
use ipl\Web\Filter\QueryString; | ||
use ipl\Web\Url; | ||
|
||
class ApiV1ContactgroupsController extends CompatController | ||
{ | ||
private const ENDPOINT = 'notifications/api/v1/contactgroups'; | ||
|
||
/** | ||
* @return void | ||
*/ | ||
public function indexAction(): void | ||
{ | ||
$this->assertPermission('notifications/api/v1'); | ||
|
||
$request = $this->getRequest(); | ||
if (! $request->isApiRequest()) { | ||
$this->httpBadRequest('No API request'); | ||
} | ||
|
||
$method = $request->getMethod(); | ||
if (in_array($method, ['POST', 'PUT']) | ||
&& (! preg_match('/([^;]*);?/', $request->getHeader('Content-Type'), $matches) | ||
Check failure on line 36 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 36 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 36 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 36 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 36 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 36 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
|| $matches[1] !== 'application/json' | ||
) | ||
) { | ||
$this->httpBadRequest('No JSON content'); | ||
} | ||
|
||
$results = []; | ||
$responseCode = 200; | ||
$db = Database::get(); | ||
$identifier = $request->getParam('identifier'); | ||
// TODO: Remove rawurldecode(). Only added to test, bcz phpstorm's http client encodes the params | ||
$queryString = rawurldecode(Url::fromRequest()->getQueryString()); | ||
$filter = FilterProcessor::assembleFilter(QueryString::parse($queryString)); | ||
|
||
switch ($method) { | ||
case 'GET': | ||
$stmt = (new Select()) | ||
->distinct() | ||
->from('contactgroup cg') | ||
->columns([ | ||
'contactgroup_id' => 'cg.id', | ||
'id' => 'cg.external_uuid', | ||
'name' | ||
]); | ||
|
||
if ($identifier !== null) { | ||
$stmt->where(['external_uuid = ?' => $identifier]); | ||
$result = $db->fetchOne($stmt); | ||
|
||
if ($result === false) { | ||
$this->httpNotFound('Contactgroup not found'); | ||
} | ||
|
||
$users = $this->fetchUserIdentifiers($result->contactgroup_id); | ||
Check failure on line 70 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 70 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 70 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 70 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 70 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 70 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
if ($users) { | ||
$result->users = $users; | ||
Check failure on line 72 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 72 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 72 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 72 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 72 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 72 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
} | ||
|
||
unset($result->contactgroup_id); | ||
Check failure on line 75 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 75 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 75 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 75 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 75 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 75 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
$results[] = $result; | ||
|
||
break; | ||
} | ||
|
||
if ($filter !== null) { | ||
$stmt->where($filter); | ||
} | ||
|
||
$stmt->limit(500); | ||
$offset = 0; | ||
|
||
ob_end_clean(); | ||
Environment::raiseExecutionTime(); | ||
|
||
$this->getResponse() | ||
->setHeader('Content-Type', 'application/json') | ||
->setHeader('Cache-Control', 'no-store') | ||
->sendResponse(); | ||
|
||
echo '['; | ||
|
||
$res = $db->select($stmt->offset($offset)); | ||
do { | ||
foreach ($res as $i => $row) { | ||
$users = $this->fetchUserIdentifiers($row->contactgroup_id); | ||
Check failure on line 101 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 101 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 101 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 101 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 101 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 101 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
if ($users) { | ||
$row->users = $users; | ||
Check failure on line 103 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 103 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 103 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 103 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 103 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 103 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
} | ||
|
||
if ($i > 0 || $offset !== 0) { | ||
echo ",\n"; | ||
} | ||
|
||
unset($row->contactgroup_id); | ||
Check failure on line 110 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 110 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 110 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 110 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 110 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 110 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
|
||
|
||
echo Json::sanitize($row); | ||
} | ||
|
||
$offset += 500; | ||
$res = $db->select($stmt->offset($offset)); | ||
} while ($res->rowCount()); | ||
|
||
echo ']'; | ||
|
||
exit; | ||
case 'POST': | ||
if ($filter !== null) { | ||
$this->httpBadRequest('Cannot filter on POST'); | ||
} | ||
|
||
$data = $request->getPost(); | ||
|
||
$this->assertValidData($data); | ||
|
||
$db->beginTransaction(); | ||
|
||
if ($identifier === null) { | ||
$identifier = $data['id']; | ||
|
||
if ($this->getContactgroupId($identifier) !== null) { | ||
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
Check failure on line 136 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.0 on ubuntu-latest
|
||
throw new HttpException('422', 'Contactgroup already exists'); | ||
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
Check failure on line 137 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.0 on ubuntu-latest
|
||
} | ||
|
||
$this->addContactgroup($data); | ||
} else { | ||
$contactgroupId = $this->getContactgroupId($identifier); | ||
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.2 on ubuntu-latest
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.1 on ubuntu-latest
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.3 on ubuntu-latest
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.4 on ubuntu-latest
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest
Check failure on line 142 in application/controllers/ApiV1ContactgroupsController.php GitHub Actions / phpstan / Static analysis with phpstan and php 8.0 on ubuntu-latest
|
||
if ($contactgroupId === null) { | ||
$this->httpNotFound('Contactgroup not found'); | ||
} | ||
|
||
if ($identifier === $data['id']) { | ||
throw new HttpException('422', 'Contactgroup already exists'); | ||
} | ||
|
||
$identifier = $data['id']; | ||
$this->removeContactgroup($contactgroupId); | ||
$this->addContactgroup($data); | ||
} | ||
|
||
$db->commitTransaction(); | ||
|
||
$this->getResponse()->setHeader('Location', self::ENDPOINT . '/' . $identifier); | ||
$responseCode = 201; | ||
|
||
break; | ||
case 'PUT': | ||
if ($identifier === null) { | ||
$this->httpBadRequest('Identifier is required'); | ||
} | ||
|
||
$data = $request->getPost(); | ||
|
||
$this->assertValidData($data); | ||
|
||
if ($identifier !== $data['id']) { | ||
$this->httpBadRequest('Identifier mismatch'); | ||
} | ||
|
||
$db->beginTransaction(); | ||
|
||
$contactgroupId = $this->getContactgroupId($identifier); | ||
if ($contactgroupId !== null) { | ||
$db->update('contactgroup', [ | ||
'name' => $data['name'], | ||
], ['id = ?' => $contactgroupId]); | ||
|
||
$db->delete('contactgroup_member', ['contactgroup_id = ?' => $identifier]); | ||
|
||
if (! empty($data['users'])) { | ||
$this->assertUsersExist($data['users']); | ||
|
||
foreach ($data['users'] as $userId) { | ||
$db->insert('contactgroup_member', [ | ||
'contactgroup_id' => $identifier, | ||
'contact_id' => $userId | ||
]); | ||
} | ||
} | ||
|
||
$responseCode = 204; | ||
} else { | ||
$this->addContactgroup($data); | ||
$responseCode = 201; | ||
} | ||
|
||
$db->commitTransaction(); | ||
|
||
break; | ||
case 'DELETE': | ||
if ($identifier === null) { | ||
$this->httpBadRequest('Identifier is required'); | ||
} | ||
|
||
$db->beginTransaction(); | ||
|
||
$contactgroupId = $this->getContactgroupId($identifier); | ||
if ($contactgroupId === null) { | ||
$this->httpNotFound('Contactgroup not found'); | ||
} | ||
|
||
$this->removeContactgroup($contactgroupId); | ||
|
||
$db->commitTransaction(); | ||
|
||
$responseCode = 204; | ||
|
||
break; | ||
default: | ||
$this->httpBadRequest('Invalid method'); | ||
} | ||
|
||
$this->getResponse() | ||
->setHttpResponseCode($responseCode) | ||
->json() | ||
->setSuccessData($results) | ||
->sendResponse(); | ||
} | ||
|
||
/** | ||
* Fetch the user(contact) identifiers of the contactgroup with the given id | ||
* | ||
* @param int $contactgroupId | ||
* | ||
* @return ?string[] | ||
*/ | ||
private function fetchUserIdentifiers(int $contactgroupId): ?array | ||
{ | ||
$users = Database::get()->fetchCol( | ||
(new Select()) | ||
->from('contactgroup_member cgm') | ||
->columns('co.external_uuid') | ||
->joinLeft('contact co', 'co.id = cgm.contact_id') | ||
->where(['cgm.contactgroup_id = ?' => $contactgroupId]) | ||
->groupBy('co.external_uuid') | ||
); | ||
|
||
return ! empty($users) ? $users : null; | ||
} | ||
|
||
/** | ||
* Assert that the given user IDs exist | ||
* | ||
* @param array $userIds | ||
* | ||
* @throws HttpException if a group does not exist | ||
*/ | ||
private function assertUsersExist(array $userIds): void | ||
{ | ||
$existingUserIds = Database::get()->fetchCol( | ||
(new Select()) | ||
->from('contact') | ||
->columns('id') | ||
->where(['id IN (?)' => $userIds]) | ||
); | ||
|
||
if (count($existingUserIds) !== count($userIds)) { | ||
throw new HttpException('404', 'Undefined user identifier given'); | ||
} | ||
} | ||
|
||
/** | ||
* Get the contactgroup id with the given identifier | ||
* | ||
* @param string $identifier | ||
* | ||
* @return ?int Returns null, if contact does not exist | ||
*/ | ||
private function getContactgroupId(string $identifier): ?int | ||
{ | ||
$contactgroup = Database::get()->fetchOne( | ||
(new Select()) | ||
->from('contactgroup') | ||
->columns('id') | ||
->where(['external_uuid = ?' => $identifier]) | ||
); | ||
|
||
return $contactgroup->id ?? null; | ||
} | ||
|
||
/** | ||
* Add a new contactgroup with the given data | ||
* | ||
* @param array $data | ||
* | ||
* @throws HttpException if a user does not exist | ||
*/ | ||
private function addContactgroup(array $data): void | ||
{ | ||
$db = Database::get(); | ||
$db->insert('contactgroup', [ | ||
'name' => $data['name'], | ||
'external_uuid' => $data['id'] | ||
]); | ||
|
||
$id = $db->lastInsertId(); | ||
|
||
if (! empty($data['users'])) { | ||
$this->assertUsersExist($data['users']); | ||
foreach ($data['users'] as $contactId) { | ||
$db->insert('contactgroup_member', [ | ||
'contactgroup_id' => $id, | ||
'contact_id' => $contactId | ||
]); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Remove the contactgroup with the given id | ||
* | ||
* @param int $id | ||
*/ | ||
private function removeContactgroup(int $id): void | ||
{ | ||
$db = Database::get(); | ||
|
||
$db->delete('contactgroup_member', ['contactgroup_id = ?' => $id]); | ||
$db->delete('contactgroup', ['id = ?' => $id]); | ||
} | ||
|
||
/** | ||
* Assert that the given data contains the required fields | ||
* | ||
* @param array $data | ||
* | ||
* @throws HttpBadRequestException | ||
*/ | ||
private function assertValidData(array $data): void | ||
{ | ||
if (! isset($data['id'], $data['name'])) { | ||
$this->httpBadRequest('missing required fields'); | ||
} | ||
} | ||
} |