Skip to content

Commit 76e2d45

Browse files
wip
1 parent 33e7304 commit 76e2d45

File tree

2 files changed

+735
-0
lines changed

2 files changed

+735
-0
lines changed
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
<?php
2+
3+
/* Icinga Notifications Web | (c) 2024 Icinga GmbH | GPLv2 */
4+
5+
namespace Icinga\Module\Notifications\Controllers;
6+
7+
use Icinga\Exception\Http\HttpException;
8+
use Icinga\Module\Notifications\Common\Database;
9+
use Icinga\Util\Environment;
10+
use Icinga\Util\Json;
11+
use ipl\Sql\Compat\FilterProcessor;
12+
use ipl\Sql\Select;
13+
use ipl\Web\Compat\CompatController;
14+
use ipl\Web\Filter\QueryString;
15+
use ipl\Web\Url;
16+
17+
class ApiV1ContactgroupsController extends CompatController
18+
{
19+
/**
20+
* @return void
21+
*/
22+
public function indexAction(): void
23+
{
24+
$this->assertPermission('notifications/api/v1');
25+
26+
$request = $this->getRequest();
27+
if (! $request->isApiRequest()) {
28+
$this->httpBadRequest('No API request');
29+
}
30+
31+
$method = $request->getMethod();
32+
if (in_array($method, ['POST', 'PUT'])
33+
&& (! preg_match('/([^;]*);?/', $request->getHeader('Content-Type'), $matches)
34+
|| $matches[1] !== 'application/json'
35+
)
36+
) {
37+
$this->httpBadRequest('No JSON content');
38+
}
39+
40+
$results = [];
41+
$responseCode = 200;
42+
$db = Database::get();
43+
$identifier = $request->getParam('identifier');
44+
// TODO: Remove rawurldecode(). Only added to test, bcz phpstorm's http client encodes the params
45+
$queryString = rawurldecode(Url::fromRequest()->getQueryString());
46+
$filter = FilterProcessor::assembleFilter(QueryString::parse($queryString));
47+
48+
switch ($method) {
49+
case 'GET':
50+
$stmt = (new Select())
51+
->distinct()
52+
->from('contactgroup cg')
53+
->columns([
54+
'contactgroup_id' => 'cg.id',
55+
'id' => 'cg.external_uuid',
56+
'name'
57+
]);
58+
59+
if ($identifier !== null) {
60+
$stmt->where(['external_uuid = ?' => $identifier]);
61+
$result = $db->fetchOne($stmt);
62+
63+
$users = $db->fetchCol(
64+
(new Select())
65+
->from('contactgroup_member')
66+
->columns(['contact_id'])
67+
->where(['contactgroup_id = ?' => $result->contactgroup_id])
68+
);
69+
70+
if (! empty($users)) {
71+
$result->users = $users;
72+
}
73+
74+
unset($result->contactgroup_id);
75+
$results[] = $result;
76+
77+
break;
78+
}
79+
80+
if ($filter !== null) {
81+
$stmt->where($filter);
82+
}
83+
84+
$stmt->limit(500);
85+
$offset = 0;
86+
87+
ob_end_clean();
88+
Environment::raiseExecutionTime();
89+
90+
$this->getResponse()
91+
->setHeader('Content-Type', 'application/json')
92+
->setHeader('Cache-Control', 'no-store')
93+
->sendResponse();
94+
95+
echo '[';
96+
97+
$results = $db->select($stmt->offset($offset));
98+
do {
99+
foreach ($results as $i => $row) {
100+
$users = $db->fetchCol(
101+
(new Select())
102+
->from('contactgroup_member')
103+
->columns(['contact_id'])
104+
->where(['contactgroup_id = ?' => $row->contactgroup_id])
105+
);
106+
107+
if (! empty($users)) {
108+
$row->users = $users;
109+
}
110+
111+
if ($i > 0 || $offset !== 0) {
112+
echo ",\n";
113+
}
114+
115+
unset($row->contactgroup_id);
116+
117+
echo Json::sanitize($row);
118+
}
119+
120+
$offset += 500;
121+
$results = $db->select($stmt->offset($offset));
122+
} while ($results->rowCount());
123+
124+
echo ']';
125+
126+
exit;
127+
case 'POST':
128+
if ($filter !== null) {
129+
$this->httpBadRequest('Cannot filter on POST');
130+
}
131+
132+
$data = $request->getPost();
133+
134+
if (! isset($data['id'], $data['name'])) {
135+
$this->httpBadRequest('missing required fields');
136+
}
137+
138+
$db->beginTransaction();
139+
if ($identifier === null) {
140+
$identifier = $data['id'];
141+
142+
if ($this->getContactgroupId($identifier) !== null) {
143+
throw new HttpException('422', 'Contactgroup already exists');
144+
}
145+
146+
$this->addContactgroup($data);
147+
} else {
148+
$contactgroupId = $this->getContactgroupId($identifier);
149+
if ($contactgroupId === null) {
150+
$this->httpNotFound('Contactgroup not found');
151+
}
152+
153+
if ($identifier === $data['id']) {
154+
throw new HttpException('422', 'Contactgroup already exists');
155+
}
156+
157+
$identifier = $data['id'];
158+
$this->removeContactgroup($contactgroupId);
159+
$this->addContactgroup($data);
160+
}
161+
162+
$db->commitTransaction();
163+
164+
$this->getResponse()->setHeader('Location', 'notifications/api/v1/contactgroups/' . $identifier);
165+
$responseCode = 201;
166+
167+
break;
168+
case 'PUT':
169+
if ($identifier === null) {
170+
$this->httpBadRequest('Identifier is required');
171+
}
172+
173+
$data = $request->getPost();
174+
175+
if (! isset($data['id'], $data['name'])) {
176+
$this->httpBadRequest('missing required fields');
177+
}
178+
179+
if ($identifier !== $data['id']) {
180+
$this->httpBadRequest('Identifier mismatch');
181+
}
182+
183+
$db->beginTransaction();
184+
$contactgroupId = $this->getContactgroupId($identifier);
185+
if ($contactgroupId !== null) {
186+
$db->update('contactgroup', [
187+
'name' => $data['name'],
188+
], ['id = ?' => $identifier]);
189+
190+
if (! empty($data['users'])) {
191+
$db->delete('contactgroup_member', ['contactgroup_id = ?' => $identifier]);
192+
193+
$this->assertUsersExist($data['users']);
194+
195+
foreach ($data['users'] as $userId) {
196+
$db->insert('contactgroup_member', [
197+
'contactgroup_id' => $identifier,
198+
'contact_id' => $userId
199+
]);
200+
}
201+
}
202+
203+
$responseCode = 204;
204+
} else {
205+
$this->addContactgroup($data);
206+
$responseCode = 201;
207+
}
208+
209+
$db->commitTransaction();
210+
211+
break;
212+
case 'DELETE':
213+
if ($identifier === null) {
214+
$this->httpBadRequest('Identifier is required');
215+
}
216+
217+
$db->beginTransaction();
218+
219+
$contactgroupId = $this->getContactgroupId($identifier);
220+
if ($contactgroupId === null) {
221+
$this->httpNotFound('Contactgroup not found');
222+
}
223+
224+
$this->removeContactgroup($contactgroupId);
225+
226+
$db->commitTransaction();
227+
228+
$responseCode = 204;
229+
230+
break;
231+
default:
232+
$this->httpBadRequest('Invalid method');
233+
}
234+
235+
$this->getResponse()
236+
->setHttpResponseCode($responseCode)
237+
->json()
238+
->setSuccessData($results)
239+
->sendResponse();
240+
}
241+
242+
/**
243+
* Assert that the given user IDs exist
244+
*
245+
* @param array $userIds
246+
*
247+
* @throws HttpException if a group does not exist
248+
*/
249+
private function assertUsersExist(array $userIds): void
250+
{
251+
$existingUserIds = Database::get()->fetchCol(
252+
(new Select())
253+
->from('contact')
254+
->columns('id')
255+
->where(['id IN (?)' => $userIds])
256+
);
257+
258+
if (count($existingUserIds) !== count($userIds)) {
259+
throw new HttpException('404', 'Undefined user identifier given');
260+
}
261+
}
262+
263+
/**
264+
* Get the contactgroup id with the given identifier
265+
*
266+
* @param string $identifier
267+
*
268+
* @return ?int Returns null, if contact does not exist
269+
*/
270+
private function getContactgroupId(string $identifier): ?int
271+
{
272+
$contactgroup = Database::get()->fetchOne(
273+
(new Select())
274+
->from('contactgroup')
275+
->columns('id')
276+
->where(['external_uuid = ?' => $identifier])
277+
);
278+
279+
return $contactgroup->id ?? null;
280+
}
281+
282+
/**
283+
* Add a new contactgroup with the given data
284+
*
285+
* @param array $data
286+
*
287+
* @throws HttpException if a user does not exist
288+
*/
289+
private function addContactgroup(array $data): void
290+
{
291+
$db = Database::get();
292+
$db->insert('contactgroup', [
293+
'name' => $data['name'],
294+
'external_uuid' => $data['id']
295+
]);
296+
297+
$id = $db->lastInsertId();
298+
299+
if (! empty($data['users'])) {
300+
$this->assertUsersExist($data['users']);
301+
foreach ($data['users'] as $userId) {
302+
$db->insert('contactgroup_member', [
303+
'contactgroup_id' => $id,
304+
'contact_id' => $userId
305+
]);
306+
}
307+
}
308+
}
309+
310+
/**
311+
* Remove the contactgroup with the given id
312+
*
313+
* @param int $id
314+
*/
315+
private function removeContactgroup(int $id): void
316+
{
317+
$db = Database::get();
318+
319+
//$db->delete('schedule_member', ['contactgroup_id = ?' => $identifier]); // TODO: require in contactForm
320+
$db->delete('contactgroup_member', ['contactgroup_id = ?' => $id]);
321+
$db->delete('contactgroup', ['id = ?' => $id]);
322+
}
323+
}

0 commit comments

Comments
 (0)