Passed
Push — master ( 9e5f06...f158b8 )
by Marcel
03:58 queued 13s
created

OutputController::readPreview()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 17
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 23
rs 9.7
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\Controller;
13
14
use OCA\Analytics\DataSession;
15
use OCA\Analytics\Service\ReportService;
16
use OCA\Analytics\Service\ShareService;
17
use OCA\Analytics\Service\ThresholdService;
18
use OCA\Analytics\Service\StorageService;
19
use OCA\Analytics\Service\VariableService;
20
use OCP\AppFramework\Controller;
21
use OCP\AppFramework\Http;
22
use OCP\AppFramework\Http\DataResponse;
23
use OCP\AppFramework\Http\NotFoundResponse;
24
use OCP\Constants;
25
use OCP\DB\Exception;
26
use OCP\Files\NotFoundException;
27
use OCP\IRequest;
28
use Psr\Log\LoggerInterface;
29
30
class OutputController extends Controller
31
{
32
    private $logger;
33
    private $ReportService;
34
    private $DataSession;
35
    private $ShareService;
36
    private $DatasourceController;
37
    private $StorageService;
38
    private $ThresholdService;
39
    private $VariableService;
40
41
    public function __construct(
42
        string $AppName,
43
        IRequest $request,
44
        LoggerInterface $logger,
45
        ReportService $ReportService,
46
        ShareService $ShareService,
47
        DataSession $DataSession,
48
        DatasourceController $DatasourceController,
49
        StorageService $StorageService,
50
        ThresholdService $ThresholdService,
51
        VariableService $VariableService
52
    )
53
    {
54
        parent::__construct($AppName, $request);
55
        $this->logger = $logger;
56
        $this->ReportService = $ReportService;
57
        $this->DataSession = $DataSession;
58
        $this->ShareService = $ShareService;
59
        $this->DatasourceController = $DatasourceController;
60
        $this->StorageService = $StorageService;
61
        $this->ThresholdService = $ThresholdService;
62
        $this->VariableService = $VariableService;
63
    }
64
65
    /**
66
     * get the data when requested from internal page
67
     *
68
     * @NoAdminRequired
69
     * @param int $reportId
70
     * @param $filteroptions
71
     * @param $dataoptions
72
     * @param $chartoptions
73
     * @return DataResponse|NotFoundResponse
74
     * @throws Exception
75
     */
76
    public function read(int $reportId, $filteroptions, $dataoptions, $chartoptions)
77
    {
78
        $reportMetadata = $this->ReportService->read($reportId);
79
        if (empty($reportMetadata)) $reportMetadata = $this->ShareService->getSharedReport($reportId);
80
81
        if (!empty($reportMetadata)) {
82
            $reportMetadata = $this->evaluateCanFilter($reportMetadata, $filteroptions, $dataoptions, $chartoptions);
83
            $result = $this->getData($reportMetadata);
84
            return new DataResponse($result, HTTP::STATUS_OK);
85
        } else {
86
            return new NotFoundResponse();
87
        }
88
    }
89
90
    /**
91
     * Preview the data
92
     *
93
     * @NoAdminRequired
94
     * @param $type
95
     * @param $options
96
     * @return DataResponse|NotFoundResponse
97
     * @throws Exception
98
     */
99
    public function readPreview ($type, $options)
100
    {
101
        $reportMetadata = [];
102
         $array = json_decode($options, true);
103
        foreach ($array as $key => $value) {
104
            $array[$key] = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
105
        }
106
        $reportMetadata['link'] = json_encode($array);
107
        $reportMetadata['type'] = $type;
108
        $reportMetadata['dataset'] = 0;
109
        $reportMetadata['filteroptions'] = '';
110
        $reportMetadata['user_id'] = 'admin';
111
        $reportMetadata['id'] = 0;
112
113
        $result = $this->getData($reportMetadata);
114
        unset($result['options']
115
            , $result['dimensions']
116
            , $result['filterApplied']
117
            , $result['thresholds']
118
        );
119
        $result['data'] = array_slice($result['data'], 0, 1);
120
121
        return new DataResponse($result, HTTP::STATUS_OK);
122
    }
123
124
125
    /**
126
     * Get the data from backend;
127
     * pre-evaluation of valid datasetId within read & readPublic is trusted here
128
     *
129
     * @NoAdminRequired
130
     * @param $reportMetadata
131
     * @return array
132
     * @throws Exception
133
     */
134
    private function getData($reportMetadata)
135
    {
136
        $datasource = (int)$reportMetadata['type'];
137
        $datasetId = (int)$reportMetadata['dataset'];
138
139
        $filterWithVariables = $reportMetadata['filteroptions']; // need to remember the filter with original text variables
140
        $reportMetadata = $this->VariableService->replaceFilterVariables($reportMetadata); // replace %xx% dynamic variables
141
142
        if ($datasource === DatasourceController::DATASET_TYPE_INTERNAL_DB) {
143
            // Internal data
144
            if ($datasetId !== 0) {
145
                $result = $this->StorageService->read($datasetId, $reportMetadata);
146
            } else {
147
                $result['error'] = 'inconsistent report';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.
Loading history...
148
            }
149
        } else {
150
            // Realtime data
151
            $result = $this->DatasourceController->read($datasource, $reportMetadata);
152
        }
153
154
        unset($reportMetadata['parent']
155
            , $reportMetadata['user_id']
156
            , $reportMetadata['link']
157
            , $reportMetadata['dimension1']
158
            , $reportMetadata['dimension2']
159
            , $reportMetadata['dimension3']
160
            , $reportMetadata['value']
161
            , $reportMetadata['password']
162
            , $reportMetadata['dataset']
163
        );
164
        $result['filterApplied'] = $reportMetadata['filteroptions'];
165
        $reportMetadata['filteroptions'] = $filterWithVariables; // keep the original filters
166
        // there can be different values for no options. null during creation; empty after removal; => harmonize them
167
        $reportMetadata['chartoptions'] = ($reportMetadata['chartoptions'] === '' || $reportMetadata['chartoptions'] === 'null') ? null : $reportMetadata['chartoptions'];
168
        $reportMetadata['dataoptions'] = ($reportMetadata['dataoptions'] === '' || $reportMetadata['dataoptions'] === 'null') ? null : $reportMetadata['dataoptions'];
169
        $result['options'] = $reportMetadata;
170
        $result['thresholds'] = $this->ThresholdService->read($reportMetadata['id']);
171
        return $result;
172
    }
173
174
    /**
175
     * get the data when requested from public page
176
     *
177
     * @NoAdminRequired
178
     * @PublicPage
179
     * @UseSession
180
     * @param $token
181
     * @param $filteroptions
182
     * @param $dataoptions
183
     * @param $chartoptions
184
     * @return DataResponse|NotFoundResponse
185
     * @throws Exception
186
     */
187
    public function readPublic($token, $filteroptions, $dataoptions, $chartoptions)
188
    {
189
        $share = $this->ShareService->getReportByToken($token);
190
        if (empty($share)) {
191
            // Dataset not shared or wrong token
192
            return new NotFoundResponse();
193
        } else {
194
            if ($share['password'] !== null) {
195
                $password = $this->DataSession->getPasswordForShare($token);
196
                $passwordVerification = $this->ShareService->verifyPassword($password, $share['password']);
197
                if ($passwordVerification === false) {
198
                    return new NotFoundResponse();
199
                }
200
            }
201
            $share = $this->evaluateCanFilter($share, $filteroptions, $dataoptions, $chartoptions);
202
            $result = $this->getData($share);
203
            return new DataResponse($result, HTTP::STATUS_OK);
204
        }
205
    }
206
207
    /**
208
     * evaluate if the user did filter in the report and if he is allowed to filter (shared reports)
209
     *
210
     * @param $metadata
211
     * @param $filteroptions
212
     * @param $dataoptions
213
     * @param $chartoptions
214
     * @return mixed
215
     */
216
    private function evaluateCanFilter($metadata, $filteroptions, $dataoptions, $chartoptions)
217
    {
218
        // send current user filter options to the data request
219
        // only if the report has update-permissions
220
        // if nothing is changed by the user, the filter which is stored for the report, will be used
221
        if ($filteroptions and $filteroptions !== '' and (int)$metadata['permissions'] === Constants::PERMISSION_UPDATE) {
222
            $metadata['filteroptions'] = $filteroptions;
223
            $metadata['dataoptions'] = $dataoptions;
224
            $metadata['chartoptions'] = $chartoptions;
225
        }
226
        return $metadata;
227
    }
228
}