Passed
Push — master ( ac5f58...0c3cf2 )
by Marcel
02:26
created

ApiDataController::data()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 10
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 14
rs 9.9332
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
	 * list datasets
175
	 * @CORS
176
	 * @NoCSRFRequired
177
	 * @NoAdminRequired
178
	 * @return DataResponse
179
	 * @throws \Exception
180
	 */
181
	public function index() {
182
		return $this->DatasetService->index();
183
	}
184
185
	/**
186
	 * read data of a dataset with additional information for table and series
187
	 * @CORS
188
	 * @NoCSRFRequired
189
	 * @NoAdminRequired
190
	 * @return DataResponse
191
	 * @throws \Exception
192
	 */
193
	public function detail(int $datasetId)
194
	{
195
		$datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
196
197
		if (!empty($datasetMetadata)) {
198
			$allData = $this->StorageController->read($datasetMetadata);
199
			$series = array_values(array_unique(array_map('array_shift', $allData['data'])));
200
201
			return new DataResponse([
202
				'header' => $allData['header'],
203
				'dimensions' => $allData['dimensions'],
204
				'series' => $series,
205
			], HTTP::STATUS_OK);
206
		} else {
207
			return new DataResponse([
208
				'message' => 'No metadata available for given $datasetId',
209
			], HTTP::STATUS_OK);
210
		}
211
	}
212
213
	/**
214
	 * get all data of a dataset and respect filter options
215
	 * @CORS
216
	 * @NoCSRFRequired
217
	 * @NoAdminRequired
218
	 * @return DataResponse
219
	 * @throws \Exception
220
	 */
221
	public function data(int $datasetId)
222
	{
223
		$params = $this->request->getParams();
224
		$datasetMetadata = $this->DatasetService->getOwnDataset($datasetId);
225
226
		if (!empty($datasetMetadata)) {
227
			$options = json_decode($params['filteroptions'], true);
228
			$allData = $this->StorageMapper->read($datasetMetadata['id'], $options);
229
230
			return new DataResponse($allData, HTTP::STATUS_OK);
231
		} else {
232
			return new DataResponse([
233
				'message' => 'No data available for given $datasetId',
234
			], HTTP::STATUS_OK);
235
		}
236
	}
237
238
    /**
239
     * derive if the parameter is technical or the free text description from the report
240
     * @param $data
241
     * @param $datasetMetadata
242
     * @param $dimension
243
     * @return array | bool
244
     */
245
    protected function deriveParameterNames($data, $datasetMetadata, $dimension)
246
    {
247
        if (isset($data[$dimension])) {
248
            return $data[$dimension];
249
        } elseif (isset($data[$datasetMetadata[$dimension]])) {
250
            return $data[$datasetMetadata[$dimension]];
251
        } else {
252
            $this->errors[] = $dimension . ' required';
253
            return false;
254
        }
255
    }
256
257
    /**
258
     * derive if maintenance is possible
259
     * @param $datasetMetadata
260
     * @return DataResponse | bool
261
     */
262
    protected function deriveMaintenancePossible($datasetMetadata)
263
    {
264
        if (empty($datasetMetadata)) {
265
            $this->errors[] = 'Unknown report or dataset';
266
            return $this->requestResponse(false, self::NOT_FOUND, implode(',', $this->errors));
267
        } elseif ((int)$datasetMetadata['type'] !== DatasourceController::DATASET_TYPE_INTERNAL_DB) {
268
            $this->errors[] = 'Report does not allow data maintenance';
269
            return $this->requestResponse(false, self::NOT_ALLOWED, implode(',', $this->errors));
270
        }
271
        return true;
272
    }
273
274
    /**
275
     * @param bool $success
276
     * @param int|null $code
277
     * @param string|null $message
278
     * @return DataResponse
279
     */
280
    protected function requestResponse($success, $code = null, $message = null)
281
    {
282
        if (!$success) {
283
            if ($code === null) {
284
                $code = self::UNKNOWN;
285
            }
286
            $array = [
287
                'success' => false,
288
                'error' => ['code' => $code,
289
                    'message' => $message
290
                ]
291
            ];
292
        } else {
293
            $array = [
294
                'success' => true,
295
                'message' => $message
296
            ];
297
        }
298
        $response = new DataResponse();
299
        $response->setData($array)->render();
300
        return $response;
301
    }
302
    // 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
303
    // 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
304
    // 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
305
306
    // 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
307
    // 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
308
309
}
310