44
55use Exception ;
66use Generator ;
7- use GuzzleHttp \Psr7 \Response ;
87use Icinga \Exception \Http \HttpBadRequestException ;
98use Icinga \Exception \Http \HttpException ;
109use Icinga \Exception \Json \JsonDecodeException ;
1110use Icinga \Exception \Json \JsonEncodeException ;
1211use Icinga \Module \Notifications \Api \ApiCore ;
1312use Icinga \Module \Notifications \Api \Elements \HttpMethod ;
14- use Icinga \Module \Notifications \Common \Database ;
1513use Icinga \Util \Json ;
1614use ipl \Sql \Compat \FilterProcessor ;
1715use ipl \Sql \Connection ;
2220use Psr \Http \Message \ServerRequestInterface ;
2321use OpenApi \Attributes as OA ;
2422use Ramsey \Uuid \Uuid ;
25- use Psr \Http \Server \RequestHandlerInterface ;
2623use stdClass ;
27- use ValueError ;
2824
2925/**
3026 * Base class for API version 1.
7167abstract class ApiV1 extends ApiCore
7268{
7369 /**
74- * API version.
75- *
7670 * This constant defines the version of the API.
7771 *
7872 * @var string
@@ -84,10 +78,12 @@ abstract class ApiV1 extends ApiCore
8478 *
8579 * This method processes the incoming request, determines the appropriate method to call
8680 * based on the HTTP method and presence of an identifier, and invokes that method.
87- * It also handles validation of the identifier and request body for POST and PUT requests.
81+ * It also handles validation of the request body for POST and PUT requests.
8882 *
8983 * @param ServerRequestInterface $request The incoming server request.
84+ *
9085 * @return ResponseInterface The response generated by the invoked method.
86+ *
9187 * @throws HttpBadRequestException If the request is not valid.
9288 * @throws HttpException If the requested method does not exist.
9389 */
@@ -107,6 +103,17 @@ public function handleRequest(ServerRequestInterface $request): ResponseInterfac
107103 return $ this ->createResponse (...$ responseData );
108104 }
109105
106+ /**
107+ * Validate the incoming request.
108+ *
109+ * This method checks the validity of the request based on the HTTP method,
110+ * presence of an identifier, and query parameters. It throws an HttpBadRequestException
111+ * if any validation fails.
112+ *
113+ * @param ServerRequestInterface $request The request object to validate.
114+ *
115+ * @throws HttpBadRequestException If the request is not valid.
116+ */
110117 protected function assertValidRequest (ServerRequestInterface $ request ): void
111118 {
112119 $ httpMethod = $ request ->getAttribute ('httpMethod ' );
@@ -139,61 +146,61 @@ protected function assertValidRequest(ServerRequestInterface $request): void
139146 }
140147 }
141148
142-
143- //TODO: decide if these following functions should be versioned or moved to ApiCore
144-
145149 /**
146150 * Create a filter from the filter string.
147151 *
148- * This method parses the filter string and returns an array of filter rules.
149- * If the filter string is empty, it returns false.
152+ * @param string $filterStr
153+ * @param array $allowedColumns
154+ * @param string $idColumnName
150155 *
151- * @param callable $listener A listener function to handle conditions in the query string.
152156 * @return array|bool Returns an array of filter rules or false if no filter string is provided.
157+ *
153158 * @throws HttpBadRequestException If the filter string cannot be parsed.
154159 */
155160 protected function assembleFilter (string $ filterStr , array $ allowedColumns , string $ idColumnName ): array |bool
156161 {
157- if (! empty ($ filterStr )) {
158- try {
159- $ filterRule = QueryString::fromString ($ filterStr )
160- ->on (
161- QueryString::ON_CONDITION ,
162- function (Condition $ condition ) use ($ allowedColumns , $ idColumnName ) {
163- $ column = $ condition ->getColumn ();
164- if (! in_array ($ column , $ allowedColumns )) {
165- throw new HttpBadRequestException (
166- sprintf (
167- 'Invalid request parameter: Filter column %s given, only %s are allowed ' ,
168- $ column ,
169- preg_replace ('/,([^,]*)$/ ' , ' and$1 ' , implode (', ' , $ allowedColumns ))
170- )
171- );
172- }
173-
174- if ($ column === 'id ' ) {
175- if (! Uuid::isValid ($ condition ->getValue ())) {
176- throw new HttpBadRequestException ('The given filter id is not a valid UUID ' );
177- }
162+ if (empty ($ filterStr )) {
163+ return false ;
164+ }
165+ try {
166+ $ filterRule = QueryString::fromString ($ filterStr )
167+ ->on (
168+ QueryString::ON_CONDITION ,
169+ function (Condition $ condition ) use ($ allowedColumns , $ idColumnName ) {
170+ $ column = $ condition ->getColumn ();
171+ if (! in_array ($ column , $ allowedColumns )) {
172+ throw new HttpBadRequestException (
173+ sprintf (
174+ 'Invalid request parameter: Filter column %s given, only %s are allowed ' ,
175+ $ column ,
176+ preg_replace ('/,([^,]*)$/ ' , ' and$1 ' , implode (', ' , $ allowedColumns ))
177+ )
178+ );
179+ }
178180
179- $ condition ->setColumn ($ idColumnName );
181+ if ($ column === 'id ' ) {
182+ if (! Uuid::isValid ($ condition ->getValue ())) {
183+ throw new HttpBadRequestException ('The given filter id is not a valid UUID ' );
180184 }
185+
186+ $ condition ->setColumn ($ idColumnName );
181187 }
182- )->parse ();
188+ }
189+ )->parse ();
183190
184- return FilterProcessor::assembleFilter ($ filterRule );
185- } catch (Exception $ e ) {
186- throw new HttpBadRequestException ($ e ->getMessage ());
187- }
191+ return FilterProcessor::assembleFilter ($ filterRule );
192+ } catch (Exception $ e ) {
193+ throw new HttpBadRequestException ($ e ->getMessage ());
188194 }
189- return false ;
190195 }
191196
192197 /**
193198 * Validate that the request has a JSON content type and return the parsed JSON content.
194199 *
195200 * @param ServerRequestInterface $request The request object to validate.
201+ *
196202 * @return array The validated JSON content as an associative array.
203+ *
197204 * @throws HttpBadRequestException If the content type is not application/json.
198205 */
199206 private function getValidRequestBody (ServerRequestInterface $ request ): array
@@ -233,6 +240,7 @@ private function getValidRequestBody(ServerRequestInterface $request): array
233240 * @param int $batchSize The number of rows to fetch in each batch (default is 500).
234241 *
235242 * @return Generator Yields JSON-encoded strings representing the content.
243+ *
236244 * @throws JsonEncodeException
237245 */
238246 protected function createContentGenerator (
0 commit comments