Passed
Push — master ( 0b1a33...6372a5 )
by Marcel
06:49
created

ReportService::search()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * Analytics
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the LICENSE.md file.
7
 *
8
 * @author Marcel Scherello <[email protected]>
9
 * @copyright 2021 Marcel Scherello
10
 */
11
12
namespace OCA\Analytics\Service;
13
14
use OCA\Analytics\Activity\ActivityManager;
15
use OCA\Analytics\Controller\DatasourceController;
16
use OCA\Analytics\Db\DataloadMapper;
17
use OCA\Analytics\Db\ReportMapper;
18
use OCA\Analytics\Db\StorageMapper;
19
use OCP\AppFramework\Http\DataDownloadResponse;
20
use OCP\AppFramework\Http\DataResponse;
21
use OCP\Files\IRootFolder;
22
use OCP\ITagManager;
23
use Psr\Log\LoggerInterface;
24
25
class ReportService
26
{
27
    private $userId;
28
    private $logger;
29
    private $tagManager;
30
    private $ShareService;
31
    private $DatasetService;
32
    private $StorageMapper;
33
    private $ReportMapper;
34
    private $ThresholdService;
35
    private $DataloadMapper;
36
    private $ActivityManager;
37
    private $rootFolder;
38
    private $VariableService;
39
40
    public function __construct(
41
        $userId,
42
        LoggerInterface $logger,
43
        ITagManager $tagManager,
44
        ShareService $ShareService,
45
        DatasetService $DatasetService,
46
        StorageMapper $StorageMapper,
47
        ReportMapper $ReportMapper,
48
        ThresholdService $ThresholdService,
49
        DataloadMapper $DataloadMapper,
50
        ActivityManager $ActivityManager,
51
        IRootFolder $rootFolder,
52
        VariableService $VariableService
53
    )
54
    {
55
        $this->userId = $userId;
56
        $this->logger = $logger;
57
        $this->tagManager = $tagManager;
58
        $this->ShareService = $ShareService;
59
        $this->DatasetService = $DatasetService;
60
        $this->ThresholdService = $ThresholdService;
61
        $this->StorageMapper = $StorageMapper;
62
        $this->ReportMapper = $ReportMapper;
63
        $this->DataloadMapper = $DataloadMapper;
64
        $this->ActivityManager = $ActivityManager;
65
        $this->rootFolder = $rootFolder;
66
        $this->VariableService = $VariableService;
67
    }
68
69
    /**
70
     * get all reports
71
     *
72
     * @return DataResponse
73
     */
74
    public function index()
75
    {
76
        $ownReports = $this->ReportMapper->index();
77
78
        // get dataload indicators for icons shown in the advanced screen
79
        $dataloads = $this->DataloadMapper->getAllDataloadMetadata();
80
        foreach ($dataloads as $dataload) {
81
            $key = array_search($dataload['dataset'], array_column($ownReports, 'dataset'));
82
            if ($key !== '') {
83
                if ($dataload['schedules'] !== '' and $dataload['schedules'] !== null) {
84
                    $dataload['schedules'] = 1;
85
                } else {
86
                    $dataload['schedules'] = 0;
87
                }
88
                $ownReports[$key]['dataloads'] = $dataload['dataloads'];
89
                $ownReports[$key]['schedules'] = $dataload['schedules'];
90
            }
91
        }
92
93
        // get shared reports and remove doublicates
94
        $sharedReports = $this->ShareService->getSharedReports();
95
        foreach ($sharedReports as $sharedReport) {
96
            if (!array_search($sharedReport['id'], array_column($ownReports, 'id'))) {
97
                $sharedReport['type'] = '99';
98
                $sharedReport['parrent'] = '0';
99
                array_push($ownReports, $sharedReport);
100
            }
101
        }
102
103
        $favorites = $this->tagManager->load('analytics')->getFavorites();
104
        foreach ($ownReports as &$ownReport) {
105
            $hasTag = 0;
106
            if (is_array($favorites) and in_array($ownReport['id'], $favorites)) {
107
                $hasTag = 1;
108
            }
109
            $ownReport['favorite'] = $hasTag;
110
            $ownReport = $this->VariableService->replaceTextVariables($ownReport);
111
        }
112
113
        return new DataResponse($ownReports);
114
    }
115
116
    /**
117
     * get own report details
118
     *
119
     * @param int $reportId
120
     * @return array
121
     */
122
    public function read(int $reportId)
123
    {
124
        $ownReport = $this->ReportMapper->read($reportId);
125
        if (!empty($ownReport)) {
126
            $ownReport['permissions'] = \OCP\Constants::PERMISSION_UPDATE;
127
            $ownReport = $this->VariableService->replaceTextVariables($ownReport);
128
        }
129
        return $ownReport;
130
    }
131
132
    /**
133
     * get own reports which are marked as favorites
134
     *
135
     * @return array|bool
136
     */
137
    public function getOwnFavoriteReports()
138
    {
139
        $ownReports = $this->ReportMapper->index();
140
        $favorits = $this->tagManager->load('analytics')->getFavorites();
141
        $sharedReports = $this->ShareService->getSharedReports();
142
143
        foreach ($favorits as $favorite) {
144
            if (array_search($favorite, array_column($ownReports, 'id')) === false
145
                && array_search($favorite, array_column($sharedReports, 'id')) === false) {
146
                unset($favorits[$favorite]);
147
                $this->tagManager->load('analytics')->removeFromFavorites($favorite);
148
            }
149
        }
150
151
        return $favorits;
152
    }
153
154
    /**
155
     * create new blank report
156
     *
157
     * @return int
158
     */
159
    public function create(): int
160
    {
161
        $this->ActivityManager->triggerEvent(0, ActivityManager::OBJECT_DATASET, ActivityManager::SUBJECT_DATASET_ADD);
162
        return $this->ReportMapper->create();
163
    }
164
165
    /**
166
     * copy an existing report with the current navigation status
167
     *
168
     * @NoAdminRequired
169
     * @param int $reportId
170
     * @param $chartoptions
171
     * @param $dataoptions
172
     * @param $filteroptions
173
     * @return int
174
     */
175
    public function createCopy(int $reportId, $chartoptions, $dataoptions, $filteroptions)
176
    {
177
178
        $newId = $this->ReportMapper->create();
179
        $template = $this->ReportMapper->read($reportId);
180
        $this->ReportMapper->update($newId,
181
            $template['name'] . ' copy',
182
            $template['subheader'],
183
            $template['parent'],
184
            $template['type'],
185
            $template['dataset'],
186
            $template['link'],
187
            $template['visualization'],
188
            $template['chart'],
189
            $template['chartoptions'],
190
            $template['dataoptions'],
191
            $template['dimension1'],
192
            $template['dimension2'],
193
            $template['value']);
194
        $this->ReportMapper->updateOptions($newId, $chartoptions, $dataoptions, $filteroptions);
195
        return $newId;
196
    }
197
198
    /**
199
     * create new report
200
     *
201
     * @param string $file
202
     * @return int
203
     */
204
    public function createFromFile($file = '')
205
    {
206
        $this->ActivityManager->triggerEvent(0, ActivityManager::OBJECT_DATASET, ActivityManager::SUBJECT_DATASET_ADD);
207
        $reportId = $this->ReportMapper->create();
208
209
        if ($file !== '') {
210
            $name = explode('.', end(explode('/', $file)))[0];
211
            $subheader = $file;
212
            $parent = 0;
213
            $type = DatasourceController::DATASET_TYPE_FILE;
214
            $link = $file;
215
            $visualization = 'table';
216
            $chart = 'line';
217
            $this->update($reportId, $name, $subheader, $parent, $type, $link, $visualization, $chart, '', '');
0 ignored issues
show
Bug introduced by
$link of type string is incompatible with the type integer expected by parameter $dataset of OCA\Analytics\Service\ReportService::update(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

217
            $this->update($reportId, $name, $subheader, $parent, $type, /** @scrutinizer ignore-type */ $link, $visualization, $chart, '', '');
Loading history...
Bug introduced by
The call to OCA\Analytics\Service\ReportService::update() has too few arguments starting with dataoptions. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

217
            $this->/** @scrutinizer ignore-call */ 
218
                   update($reportId, $name, $subheader, $parent, $type, $link, $visualization, $chart, '', '');

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
218
        }
219
        return $reportId;
220
    }
221
222
    /**
223
     * update report details
224
     *
225
     * @param int $reportId
226
     * @param $name
227
     * @param $subheader
228
     * @param int $parent
229
     * @param int $type
230
     * @param int $dataset
231
     * @param $link
232
     * @param $visualization
233
     * @param $chart
234
     * @param $chartoptions
235
     * @param $dataoptions
236
     * @param null $dimension1
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $dimension1 is correct as it would always require null to be passed?
Loading history...
237
     * @param null $dimension2
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $dimension2 is correct as it would always require null to be passed?
Loading history...
238
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
239
     * @return bool
240
     * @throws \OCP\DB\Exception
241
     */
242
    public function update(int $reportId, $name, $subheader, int $parent, int $type, int $dataset, $link, $visualization, $chart, $chartoptions, $dataoptions, $dimension1 = null, $dimension2 = null, $value = null)
243
    {
244
        if ($type === DatasourceController::DATASET_TYPE_GROUP) {
245
            $parent = 0;
246
        }
247
        if ($type === DatasourceController::DATASET_TYPE_INTERNAL_DB && $dataset === 0) { // New dataset
248
            $dataset = $this->DatasetService->create($name, $dimension1, $dimension2, $value);
249
        }
250
        return $this->ReportMapper->update($reportId, $name, $subheader, $parent, $type, $dataset, $link, $visualization, $chart, $chartoptions, $dataoptions, $dimension1, $dimension2, $value);
251
    }
252
253
    /**
254
     * set/remove the favorite flag for a report
255
     *
256
     * @param int $reportId
257
     * @param string $favorite
258
     * @return bool
259
     */
260
    public function setFavorite(int $reportId, string $favorite)
261
    {
262
        if ($favorite === 'true') {
263
            $return = $this->tagManager->load('analytics')->addToFavorites($reportId);
264
        } else {
265
            $return = $this->tagManager->load('analytics')->removeFromFavorites($reportId);
266
        }
267
        return $return;
268
    }
269
270
    /**
271
     * Import Report from File
272
     *
273
     * @param string|null $path
274
     * @param string|null $raw
275
     * @return int
276
     * @throws \OCP\Files\NotFoundException
277
     * @throws \OCP\Files\NotPermittedException
278
     */
279
    public function import(string $path = null, string $raw = null)
280
    {
281
        if ($path !== '') {
282
            $file = $this->rootFolder->getUserFolder($this->userId)->get($path);
283
            $data = $file->getContent();
0 ignored issues
show
Bug introduced by
The method getContent() does not exist on OCP\Files\Node. It seems like you code against a sub-type of OCP\Files\Node such as OCP\Files\File. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

283
            /** @scrutinizer ignore-call */ 
284
            $data = $file->getContent();
Loading history...
284
        } else if ($raw !== null) {
285
            $data = $raw;
286
        } else {
287
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
288
        }
289
        $data = json_decode($data, true);
290
291
        $dataset = $data['dataset'];
292
        isset($dataset['name']) ? $name = $dataset['name'] : $name = '';
293
        isset($dataset['subheader']) ? $subheader = $dataset['subheader'] : $subheader = '';
294
        $parent = 0;
295
        isset($dataset['type']) ? $type = $dataset['type'] : $type = null;
296
        isset($dataset['link']) ? $link = $dataset['link'] : $link = null;
297
        isset($dataset['visualization']) ? $visualization = $dataset['visualization'] : $visualization = null;
298
        isset($dataset['chart']) ? $chart = $dataset['chart'] : $chart = null;
299
        isset($dataset['chartoptions']) ? $chartoptions = $dataset['chartoptions'] : $chartoptions = null;
300
        isset($dataset['dataoptions']) ? $dataoptions = $dataset['dataoptions'] : $dataoptions = null;
301
        isset($dataset['filteroptions']) ? $filteroptions = $dataset['filteroptions'] : $filteroptions = null;
302
        isset($dataset['dimension1']) ? $dimension1 = $dataset['dimension1'] : $dimension1 = null;
303
        isset($dataset['dimension2']) ? $dimension2 = $dataset['dimension2'] : $dimension2 = null;
304
        isset($dataset['value']) ? $value = $dataset['value'] : $value = null;
305
306
        $reportId = $this->ReportMapper->create();
307
        $this->ReportMapper->update($reportId, $name, $subheader, $parent, $type, $link, $visualization, $chart, $chartoptions, $dataoptions, $dimension1, $dimension2, $value, $filteroptions);
308
309
        foreach ($data['dataload'] as $dataload) {
310
            isset($dataload['datasource']) ? $datasource = $dataload['datasource'] : $datasource = null;
311
            isset($dataload['name']) ? $name = $dataload['name'] : $name = null;
312
            isset($dataload['option']) ? $option = $dataload['option'] : $option = null;
313
            $schedule = null;
314
315
            /**todo**/
316
            $dataloadId = $this->DataloadMapper->create($reportId, $datasource);
317
            $this->DataloadMapper->update($dataloadId, $name, $option, $schedule);
318
        }
319
320
        foreach ($data['threshold'] as $threshold) {
321
            isset($threshold['dimension1']) ? $dimension1 = $threshold['dimension1'] : $dimension1 = null;
322
            isset($threshold['value']) ? $value = $threshold['value'] : $value = null;
323
            isset($threshold['option']) ? $option = $threshold['option'] : $option = null;
324
            isset($threshold['severity']) ? $severity = $threshold['severity'] : $severity = null;
325
            $this->ThresholdService->create($reportId, $dimension1, $option, $value, $severity);
326
        }
327
328
        foreach ($data['data'] as $dData) {
329
            isset($dData[0]) ? $dimension1 = $dData[0] : $dimension1 = null;
330
            isset($dData[1]) ? $dimension2 = $dData[1] : $dimension2 = null;
331
            isset($dData[2]) ? $value = $dData[2] : $value = null;
332
            $this->StorageMapper->create($reportId, $dimension1, $dimension2, $value);
333
        }
334
335
        if (isset($data['favorite'])) {
336
            $this->setFavorite($reportId, $data['favorite']);
337
        }
338
339
        return $reportId;
340
    }
341
342
    /**
343
     * Export Report
344
     *
345
     * @param int $reportId
346
     * @return DataDownloadResponse
347
     */
348
    public function export(int $reportId)
349
    {
350
        /**todo**/
351
        $result = array();
352
        $result['dataset'] = $this->ReportMapper->read($reportId);
353
        $result['dataload'] = $this->DataloadMapper->read($datasetId);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $datasetId seems to be never defined.
Loading history...
354
        $result['threshold'] = $this->ThresholdService->read($reportId);
355
        $result['favorite'] = '';
356
357
        if ($result['dataset']['type'] === DatasourceController::DATASET_TYPE_INTERNAL_DB) {
358
            $result['data'] = $this->StorageMapper->read($datasetId);
359
        }
360
361
        unset($result['dataset']['id'], $result['dataset']['user_id'], $result['dataset']['user_id'], $result['dataset']['parent']);
362
        $data = json_encode($result);
363
        return new DataDownloadResponse($data, $result['dataset']['name'] . '.export.txt', 'text/plain; charset=utf-8');
364
    }
365
366
    /**
367
     * Delete Dataset and all depending objects
368
     *
369
     * @param int $reportId
370
     * @return bool
371
     */
372
    public function delete(int $reportId): bool
373
    {
374
        $this->ShareService->deleteShareByReport($reportId);
375
        $this->StorageMapper->deleteByDataset($reportId);
376
        /**todo**/
377
        // delete dataset when last report
378
        $this->ReportMapper->delete($reportId);
379
        $this->ThresholdService->deleteThresholdByReport($reportId);
380
        $this->DataloadMapper->deleteDataloadByDataset($reportId);
381
        $this->ActivityManager->triggerEvent(0, ActivityManager::OBJECT_DATASET, ActivityManager::SUBJECT_DATASET_DELETE);
382
        $this->setFavorite($reportId, 'false');
383
        return true;
384
    }
385
386
    /**
387
     * Update report options
388
     *
389
     * @param int $reportId
390
     * @param $chartoptions
391
     * @param $dataoptions
392
     * @param $filteroptions
393
     * @return bool
394
     */
395
    public function updateOptions(int $reportId, $chartoptions, $dataoptions, $filteroptions)
396
    {
397
        return $this->ReportMapper->updateOptions($reportId, $chartoptions, $dataoptions, $filteroptions);
398
    }
399
400
    /**
401
     * get report refresh options
402
     *
403
     * @NoAdminRequired
404
     * @param int $reportId
405
     * @param $refresh
406
     * @return bool
407
     */
408
    public function updateRefresh(int $reportId, $refresh)
409
    {
410
        return $this->ReportMapper->updateRefresh($reportId, $refresh);
411
    }
412
413
    /**
414
     * search for reports
415
     *
416
     * @param string $searchString
417
     * @return array
418
     */
419
    public function search(string $searchString)
420
    {
421
        return $this->ReportMapper->search($searchString);
422
    }
423
424
}