Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.44% covered (success)
97.44%
152 / 156
76.92% covered (warning)
76.92%
10 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Search
97.44% covered (success)
97.44%
152 / 156
76.92% covered (warning)
76.92%
10 / 13
57
0.00% covered (danger)
0.00%
0 / 1
 readResponse
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
2
 readSearchParameters
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
12
 readProcessSearchResults
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 shouldRunProcessSearch
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 hasStructuredSearchFilters
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 shouldRunLogSearch
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 hasLogSearchFilters
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 buildProcessSearchParameters
88.24% covered (warning)
88.24%
15 / 17
0.00% covered (danger)
0.00%
0 / 1
6.06
 readLogSearchResults
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
3
 filterProcessListForUserRights
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 filterLogListForUserRights
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
7.07
 readStringParameter
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 readNumberParameter
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * @package Zmsadmin
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsadmin;
9
10use BO\Slim\Render;
11use BO\Zmsentities\Collection\LogList;
12use BO\Zmsentities\Log as LogEntity;
13use BO\Zmsentities\Collection\ProcessList;
14
15class Search extends BaseController
16{
17    private const int DEFAULT_RESULTS_PER_PAGE = 100;
18
19    private const int MAX_RESULTS_PER_PAGE = 1000;
20
21    /**
22     * @SuppressWarnings(Param)
23     * @return \Psr\Http\Message\ResponseInterface
24     */
25    #[\Override]
26    public function readResponse(
27        \Psr\Http\Message\RequestInterface $request,
28        \Psr\Http\Message\ResponseInterface $response,
29        array $args
30    ): \Psr\Http\Message\ResponseInterface {
31        $workstation = \App::$http->readGetResult('/workstation/', ['resolveReferences' => 2])->getEntity();
32        $parameters = $this->readSearchParameters($request->getAttribute('validator'));
33        if ($workstation->getUseraccount()->hasRole('audit_viewer')) {
34            $parameters['hideNavigation'] = 1;
35        }
36        $scopeIds = $workstation->getUseraccount()->getDepartmentList()->getUniqueScopeList()->getIds();
37
38        [$processList, $processSearchTotal] = $this->readProcessSearchResults(
39            $workstation,
40            $parameters,
41            $scopeIds
42        );
43        $logList = $this->readLogSearchResults($workstation, $parameters, $scopeIds);
44
45        return Render::withHtml(
46            $response,
47            'page/search.twig',
48            array(
49                'title' => 'Suche',
50                'hideNavigation' => (bool) $parameters['hideNavigation'],
51                'service' => $parameters['service'],
52                'provider' => $parameters['provider'],
53                'userAction' => $parameters['userAction'],
54                'date' => $parameters['date'],
55                'page' => $parameters['page'],
56                'perPage' => $parameters['perPage'],
57                'workstation' => $workstation,
58                'processList' => $processList,
59                'logList' => $logList ?? [],
60                'searchProcessQuery' => $parameters['queryString'],
61                'processSearchTotal' => $processSearchTotal,
62                'menuActive' => 'search'
63            )
64        );
65    }
66
67    private function readSearchParameters($validator): array
68    {
69        $queryString = $validator->getParameter('query')
70            ->isString('', false)
71            ->getValue();
72        if ($queryString !== null && $queryString !== '') {
73            $queryString = html_entity_decode((string) $queryString, ENT_QUOTES | ENT_HTML5, 'UTF-8');
74        } else {
75            $queryString = $queryString ?? '';
76        }
77
78        $service = $this->readStringParameter($validator, 'service');
79        $provider = $this->readStringParameter($validator, 'provider');
80        $date = $validator->getParameter('date')->isString()->setDefault(null)->getValue();
81        $page = $this->readNumberParameter($validator, 'page', 1);
82        $userAction = $this->readNumberParameter($validator, 'user', 0);
83        $requestedResultsPerPage = $this->readNumberParameter($validator, 'perPage', self::DEFAULT_RESULTS_PER_PAGE);
84        $resultsPerPage = min($requestedResultsPerPage, self::MAX_RESULTS_PER_PAGE);
85        $hideNavigation = $this->readNumberParameter($validator, 'hideNavigation', 0);
86
87        return [
88            'queryString' => $queryString,
89            'page' => $page,
90            'service' => $service ? trim($service) : null,
91            'provider' => $provider ? trim($provider) : null,
92            'date' => $date !== null && trim($date) !== '' ? trim($date) : null,
93            'userAction' => $userAction,
94            'perPage' => $resultsPerPage,
95            'hideNavigation' => $hideNavigation,
96            'isSearchRequested' => (
97                trim($queryString) !== ''
98                || trim($service) !== ''
99                || trim($provider) !== ''
100                || ($date !== null && trim($date) !== '')
101                || $userAction !== 0
102            ),
103        ];
104    }
105
106    private function readProcessSearchResults($workstation, array $parameters, array $scopeIds): array
107    {
108        if (!$this->shouldRunProcessSearch($workstation, $parameters)) {
109            return [new ProcessList(), 0];
110        }
111
112        $searchParameters = $this->buildProcessSearchParameters($workstation, $parameters, $scopeIds);
113        $searchResult = \App::$http->readGetResult('/process/search/', $searchParameters);
114        $processList = $searchResult->getCollection();
115        $searchMeta = $searchResult->getMeta();
116        $processSearchTotal = isset($searchMeta->totalCount)
117            ? (int) $searchMeta->totalCount
118            : $processList->count();
119
120        if (!empty($processList) && !$workstation->getUseraccount()->isSuperUser()) {
121            $processList = $this->filterProcessListForUserRights($processList, $scopeIds);
122        }
123
124        return [$processList, $processSearchTotal];
125    }
126
127    private function shouldRunProcessSearch($workstation, array $parameters): bool
128    {
129        if (!$parameters['isSearchRequested']) {
130            return false;
131        }
132
133        if (!$workstation->getUseraccount()->hasPermissions(['customersearch'])) {
134            return false;
135        }
136
137        $queryString = trim((string) $parameters['queryString']);
138
139        return $queryString !== '' || $this->hasStructuredSearchFilters($parameters);
140    }
141
142    private function hasStructuredSearchFilters(array $parameters): bool
143    {
144        return $parameters['service'] !== null
145            || $parameters['provider'] !== null
146            || $parameters['date'] !== null;
147    }
148
149    private function shouldRunLogSearch($workstation, array $parameters): bool
150    {
151        if (!$workstation->getUseraccount()->hasPermissions(['logs'])) {
152            return false;
153        }
154
155        if ($this->hasLogSearchFilters($parameters)) {
156            return true;
157        }
158
159        return $workstation->getUseraccount()->isSuperUser()
160            && !$parameters['isSearchRequested'];
161    }
162
163    private function hasLogSearchFilters(array $parameters): bool
164    {
165        return trim((string) $parameters['queryString']) !== ''
166            || $parameters['service'] !== null
167            || $parameters['provider'] !== null
168            || $parameters['date'] !== null
169            || $parameters['userAction'] !== 0;
170    }
171
172    private function buildProcessSearchParameters($workstation, array $parameters, array $scopeIds): array
173    {
174        $queryString = trim((string) $parameters['queryString']);
175        $searchParameters = [
176            'resolveReferences' => 1,
177            'page' => $parameters['page'],
178            'limit' => $parameters['perPage'],
179        ];
180        if ($queryString !== '') {
181            $searchParameters['query'] = $queryString;
182        }
183        if ($parameters['service'] !== null) {
184            $searchParameters['service'] = $parameters['service'];
185        }
186        if ($parameters['provider'] !== null) {
187            $searchParameters['provider'] = $parameters['provider'];
188        }
189        if ($parameters['date'] !== null) {
190            $searchParameters['date'] = $parameters['date'];
191        }
192        if (!$workstation->getUseraccount()->isSuperUser()) {
193            $searchParameters['scopeIds'] = implode(',', $scopeIds);
194        }
195
196        return $searchParameters;
197    }
198
199    private function readLogSearchResults($workstation, array $parameters, array $scopeIds): ?LogList
200    {
201        if (!$this->shouldRunLogSearch($workstation, $parameters)) {
202            return null;
203        }
204
205        $logParameters = [
206            'searchQuery' => urlencode((string) $parameters['queryString']),
207            'page' => $parameters['page'],
208            'perPage' => $parameters['perPage'],
209            'service' => $parameters['service'],
210            'provider' => $parameters['provider'],
211            'userAction' => $parameters['userAction'],
212            'date' => $parameters['date'],
213        ];
214        if (!$workstation->getUseraccount()->isSuperUser()) {
215            $logParameters['scopeIds'] = implode(',', $scopeIds);
216        }
217
218        $logList = \App::$http
219            ->readGetResult("/log/process/", $logParameters)
220            ->getCollection();
221
222        return $this->filterLogListForUserRights(
223            $logList,
224            $scopeIds,
225            $workstation->getUseraccount()->isSuperUser()
226        );
227    }
228
229    private function filterProcessListForUserRights(?ProcessList $processList, array $scopeIds): ProcessList
230    {
231        if (empty($processList)) {
232            return new ProcessList();
233        }
234
235        $list = new ProcessList();
236
237        foreach ($processList as $process) {
238            if (in_array($process->scope->id, $scopeIds)) {
239                $list->addEntity(clone $process);
240            }
241        }
242
243        return $list;
244    }
245
246    private function filterLogListForUserRights(
247        ?LogList $logList,
248        array $scopeIds,
249        bool $bypassScopeFilter = false
250    ): LogList {
251        if (!isset($logList) || !$logList) {
252            $logList = new LogList();
253        }
254
255        $list = new LogList();
256
257        foreach ($logList as $log) {
258            $log->display = LogEntity::formatDisplayFields($log->getArrayCopy());
259
260            if (
261                $bypassScopeFilter
262                || (isset($log->scope_id) && in_array($log->scope_id, $scopeIds))
263            ) {
264                $list->addEntity(clone $log);
265            }
266        }
267
268        return $list;
269    }
270
271    private function readStringParameter($validator, string $name, string $default = ''): string
272    {
273        return $validator->getParameter($name)
274            ->isString()
275            ->setDefault($default)
276            ->getValue() ?? $default;
277    }
278
279    private function readNumberParameter($validator, string $name, int $default): int
280    {
281        return (int) $validator->getParameter($name)
282            ->isNumber()
283            ->setDefault($default)
284            ->getValue();
285    }
286}