Passed
Push — master ( 6c703d...3d333b )
by Marcel
03:19
created

ReportService::update()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 3
b 0
f 0
nc 2
nop 12
dl 0
loc 9
rs 10

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 2019-2022 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
90
        // get shared reports and remove duplicates
91
        $sharedReports = $this->ShareService->getSharedReports();
92
        foreach ($sharedReports as $sharedReport) {
93
            if (!array_search($sharedReport['id'], array_column($ownReports, 'id'))) {
94
                $sharedReport['type'] = '99';
95
                $sharedReport['parent'] = '0';
96
                array_push($ownReports, $sharedReport);
97
            }
98
        }
99
        if (count($ownReports) === 0) return $ownReports;
100
101
        // get data load indicators for icons shown in the advanced screen
102
        $dataloads = $this->DataloadMapper->getAllDataloadMetadata();
103
        foreach ($dataloads as $dataload) {
104
            $key = array_search($dataload['dataset'], array_column($ownReports, 'dataset'));
105
            if ($key !== '') {
106
                if ($dataload['schedules'] !== '' and $dataload['schedules'] !== null) {
107
                    $dataload['schedules'] = 1;
108
                } else {
109
                    $dataload['schedules'] = 0;
110
                }
111
                $ownReports[$key]['dataloads'] = $dataload['dataloads'];
112
                $ownReports[$key]['schedules'] = $dataload['schedules'];
113
            }
114
        }
115
116
        $favorites = $this->tagManager->load('analytics')->getFavorites();
117
        foreach ($ownReports as &$ownReport) {
118
            $hasTag = 0;
119
            if (is_array($favorites) and in_array($ownReport['id'], $favorites)) {
120
                $hasTag = 1;
121
            }
122
            $ownReport['favorite'] = $hasTag;
123
            $ownReport = $this->VariableService->replaceTextVariables($ownReport);
124
        }
125
126
        return $ownReports;
127
    }
128
129
    /**
130
     * get own report details
131
     *
132
     * @param int $reportId
133
     * @return array
134
     * @throws Exception
135
     */
136
    public function read(int $reportId, $replace = true)
137
    {
138
        $ownReport = $this->ReportMapper->readOwn($reportId);
139
        if (!empty($ownReport)) {
140
            $ownReport['permissions'] = \OCP\Constants::PERMISSION_UPDATE;
141
            if ($replace) $ownReport = $this->VariableService->replaceTextVariables($ownReport);
142
143
            if ($ownReport['type'] === DatasourceController::DATASET_TYPE_INTERNAL_DB && $ownReport['dataset'] !== 0) {
144
                $dataset = $this->DatasetService->readOwn($ownReport['dataset']);
145
                $ownReport['dimension1'] = $dataset['dimension1'];
146
                $ownReport['dimension2'] = $dataset['dimension2'];
147
                $ownReport['value'] = $dataset['value'];
148
            }
149
150
        }
151
        return $ownReport;
152
    }
153
154
    /**
155
     * check if own report
156
     *
157
     * @param int $reportId
158
     * @return bool
159
     */
160
    public function isOwn(int $reportId)
161
    {
162
        $ownReport = $this->ReportMapper->readOwn($reportId);
163
        if (!empty($ownReport)) {
164
            return true;
165
        } else {
166
            return false;
167
        }
168
    }
169
170
    /**
171
     * create new blank report
172
     *
173
     * @return int
174
     * @throws Exception
175
     */
176
    public function create($name, $subheader, $parent, $type, int $dataset, $link, $visualization, $chart, $dimension1, $dimension2, $value, $addReport = null): int
