Passed
Push — master ( fc42a6...b0746a )
by Marcel
02:44 queued 11s
created

ReportService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 14
c 3
b 0
f 0
nc 1
nop 14
dl 0
loc 31
rs 9.7998

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 OCA\Analytics\Db\ThresholdMapper;
20
use OCP\AppFramework\Http\DataDownloadResponse;
21
use OCP\DB\Exception;
22
use OCP\Files\IRootFolder;
23
use OCP\ITagManager;
24
use OCP\IConfig;
25
use OCP\PreConditionNotMetException;
26
use Psr\Log\LoggerInterface;
27
use OCP\IL10N;
28
29
class ReportService
30
{
31
    /** @var IConfig */
32
    protected $config;
33
    private $userId;
34
    private $logger;
35
    private $tagManager;
36
    private $ShareService;
37
    private $DatasetService;
38
    private $StorageMapper;
39
    private $ReportMapper;
40
    private $ThresholdMapper;
41
    private $DataloadMapper;
42
    private $ActivityManager;
43
    private $rootFolder;
44
    private $VariableService;
45
    private $l10n;
46
47
    public function __construct(
48
        $userId,
49
        IL10N $l10n,
50
        LoggerInterface $logger,
51
        ITagManager $tagManager,
52
        ShareService $ShareService,
53
        DatasetService $DatasetService,
54
        StorageMapper $StorageMapper,
55
        ReportMapper $ReportMapper,
56
        ThresholdMapper $ThresholdMapper,
57
        DataloadMapper $DataloadMapper,
58
        ActivityManager $ActivityManager,
59
        IRootFolder $rootFolder,
60
        IConfig $config,
61
        VariableService $VariableService
62
    )
63
    {
64
        $this->userId = $userId;
65
        $this->logger = $logger;
66
        $this->tagManager = $tagManager;
67
        $this->ShareService = $ShareService;
68
        $this->DatasetService = $DatasetService;
69
        $this->ThresholdMapper = $ThresholdMapper;
70
        $this->StorageMapper = $StorageMapper;
71
        $this->ReportMapper = $ReportMapper;
72
        $this->DataloadMapper = $DataloadMapper;
73
        $this->ActivityManager = $ActivityManager;
74
        $this->rootFolder = $rootFolder;
75
        $this->VariableService = $VariableService;
76
        $this->config = $config;
77
        $this->l10n = $l10n;
78
    }
79
80
    /**
81
     * get all reports
82
     *
83
     * @return array
84
     * @throws PreConditionNotMetException
85
     */
86
    public function index(): array
87
    {
88
        $ownReports = $this->ReportMapper->index();
89
        if (count($ownReports) === 0) return $ownReports;
90
91
        // get data load indicators for icons shown in the advanced screen
92
        $dataloads = $this->DataloadMapper->getAllDataloadMetadata();
93
        foreach ($dataloads as $dataload) {
94
            $key = array_search($dataload['dataset'], array_column($ownReports, 'dataset'));
95
            if ($key !== '') {
96
                if ($dataload['schedules'] !== '' and $dataload['schedules'] !== null) {
97
                    $dataload['schedules'] = 1;
98
                } else {
99
                    $dataload['schedules'] = 0;
100
                }
101
                $ownReports[$key]['dataloads'] = $dataload['dataloads'];
102
                $ownReports[$key]['schedules'] = $dataload['schedules'];
103
            }
104
        }
105
106
        // get shared reports and remove duplicates
107
        $sharedReports = $this->ShareService->getSharedReports();
108
        foreach ($sharedReports as $sharedReport) {
109
            if (!array_search($sharedReport['id'], array_column($ownReports, 'id'))) {
110
                $sharedReport['type'] = '99';
111
                $sharedReport['parrent'] = '0';
112
                array_push($ownReports, $sharedReport);
113
            }
114
        }
115
116
        $favoriteMigration = $this->config->getUserValue($this->userId, 'analytics', 'favMig', '0');
117
        if ($favoriteMigration === '0') {
118
            $this->logger->info('Favorite migration being performed');
119
            $this->favoriteMigration($ownReports);
120
            $this->config->setUserValue($this->userId, 'analytics', 'favMig', 3.7);
121
        }
122
123
        $favorites = $this->tagManager->load('analytics')->getFavorites();
124
        foreach ($ownReports as &$ownReport) {
125
            $hasTag = 0;
126
            if (is_array($favorites) and in_array($ownReport['id'], $favorites)) {
127
                $hasTag = 1;
128
            }
129
            $ownReport['favorite'] = $hasTag;
130
            $ownReport = $this->VariableService->replaceTextVariables($ownReport);
131
        }
132
133
        return $ownReports;
134
    }
135
136
    /**
137
     * get own report details
138
     *
139
     * @param int $reportId
140
     * @return array
141
     * @throws Exception
142
     */
143
    public function read(int $reportId, $replace = true)
144
    {
145
        $ownReport = $this->ReportMapper->readOwn($reportId);
146
        if (!empty($ownReport)) {
147
            $ownReport['permissions'] = \OCP\Constants::PERMISSION_UPDATE;
148
            if ($replace) $ownReport = $this->VariableService->replaceTextVariables($ownReport);
149
150
            if ($ownReport['type'] === DatasourceController::DATASET_TYPE_INTERNAL_DB && $ownReport['dataset'] !== 0) {
151
                $dataset = $this->DatasetService->readOwn($ownReport['dataset']);
152
                $ownReport['dimension1'] = $dataset['dimension1'];
153
                $ownReport['dimension2'] = $dataset['dimension2'];
154
                $ownReport['value'] = $dataset['value'];
155
            }
156
157
        }
158
        return $ownReport;
159
    }
160
161
    /**
162
     * check if own report
163
     *
164
     * @param int $reportId
165
     * @return bool
166
     */
167
    public function isOwn(int $reportId)
168
    {
169
        $ownReport = $this->ReportMapper->readOwn($reportId);
170
        if (!empty($ownReport)) {
171
            return true;
172
        } else {
173
            return false;
174
        }
175
    }
176
177
        /**
178
     * create new blank report
179
     *
180
     * @return int
181
     */
182
    public function create($name, $subheader, $parent, $type, int $dataset, $link, $visualization, $chart, $dimension1, $dimension2, $value): int
183
    {
184
        $array = json_decode($link, true);
185
        foreach ($array as $key => $value) {
0 ignored issues
show
introduced by
$value is overwriting one of the parameters of this function.
Loading history...
186
            $array[$key] = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
187
        }
188
        $link = json_encode($array);
189
190
        if ($type === DatasourceController::DATASET_TYPE_GROUP) {
191
            $parent = 0;
192
        }
193
        if ($type === DatasourceController::DATASET_TYPE_INTERNAL_DB && $dataset === 0) { // New dataset
194
            $dataset = $this->DatasetService->create($name, $dimension1, $dimension2, $value);
195
        }
196
        $reportId = $this->ReportMapper->create($name, $subheader, $parent, $type, $dataset, $link, $visualization, $chart, $dimension1, $dimension2, $value);
197
        $this->ActivityManager->triggerEvent($reportId, ActivityManager::OBJECT_REPORT, ActivityManager::SUBJECT_REPORT_ADD);
198
        return $reportId;
199
    }
200
201
    /**
202
     * copy an existing report with the current navigation status
203
     *
204
     * @NoAdminRequired
205
     * @param int $reportId
206
     * @param $chartoptions
207
     * @param $dataoptions
208
     * @param $filteroptions
209
     * @return int
210
     * @throws Exception
211
     */
212
    public function createCopy(int $reportId, $chartoptions, $dataoptions, $filteroptions)
213
    {
214
215
        $template = $this->ReportMapper->readOwn($reportId);
216
        $newId = $this->ReportMapper->create(
217
        // TRANSLATORS Noun
218
            $template['name'] . ' ' . $this->l10n->t('copy'),
219
            $template['subheader'],
220
            $template['parent'],
221
            $template['type'],
222
            $template['dataset'],
223
            $template['link'],
224
            $template['visualization'],
225
            $template['chart'],
226
            $template['dimension1'],
227
            $template['dimension2'],
228
            $template['value']);
229
        $this->ReportMapper->updateOptions($newId, $chartoptions, $dataoptions, $filteroptions);
230
        return $newId;
231
    }
232
233
    /**
234
     * create new report
235
     *
236
     * @param string $file
237
     * @return int
238
     */
239
    public function createFromDataFile($file = '')
240
    {
241
        $this->ActivityManager->triggerEvent(0, ActivityManager::OBJECT_REPORT, ActivityManager::SUBJECT_REPORT_ADD);
242
243
        if ($file !== '') {
244
            $name = explode('.', end(explode('/', $file)))[0];
245
            $subheader = $file;
246
            $parent = 0;
247
            $dataset = 0;
248
            $type = DatasourceController::DATASET_TYPE_FILE;
249
            $link = $file;
250
            $visualization = 'table';
251
            $chart = 'line';
252
            $reportId = $this->ReportMapper->create($name, $subheader, $parent, $type, $dataset, $link, $visualization, $chart, '', '', '');
253
        }
254
        return $reportId;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $reportId does not seem to be defined for all execution paths leading up to this point.
Loading history...
255
    }
256
257
    /**
258
     * update report details
259
     *
260
     * @param int $reportId
261
     * @param $name
262
     * @param $subheader
263
     * @param int $parent
264
     * @param $link
265
     * @param $visualization
266
     * @param $chart
267
     * @param $chartoptions
268
     * @param $dataoptions
269
     * @param $dimension1
270
     * @param $dimension2
271
     * @param $value
272
     * @return bool
273
     */
274
    public function update(int $reportId, $name, $subheader, int $parent, $link, $visualization, $chart, $chartoptions, $dataoptions, $dimension1 = null, $dimension2 = null, $value = null)
275
    {
276
        $array = json_decode($link, true);
277
        foreach ($array as $key => $value) {
278
            $array[$key] = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
279
        }
280
        $link = json_encode($array);
281
282
        return $this->ReportMapper->update($reportId, $name, $subheader, $parent, $link, $visualization, $chart, $chartoptions, $dataoptions, $dimension1, $dimension2, $value);
283
    }
284
285
    /**
286
     * Delete Dataset and all depending objects
287
     *
288
     * @param int $reportId
289
     * @return string
290
     * @throws Exception
291
     */
292
    public function delete(int $reportId)
293
    {
294
        $metadata = $this->read($reportId);
295
        //$this->ActivityManager->triggerEvent($reportId, ActivityManager::OBJECT_REPORT, ActivityManager::SUBJECT_REPORT_DELETE);
296
        $this->ShareService->deleteShareByReport($reportId);
297
        $this->ThresholdMapper->deleteThresholdByReport($reportId);
298
        $this->setFavorite($reportId, 'false');
299
        $this->ReportMapper->delete($reportId);
300
301
        $report = $this->reportsForDataset((int)$metadata['dataset']);
302
        if (empty($report) && (int)$metadata['type'] === DatasourceController::DATASET_TYPE_INTERNAL_DB) {
303
            return $metadata['dataset'];
304
        } else {
305
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type string.
Loading history...
306
        }
307
    }
308
309
    /**
310
     * get dataset by user
311
     *
312
     * @param string $userId
313
     * @return array|bool
314
     * @throws Exception
315
     */
316
    public function deleteByUser(string $userId)
317
    {
318
        $reports = $this->ReportMapper->indexByUser($userId);
319
        foreach ($reports as $report) {
320
            $this->ShareService->deleteShareByReport($report['id']);
321
            $this->ThresholdMapper->deleteThresholdByReport($report['id']);
322
            $this->setFavorite($report['id'], 'false');
323
            $this->ReportMapper->delete($report['id']);
324
        }
325
        return true;
326
    }
327
328
    /**
329
     * get own reports which are marked as favorites
330
     *
331
     * @return array|bool
332
     */
333
    public function getOwnFavoriteReports()
334
    {
335
        $ownReports = $this->ReportMapper->index();
336
        $favorites = $this->tagManager->load('analytics')->getFavorites();
337
        $sharedReports = $this->ShareService->getSharedReports();
338
339
        foreach ($favorites as $favorite) {
340
            if (array_search($favorite, array_column($ownReports, 'id')) === false
341
                && array_search($favorite, array_column($sharedReports, 'id')) === false) {
342
                unset($favorites[$favorite]);
343
                $this->tagManager->load('analytics')->removeFromFavorites($favorite);
344
            }
345
        }
346
347
        return $favorites;
348
    }
349
350
    /**
351
     * set/remove the favorite flag for a report
352
     *
353
     * @param int $reportId
354
     * @param string $favorite
355
     * @return bool
356
     */
357
    public function setFavorite(int $reportId, string $favorite)
358
    {
359
        if ($favorite === 'true') {
360
            $return = $this->tagManager->load('analytics')->addToFavorites($reportId);
361
        } else {
362
            $return = $this->tagManager->load('analytics')->removeFromFavorites($reportId);
363
        }
364
        return $return;
365
    }
366
367
    /**
368
     * Import Report from File
369
     *
370
     * @param string|null $path
371
     * @param string|null $raw
372
     * @return int
373
     * @throws \OCP\Files\NotFoundException
374
     * @throws \OCP\Files\NotPermittedException
375
     */
376
    public function import(string $path = null, string $raw = null)
377
    {
378
        if ($path !== '') {
379
            $file = $this->rootFolder->getUserFolder($this->userId)->get($path);
380
            $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

380
            /** @scrutinizer ignore-call */ 
381
            $data = $file->getContent();
Loading history...
381
        } else if ($raw !== null) {
382
            $data = $raw;
383
        } else {
384
            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...
385
        }
386
        $data = json_decode($data, true);
387
388
        $report = $data['report'];
389
        isset($report['name']) ? $name = $report['name'] : $name = '';
390
        isset($report['subheader']) ? $subheader = $report['subheader'] : $subheader = '';
391
        $parent = 0;
392
        $dataset = 0;
393
        isset($report['type']) ? $type = $report['type'] : $type = null;
394
        isset($report['link']) ? $link = $report['link'] : $link = null;
395
        isset($report['visualization']) ? $visualization = $report['visualization'] : $visualization = null;
396
        isset($report['chart']) ? $chart = $report['chart'] : $chart = null;
397
        isset($report['chartoptions']) ? $chartoptions = $report['chartoptions'] : $chartoptions = null;
398
        isset($report['dataoptions']) ? $dataoptions = $report['dataoptions'] : $dataoptions = null;
399
        isset($report['filteroptions']) ? $filteroptions = $report['filteroptions'] : $filteroptions = null;
400
        isset($report['dimension1']) ? $dimension1 = $report['dimension1'] : $dimension1 = null;
401
        isset($report['dimension2']) ? $dimension2 = $report['dimension2'] : $dimension2 = null;
402
        isset($report['value']) ? $value = $report['value'] : $value = null;
403
404
        $reportId = $this->create($name, $subheader, $parent, $type, $dataset, $link, $visualization, $chart, $dimension1, $dimension2, $value);
405
        $this->updateOptions($reportId, $chartoptions, $dataoptions, $filteroptions);
406
        $report = $this->ReportMapper->readOwn($reportId);
407
        $datasetId = $report['dataset'];
408
409
        foreach ($data['dataload'] as $dataload) {
410
            isset($dataload['datasource']) ? $datasource = $dataload['datasource'] : $datasource = null;
411
            isset($dataload['name']) ? $name = $dataload['name'] : $name = null;
412
            isset($dataload['option']) ? $option = $dataload['option'] : $option = null;
413
            $schedule = null;
414
415
            $dataloadId = $this->DataloadMapper->create($datasetId, $datasource);
416
            $this->DataloadMapper->update($dataloadId, $name, $option, $schedule);
417
        }
418
419
        foreach ($data['threshold'] as $threshold) {
420
            isset($threshold['dimension1']) ? $dimension1 = $threshold['dimension1'] : $dimension1 = null;
421
            isset($threshold['value']) ? $value = $threshold['value'] : $value = null;
422
            isset($threshold['option']) ? $option = $threshold['option'] : $option = null;
423
            isset($threshold['severity']) ? $severity = $threshold['severity'] : $severity = null;
424
            $value = $this->floatvalue($value);
425
            $this->ThresholdMapper->create($reportId, $dimension1, $value, $option, $severity);
426
        }
427
428
        foreach ($data['data'] as $dData) {
429
            isset($dData[0]) ? $dimension1 = $dData[0] : $dimension1 = null;
430
            isset($dData[1]) ? $dimension2 = $dData[1] : $dimension2 = null;
431
            isset($dData[2]) ? $value = $dData[2] : $value = null;
432
            $this->StorageMapper->create($datasetId, $dimension1, $dimension2, $value);
433
        }
434
435
        if (isset($data['favorite'])) {
436
            $this->setFavorite($reportId, $data['favorite']);
437
        }
438
439
        return $reportId;
440
    }
441
442
    /**
443
     * Export Report
444
     *
445
     * @param int $reportId
446
     * @return DataDownloadResponse
447
     */
448
    public function export(int $reportId)
449
    {
450
        $result = array();
451
        $result['report'] = $this->ReportMapper->readOwn($reportId);
452
        $datasetId = $result['report']['dataset'];
453
        $result['dataload'] = $this->DataloadMapper->read($datasetId);
454
        $result['threshold'] = $this->ThresholdMapper->getThresholdsByReport($reportId);
455
        $result['favorite'] = '';
456
457
        if ($result['report']['type'] === DatasourceController::DATASET_TYPE_INTERNAL_DB) {
458
            $result['data'] = $this->StorageMapper->read($datasetId);
459
        }
460
461
        unset($result['report']['id'], $result['report']['user_id'], $result['report']['user_id'], $result['report']['parent'], $result['report']['dataset']);
462
        $data = json_encode($result);
463
        return new DataDownloadResponse($data, $result['report']['name'] . '.export.txt', 'text/plain; charset=utf-8');
464
    }
465
466
    /**
467
     * Update report options
468
     *
469
     * @param int $reportId
470
     * @param $chartoptions
471
     * @param $dataoptions
472
     * @param $filteroptions
473
     * @return bool
474
     */
475
    public function updateOptions(int $reportId, $chartoptions, $dataoptions, $filteroptions)
476
    {
477
        return $this->ReportMapper->updateOptions($reportId, $chartoptions, $dataoptions, $filteroptions);
478
    }
479
480
    /**
481
     * get report refresh options
482
     *
483
     * @NoAdminRequired
484
     * @param int $reportId
485
     * @param $refresh
486
     * @return bool
487
     */
488
    public function updateRefresh(int $reportId, $refresh)
489
    {
490
        return $this->ReportMapper->updateRefresh($reportId, $refresh);
491
    }
492
493
    /**
494
     * search for reports
495
     *
496
     * @param string $searchString
497
     * @return array
498
     */
499
    public function search(string $searchString)
500
    {
501
        return $this->ReportMapper->search($searchString);
502
    }
503
504
    /**
505
     * @throws Exception
506
     */
507
    public function reportsForDataset($datasetId) {
508
        return $this->ReportMapper->reportsForDataset($datasetId);
509
    }
510
511
    /**
512
     * migrate old favorite ids
513
     *
514
     * @param $ownReports
515
     * @return bool
516
     */
517
    private function favoriteMigration($ownReports) {
518
        $favorites = $this->tagManager->load('analytics')->getFavorites();
519
        foreach ($favorites as $favorite) {
520
            $key = array_search($favorite, array_column($ownReports, 'dataset'));
521
            if ($key) {
522
                $this->logger->info('Favorite was migrated from '. $ownReports[$key]['dataset'] . ' to new report ' . $ownReports[$key]['id']);
523
                $this->tagManager->load('analytics')->removeFromFavorites($ownReports[$key]['dataset']);
524
                $this->tagManager->load('analytics')->addToFavorites($ownReports[$key]['id']);
525
            }
526
        }
527
        return true;
528
    }
529
530
    private function floatvalue($val)
531
    {
532
        $val = str_replace(",", ".", $val);
533
        $val = preg_replace('/\.(?=.*\.)/', '', $val);
534
        $val = preg_replace('/[^0-9-.]+/', '', $val);
535
        if (is_numeric($val)) {
536
            return number_format(floatval($val), 2, '.', '');
537
        } else {
538
            return false;
539
        }
540
    }
541
542
}
543