Passed
Push — master ( cf86d0...003506 )
by Marcel
03:25
created

ApiDataController::index()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
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 0
dl 0
loc 2
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\Controller;
13
14
use OCA\Analytics\Activity\ActivityManager;
15
use OCA\Analytics\Db\StorageMapper;
16
use OCA\Analytics\Service\DatasetService;
17
use OCP\AppFramework\ApiController;
18
use OCP\AppFramework\Http;
19
use OCP\AppFramework\Http\DataResponse;
20
use OCP\ILogger;
21
use OCP\IRequest;
22
use OCP\IUserSession;
23
24
class ApiDataController extends ApiController
25
{
26
    const UNKNOWN = 9001;
27
    const MISSING_PARAM = 9002;
28
    const NOT_FOUND = 9003;
29
    const NOT_ALLOWED = 9004;
30
31
    protected $errors = [];
32
    private $logger;
33
    private $userSession;
34
    private $ActivityManager;
35
    private $DatasetService;
36
    private $StorageController;
37
	private $StorageMapper;
38
39
    public function __construct(
40
        $appName,
41
        IRequest $request,
42
        ILogger $logger,
43
        IUserSession $userSession,
44
        ActivityManager $ActivityManager,
45
        DatasetService $DatasetService,
46
        StorageController $StorageController,
47
		StorageMapper $StorageMapper
48
    )
49
    {
50
        parent::__construct(
51
            $appName,
52
            $request,
53
            'POST'
54
            );
55
        $this->logger = $logger;
56
        $this->userSession = $userSession;
57
        $this->ActivityManager = $ActivityManager;
58
        $this->DatasetService = $DatasetService;
59
        $this->StorageController = $StorageController;
60
        $this->StorageMapper = $StorageMapper;
61
    }
62
63
    /**
64
     * add data via there database names
65
     * @CORS
66
     * @NoCSRFRequired
67
     * @NoAdminRequired
68
     * @param int $datasetId
69
     * @return DataResponse
70
     * @throws \Exception
71
     */
72
    public function addData(int $datasetId)
73
    {
74
        $params = $this->request->getParams();
75
        $datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
76
77
        $this->deriveMaintenancePossible($datasetMetadata);
78
79
        if (!isset($params['dimension1'])) {
80
            $this->errors[] = 'Dimension 1 required';
81
        } elseif (!isset($params['dimension2'])) {
82
            $this->errors[] = 'Dimension 2 required';
83
        } elseif (!isset($params['dimension3'])) {
84
            $this->errors[] = 'Dimension 3 required';
85
        }
86
        if (!empty($this->errors)) {
87
            return $this->requestResponse(false, self::MISSING_PARAM, implode(',', $this->errors));
88
        }
89
90
        $this->StorageController->update($datasetId, $params['dimension1'], $params['dimension2'], $params['dimension3']);
91
        $this->ActivityManager->triggerEvent($datasetId, ActivityManager::OBJECT_DATA, ActivityManager::SUBJECT_DATA_ADD_API);
92
93
        return $this->requestResponse(
94
            true,
95
            Http::STATUS_OK,
96
            'Data update successfull');
97
    }
98
99
    /**
100
     * add data via there real field names
101
     * @CORS
102
     * @NoCSRFRequired
103
     * @NoAdminRequired
104
     * @param int $datasetId
105
     * @return DataResponse
106
     * @throws \Exception
107
     */
108
    public function addDataV2(int $datasetId)
109
    {
110
        $message = 'No -data- parameter';
111
        $params = $this->request->getParams();
112
        $datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
113
114
        $this->deriveMaintenancePossible($datasetMetadata);
115
116
        foreach ($params['data'] as $dataArray) {
117
118
            $dimension1 = $this->deriveParameterNames($dataArray, $datasetMetadata, 'dimension1');
119
            $dimension2 = $this->deriveParameterNames($dataArray, $datasetMetadata, 'dimension2');
120
            $value = $this->deriveParameterNames($dataArray, $datasetMetadata, 'value');
121
122
            if (!empty($this->errors)) {
123
                return $this->requestResponse(false, self::MISSING_PARAM, implode(',', $this->errors));
124
            }
125
126
            $this->StorageController->update($datasetId, $dimension1, $dimension2, $value);
127
            $this->ActivityManager->triggerEvent($datasetId, ActivityManager::OBJECT_DATA, ActivityManager::SUBJECT_DATA_ADD_API);
128
            $message = 'Data update successfull';
129
        }
130
131
        return $this->requestResponse(
132
            true,
133
            Http::STATUS_OK,
134
            $message);
135
    }
136
137
    /**
138
     * delete data
139
     * @CORS
140
     * @NoCSRFRequired
141
     * @NoAdminRequired
142
     * @param int $datasetId
143
     * @return DataResponse
144
     * @throws \Exception
145
     */
146
    public function deleteDataV2(int $datasetId)
147
    {
148
        $message = 'No -delete- parameter';
149
        $params = $this->request->getParams();
150
        //$this->logger->debug('array: ' . json_encode($params));
151
        $datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
152
153
        $this->deriveMaintenancePossible($datasetMetadata);
154
155
        foreach ($params['delete'] as $dataArray) {
156
            $dimension1 = $this->deriveParameterNames($dataArray, $datasetMetadata, 'dimension1');
157
            $dimension2 = $this->deriveParameterNames($dataArray, $datasetMetadata, 'dimension2');
158
159
            if (!empty($this->errors)) {
160
                return $this->requestResponse(false, self::MISSING_PARAM, implode(',', $this->errors));
161
            }
162
163
            $this->StorageController->delete($datasetId, $dimension1, $dimension2);
164
            $message = 'Data deleted';
165
        }
166
167
        return $this->requestResponse(
168
            true,
169
            Http::STATUS_OK,
170
            $message);
171
    }
172
173
174
    ///
175
    /// API V3
176
    ///
177
178
    /**
179
     * get all data of a dataset and respect filter options
180
     * @CORS
181
     * @NoCSRFRequired
182
     * @NoAdminRequired
183
     * @return DataResponse
184
     * @throws \Exception
185
     */
186
    public function dataGetV3(int $datasetId)
187
    {
188
        $params = $this->request->getParams();
189
        $datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
190
191
        if (!empty($datasetMetadata)) {
192
            $options = json_decode($params['filteroptions'], true);
193
            $allData = $this->StorageMapper->read($datasetMetadata['id'], $options);
194
195
            return new DataResponse($allData, HTTP::STATUS_OK);
196
        } else {
197
            return new DataResponse([
198
                'message' => 'No data available for given $datasetId',
199
            ], HTTP::STATUS_OK);
200
        }
201
    }
202
203
    /**
204
     * delete data
205
     * @CORS
206
     * @NoCSRFRequired
207
     * @NoAdminRequired
208
     * @param int $datasetId
209
     * @return DataResponse
210
     * @throws \Exception
211
     */
212
    public function dataDeleteV3(int $datasetId)
213
    {
214
        return $this->deleteDataV2($datasetId);
215
    }
216
217
    /**
218
     * add data via there real field names
219
     * @CORS
220
     * @NoCSRFRequired
221
     * @NoAdminRequired
222
     * @param int $datasetId
223
     * @return DataResponse
224
     * @throws \Exception
225
     */
226
    public function dataAddV3(int $datasetId)
227
    {
228
        return $this->addDataV2($datasetId);
229
    }
230
231
    /**
232
     * list datasets
233
     * @CORS
234
     * @NoCSRFRequired
235
     * @NoAdminRequired
236
     * @return DataResponse
237
     * @throws \Exception
238
     */
239
    public function datasetsIndexV3()
240
    {
241
        return $this->DatasetService->index();
242
    }
243
244
    /**
245
     * read data of a dataset with additional information for table and series
246
     * @CORS
247
     * @NoCSRFRequired
248
     * @NoAdminRequired
249
     * @return DataResponse
250
     * @throws \Exception
251
     */
252
    public function datasetsDetailV3(int $datasetId)
253
    {
254
        $datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
255
256
        if (!empty($datasetMetadata)) {
257
            $allData = $this->StorageController->read($datasetMetadata);
258
            $series = array_values(array_unique(array_map('array_shift', $allData['data'])));
259
260
            return new DataResponse([
261
                'header' => $allData['header'],
262
                'dimensions' => $allData['dimensions'],
263
                'series' => $series,
264
            ], HTTP::STATUS_OK);
265
        } else {
266
            return new DataResponse([
267
                'message' => 'No metadata available for given $datasetId',
268
            ], HTTP::STATUS_OK);
269
        }
270
    }
271
272
273
    /**
274
     * derive if the parameter is technical or the free text description from the report
275
     * @param $data
276
     * @param $datasetMetadata
277
     * @param $dimension
278
     * @return array | bool
279
     */
280
    protected function deriveParameterNames($data, $datasetMetadata, $dimension)
281
    {
282
        if (isset($data[$dimension])) {
283
            return $data[$dimension];
284
        } elseif (isset($data[$datasetMetadata[$dimension]])) {
285
            return $data[$datasetMetadata[$dimension]];
286
        } else {
287
            $this->errors[] = $dimension . ' required';
288
            return false;
289
        }
290
    }
291
292
    /**
293
     * derive if maintenance is possible
294
     * @param $datasetMetadata
295
     * @return DataResponse | bool
296
     */
297
    protected function deriveMaintenancePossible($datasetMetadata)
298
    {
299
        if (empty($datasetMetadata)) {
300
            $this->errors[] = 'Unknown report or dataset';
301
            return $this->requestResponse(false, self::NOT_FOUND, implode(',', $this->errors));
302
        } elseif ((int)$datasetMetadata['type'] !== DatasourceController::DATASET_TYPE_INTERNAL_DB) {
303
            $this->errors[] = 'Report does not allow data maintenance';
304
            return $this->requestResponse(false, self::NOT_ALLOWED, implode(',', $this->errors));
305
        }
306
        return true;
307
    }
308
309
    /**
310
     * @param bool $success
311
     * @param int|null $code
312
     * @param string|null $message
313
     * @return DataResponse
314
     */
315
    protected function requestResponse($success, $code = null, $message = null)
316
    {
317
        if (!$success) {
318
            if ($code === null) {
319
                $code = self::UNKNOWN;
320
            }
321
            $array = [
322
                'success' => false,
323
                'error' => ['code' => $code,
324
                    'message' => $message
325
                ]
326
            ];
327
        } else {
328
            $array = [
329
                'success' => true,
330
                'message' => $message
331
            ];
332
        }
333
        $response = new DataResponse();
334
        $response->setData($array)->render();
335
        return $response;
336
    }
337
    // curl -u Admin:2sroW-SxRcK-AmdsF-RYMJ5-CKSyf -d '{"dimension1": "x", "dimension2": "x", "dimension3": "333,3"}' -X POST -H "Content-Type: application/json" http://nc18/nextcloud/apps/analytics/api/1.0/adddata/158
338
    // curl -u Admin:2sroW-SxRcK-AmdsF-RYMJ5-CKSyf -d '[{"Spalte 1": "x", "Spalte 2": "x", "toller wert": "333,3"}]' -X POST -H "Content-Type: application/json" http://nc18/nextcloud/apps/analytics/api/2.0/adddata/158
339
    // curl -u Admin:2sroW-SxRcK-AmdsF-RYMJ5-CKSyf -d '{"data":[{"Spalte 1": "a", "Spalte 2": "a", "toller wert": "1"}, {"dimension1": "b", "dimension2": "b", "value": "2"}]}' -X POST -H "Content-Type: application/json" http://nc18/nextcloud/apps/analytics/api/2.0/adddata/158
340
341
    // curl -u Admin:2sroW-SxRcK-AmdsF-RYMJ5-CKSyf -d '{"delete":[{"dimension1": "a", "dimension2": "a"}]}' -X POST -H "Content-Type: application/json" http://nc18/nextcloud/apps/analytics/api/2.0/deletedata/158
342
    // curl -u Admin:2sroW-SxRcK-AmdsF-RYMJ5-CKSyf -d '{"del":[{"dimension1": "a", "dimension2": "a"}]}' -X POST -H "Content-Type: application/json" http://nc18/nextcloud/apps/analytics/api/2.0/deletedata/158
343
344
}
345