177
    {
178
        $array = json_decode($link, true);
179
        if (is_array($array)){
180
            foreach ($array as $key => $value) {
0 ignored issues
show
introduced by
$value is overwriting one of the parameters of this function.
Loading history...
181
                $array[$key] = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
182
            }
183
        }
184
        $link = json_encode($array);
185
186
        if ($type === DatasourceController::DATASET_TYPE_GROUP) {
187
            $parent = 0;
188
        }
189
        if ($type === DatasourceController::DATASET_TYPE_INTERNAL_DB && $dataset === 0) { // New dataset
190
            $dataset = $this->DatasetService->create($name, $dimension1, $dimension2, $value);
191
        }
192
        $reportId = $this->ReportMapper->create($name, $subheader, $parent, $type, $dataset, $link, $visualization, $chart, $dimension1, $dimension2, $value);
193
        $this->ActivityManager->triggerEvent($reportId, ActivityManager::OBJECT_REPORT, ActivityManager::SUBJECT_REPORT_ADD);
194
195
        if ($addReport !== null && $addReport !== '') {
196
            $this->updateGroup($addReport, $reportId);
197
        }
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 $options
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, $options, $visualization, $chart, $chartoptions, $dataoptions, $dimension1 = null, $dimension2 = null, $value = null)
275
    {
276
        $array = json_decode($options, true);
277
        foreach ($array as $key => $value) {
278
            $array[$key] = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
279
        }
280
        $options = json_encode($array);
281
282
        return $this->ReportMapper->update($reportId, $name, $subheader, $parent, $options, $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->ReportMapper->readOwn($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';
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 !== '' and $path !== null) {
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 0;
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
        $this->DataloadMapper->beginTransaction();
410
411
        foreach ($data['dataload'] as $dataload) {
412
            isset($dataload['datasource']) ? $datasource = $dataload['datasource'] : $datasource = null;
413
            isset($dataload['name']) ? $name = $dataload['name'] : $name = null;
414
            isset($dataload['option']) ? $option = $dataload['option'] : $option = null;
415
            $schedule = null;
416
417
            $dataloadId = $this->DataloadMapper->create($datasetId, $datasource);
418
            $this->DataloadMapper->update($dataloadId, $name, $option, $schedule);
419
        }
420
421
        foreach ($data['threshold'] as $threshold) {
422
            isset($threshold['dimension1']) ? $dimension1 = $threshold['dimension1'] : $dimension1 = null;
423
            isset($threshold['value']) ? $value = $threshold['value'] : $value = null;
424
            isset($threshold['option']) ? $option = $threshold['option'] : $option = null;
425
            isset($threshold['severity']) ? $severity = $threshold['severity'] : $severity = null;
426
            $value = $this->floatvalue($value);
427
            $this->ThresholdMapper->create($reportId, $dimension1, $value, $option, $severity);
428
        }
429
430
        foreach ($data['data'] as $dData) {
431
            isset($dData[0]) ? $dimension1 = $dData[0] : $dimension1 = null;
432
            isset($dData[1]) ? $dimension2 = $dData[1] : $dimension2 = null;
433
            isset($dData[2]) ? $value = $dData[2] : $value = null;
434
            $this->StorageMapper->create($datasetId, $dimension1, $dimension2, $value);
435
        }
436
437
        $this->DataloadMapper->commit();
438
439
        if (isset($data['favorite'])) {
440
            $this->setFavorite($reportId, $data['favorite']);
441
        }
442
443
        return $reportId;
444
    }
445
446
    /**
447
     * Export Report
448
     *
449
     * @param int $reportId
450
     * @return DataDownloadResponse
451
     */
452
    public function export(int $reportId)
453
    {
454
        $result = array();
455
        $result['report'] = $this->ReportMapper->readOwn($reportId);
456
        $datasetId = $result['report']['dataset'];
457
        $result['dataload'] = $this->DataloadMapper->read($datasetId);
458
        $result['threshold'] = $this->ThresholdMapper->getThresholdsByReport($reportId);
459
        $result['favorite'] = '';
460
461
        if ($result['report']['type'] === DatasourceController::DATASET_TYPE_INTERNAL_DB) {
462
            $result['data'] = $this->StorageMapper->read($datasetId);
463
        }
464
465
        unset($result['report']['id'], $result['report']['user_id'], $result['report']['user_id'], $result['report']['parent'], $result['report']['dataset']);
466
        $data = json_encode($result);
467
        return new DataDownloadResponse($data, $result['report']['name'] . '.export.txt', 'text/plain; charset=utf-8');
468
    }
469
470
    /**
471
     * Update report options
472
     *
473
     * @param int $reportId
474
     * @param $chartoptions
475
     * @param $dataoptions
476
     * @param $filteroptions
477
     * @return bool
478
     */
479
    public function updateOptions(int $reportId, $chartoptions, $dataoptions, $filteroptions)
480
    {
481
        return $this->ReportMapper->updateOptions($reportId, $chartoptions, $dataoptions, $filteroptions);
482
    }
483
484
    /**
485
     * get report refresh options
486
     *
487
     * @NoAdminRequired
488
     * @param int $reportId
489
     * @param $refresh
490
     * @return bool
491
     */
492
    public function updateRefresh(int $reportId, $refresh)
493
    {
494
        return $this->ReportMapper->updateRefresh($reportId, $refresh);
495
    }
496
497
    /**
498
     * update report group assignment (from drag & drop)
499
     *
500
     * @NoAdminRequired
501
     * @param int $reportId
502
     * @param $groupId
503
     * @return bool
504
     */
505
    public function updateGroup(int $reportId, $groupId)
506
    {
507
        return $this->ReportMapper->updateGroup($reportId, $groupId);
508
    }
509
510
    /**
511
     * search for reports
512
     *
513
     * @param string $searchString
514
     * @return array
515
     */
516
    public function search(string $searchString)
517
    {
518
        return $this->ReportMapper->search($searchString);
519
    }
520
521
    /**
522
     * @throws Exception
523
     */
524
    public function reportsForDataset($datasetId) {
525
        return $this->ReportMapper->reportsForDataset($datasetId);
526
    }
527
528
    private function floatvalue($val)
529
    {
530
        $val = str_replace(",", ".", $val);
531
        $val = preg_replace('/\.(?=.*\.)/', '', $val);
532
        $val = preg_replace('/[^0-9-.]+/', '', $val);
533
        if (is_numeric($val)) {
534
            return number_format(floatval($val), 2, '.', '');
535
        } else {
536
            return false;
537
        }
538
    }
539
540
}
541