These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @author Joas Schilling <[email protected]> |
||
4 | * @author Robin Appelman <[email protected]> |
||
5 | * @author Robin McCorkell <[email protected]> |
||
6 | * |
||
7 | * @copyright Copyright (c) 2016, ownCloud GmbH. |
||
8 | * @license AGPL-3.0 |
||
9 | * |
||
10 | * This code is free software: you can redistribute it and/or modify |
||
11 | * it under the terms of the GNU Affero General Public License, version 3, |
||
12 | * as published by the Free Software Foundation. |
||
13 | * |
||
14 | * This program is distributed in the hope that it will be useful, |
||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | * GNU Affero General Public License for more details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU Affero General Public License, version 3, |
||
20 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
||
21 | * |
||
22 | */ |
||
23 | |||
24 | namespace OCA\Files_External\Service; |
||
25 | |||
26 | use OCP\DB\QueryBuilder\IQueryBuilder; |
||
27 | use OCP\IDBConnection; |
||
28 | use OCP\Security\ICrypto; |
||
29 | |||
30 | /** |
||
31 | * Stores the mount config in the database |
||
32 | */ |
||
33 | class DBConfigService { |
||
34 | const MOUNT_TYPE_ADMIN = 1; |
||
35 | const MOUNT_TYPE_PERSONAl = 2; |
||
36 | |||
37 | const APPLICABLE_TYPE_GLOBAL = 1; |
||
38 | const APPLICABLE_TYPE_GROUP = 2; |
||
39 | const APPLICABLE_TYPE_USER = 3; |
||
40 | |||
41 | /** |
||
42 | * @var IDBConnection |
||
43 | */ |
||
44 | private $connection; |
||
45 | |||
46 | /** |
||
47 | * @var ICrypto |
||
48 | */ |
||
49 | private $crypto; |
||
50 | |||
51 | /** |
||
52 | * DBConfigService constructor. |
||
53 | * |
||
54 | * @param IDBConnection $connection |
||
55 | * @param ICrypto $crypto |
||
56 | */ |
||
57 | public function __construct(IDBConnection $connection, ICrypto $crypto) { |
||
58 | $this->connection = $connection; |
||
59 | $this->crypto = $crypto; |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * @param int $mountId |
||
64 | * @return array |
||
65 | */ |
||
66 | public function getMountById($mountId) { |
||
67 | $builder = $this->connection->getQueryBuilder(); |
||
68 | $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type']) |
||
69 | ->from('external_mounts', 'm') |
||
70 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
71 | $mounts = $this->getMountsFromQuery($query); |
||
72 | if (count($mounts) > 0) { |
||
73 | return $mounts[0]; |
||
74 | } else { |
||
75 | return null; |
||
76 | } |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * Get all configured mounts |
||
81 | * |
||
82 | * @return array |
||
83 | */ |
||
84 | public function getAllMounts() { |
||
85 | $builder = $this->connection->getQueryBuilder(); |
||
86 | $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type']) |
||
87 | ->from('external_mounts'); |
||
88 | return $this->getMountsFromQuery($query); |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Get admin defined mounts |
||
93 | * |
||
94 | * @return array |
||
95 | */ |
||
96 | public function getAdminMounts() { |
||
97 | $builder = $this->connection->getQueryBuilder(); |
||
98 | $query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type']) |
||
99 | ->from('external_mounts') |
||
100 | ->where($builder->expr()->eq('type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, IQueryBuilder::PARAM_INT))); |
||
101 | return $this->getMountsFromQuery($query); |
||
102 | } |
||
103 | |||
104 | protected function getForQuery(IQueryBuilder $builder, $type, $value) { |
||
105 | $query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type']) |
||
106 | ->from('external_mounts', 'm') |
||
107 | ->innerJoin('m', 'external_applicable', 'a', $builder->expr()->eq('m.mount_id', 'a.mount_id')) |
||
108 | ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT))); |
||
109 | |||
110 | View Code Duplication | if (is_null($value)) { |
|
0 ignored issues
–
show
|
|||
111 | $query = $query->andWhere($builder->expr()->isNull('a.value')); |
||
112 | } else { |
||
113 | $query = $query->andWhere($builder->expr()->eq('a.value', $builder->createNamedParameter($value))); |
||
114 | } |
||
115 | |||
116 | return $query; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Get mounts by applicable |
||
121 | * |
||
122 | * @param int $type any of the self::APPLICABLE_TYPE_ constants |
||
123 | * @param string|null $value user_id, group_id or null for global mounts |
||
124 | * @return array |
||
125 | */ |
||
126 | public function getMountsFor($type, $value) { |
||
127 | $builder = $this->connection->getQueryBuilder(); |
||
128 | $query = $this->getForQuery($builder, $type, $value); |
||
129 | |||
130 | return $this->getMountsFromQuery($query); |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * Get admin defined mounts by applicable |
||
135 | * |
||
136 | * @param int $type any of the self::APPLICABLE_TYPE_ constants |
||
137 | * @param string|null $value user_id, group_id or null for global mounts |
||
138 | * @return array |
||
139 | */ |
||
140 | View Code Duplication | public function getAdminMountsFor($type, $value) { |
|
141 | $builder = $this->connection->getQueryBuilder(); |
||
142 | $query = $this->getForQuery($builder, $type, $value); |
||
143 | $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, IQueryBuilder::PARAM_INT))); |
||
144 | |||
145 | return $this->getMountsFromQuery($query); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Get admin defined mounts for multiple applicable |
||
150 | * |
||
151 | * @param int $type any of the self::APPLICABLE_TYPE_ constants |
||
152 | * @param string[] $values user_ids or group_ids |
||
153 | * @return array |
||
154 | */ |
||
155 | public function getAdminMountsForMultiple($type, array $values) { |
||
156 | $builder = $this->connection->getQueryBuilder(); |
||
157 | $params = array_map(function ($value) use ($builder) { |
||
158 | return $builder->createNamedParameter($value, IQueryBuilder::PARAM_STR); |
||
159 | }, $values); |
||
160 | |||
161 | $query = $builder->select(['m.mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'm.type']) |
||
162 | ->from('external_mounts', 'm') |
||
163 | ->innerJoin('m', 'external_applicable', 'a', $builder->expr()->eq('m.mount_id', 'a.mount_id')) |
||
164 | ->where($builder->expr()->eq('a.type', $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT))) |
||
165 | ->andWhere($builder->expr()->in('a.value', $params)); |
||
166 | $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_ADMIN, IQueryBuilder::PARAM_INT))); |
||
167 | |||
168 | return $this->getMountsFromQuery($query); |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * Get user defined mounts by applicable |
||
173 | * |
||
174 | * @param int $type any of the self::APPLICABLE_TYPE_ constants |
||
175 | * @param string|null $value user_id, group_id or null for global mounts |
||
176 | * @return array |
||
177 | */ |
||
178 | View Code Duplication | public function getUserMountsFor($type, $value) { |
|
179 | $builder = $this->connection->getQueryBuilder(); |
||
180 | $query = $this->getForQuery($builder, $type, $value); |
||
181 | $query->andWhere($builder->expr()->eq('m.type', $builder->expr()->literal(self::MOUNT_TYPE_PERSONAl, IQueryBuilder::PARAM_INT))); |
||
182 | |||
183 | return $this->getMountsFromQuery($query); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Add a mount to the database |
||
188 | * |
||
189 | * @param string $mountPoint |
||
190 | * @param string $storageBackend |
||
191 | * @param string $authBackend |
||
192 | * @param int $priority |
||
193 | * @param int $type self::MOUNT_TYPE_ADMIN or self::MOUNT_TYPE_PERSONAL |
||
194 | * @return int the id of the new mount |
||
195 | */ |
||
196 | public function addMount($mountPoint, $storageBackend, $authBackend, $priority, $type) { |
||
197 | if (!$priority) { |
||
198 | $priority = 100; |
||
199 | } |
||
200 | $builder = $this->connection->getQueryBuilder(); |
||
201 | $query = $builder->insert('external_mounts') |
||
202 | ->values([ |
||
203 | 'mount_point' => $builder->createNamedParameter($mountPoint, IQueryBuilder::PARAM_STR), |
||
204 | 'storage_backend' => $builder->createNamedParameter($storageBackend, IQueryBuilder::PARAM_STR), |
||
205 | 'auth_backend' => $builder->createNamedParameter($authBackend, IQueryBuilder::PARAM_STR), |
||
206 | 'priority' => $builder->createNamedParameter($priority, IQueryBuilder::PARAM_INT), |
||
207 | 'type' => $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT) |
||
208 | ]); |
||
209 | $query->execute(); |
||
210 | return (int)$this->connection->lastInsertId('*PREFIX*external_mounts'); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * Remove a mount from the database |
||
215 | * |
||
216 | * @param int $mountId |
||
217 | */ |
||
218 | public function removeMount($mountId) { |
||
219 | $builder = $this->connection->getQueryBuilder(); |
||
220 | $query = $builder->delete('external_mounts') |
||
221 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
222 | $query->execute(); |
||
223 | |||
224 | $query = $builder->delete('external_applicable') |
||
225 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
226 | $query->execute(); |
||
227 | |||
228 | $query = $builder->delete('external_config') |
||
229 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
230 | $query->execute(); |
||
231 | |||
232 | $query = $builder->delete('external_options') |
||
233 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
234 | $query->execute(); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * @param int $mountId |
||
239 | * @param string $newMountPoint |
||
240 | */ |
||
241 | View Code Duplication | public function setMountPoint($mountId, $newMountPoint) { |
|
242 | $builder = $this->connection->getQueryBuilder(); |
||
243 | |||
244 | $query = $builder->update('external_mounts') |
||
245 | ->set('mount_point', $builder->createNamedParameter($newMountPoint)) |
||
246 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
247 | |||
248 | $query->execute(); |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * @param int $mountId |
||
253 | * @param string $newAuthBackend |
||
254 | */ |
||
255 | View Code Duplication | public function setAuthBackend($mountId, $newAuthBackend) { |
|
256 | $builder = $this->connection->getQueryBuilder(); |
||
257 | |||
258 | $query = $builder->update('external_mounts') |
||
259 | ->set('auth_backend', $builder->createNamedParameter($newAuthBackend)) |
||
260 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))); |
||
261 | |||
262 | $query->execute(); |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * @param int $mountId |
||
267 | * @param string $key |
||
268 | * @param string $value |
||
269 | */ |
||
270 | public function setConfig($mountId, $key, $value) { |
||
271 | if ($key === 'password') { |
||
272 | $value = $this->encryptValue($value); |
||
273 | } |
||
274 | $count = $this->connection->insertIfNotExist('*PREFIX*external_config', [ |
||
275 | 'mount_id' => $mountId, |
||
276 | 'key' => $key, |
||
277 | 'value' => $value |
||
278 | ], ['mount_id', 'key']); |
||
279 | View Code Duplication | if ($count === 0) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
280 | $builder = $this->connection->getQueryBuilder(); |
||
281 | $query = $builder->update('external_config') |
||
282 | ->set('value', $builder->createNamedParameter($value, IQueryBuilder::PARAM_STR)) |
||
283 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))) |
||
284 | ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, IQueryBuilder::PARAM_STR))); |
||
285 | $query->execute(); |
||
286 | } |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * @param int $mountId |
||
291 | * @param string $key |
||
292 | * @param string $value |
||
293 | */ |
||
294 | public function setOption($mountId, $key, $value) { |
||
295 | |||
296 | $count = $this->connection->insertIfNotExist('*PREFIX*external_options', [ |
||
297 | 'mount_id' => $mountId, |
||
298 | 'key' => $key, |
||
299 | 'value' => json_encode($value) |
||
300 | ], ['mount_id', 'key']); |
||
301 | View Code Duplication | if ($count === 0) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
302 | $builder = $this->connection->getQueryBuilder(); |
||
303 | $query = $builder->update('external_options') |
||
304 | ->set('value', $builder->createNamedParameter(json_encode($value), IQueryBuilder::PARAM_STR)) |
||
305 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))) |
||
306 | ->andWhere($builder->expr()->eq('key', $builder->createNamedParameter($key, IQueryBuilder::PARAM_STR))); |
||
307 | $query->execute(); |
||
308 | } |
||
309 | } |
||
310 | |||
311 | public function addApplicable($mountId, $type, $value) { |
||
312 | $this->connection->insertIfNotExist('*PREFIX*external_applicable', [ |
||
313 | 'mount_id' => $mountId, |
||
314 | 'type' => $type, |
||
315 | 'value' => $value |
||
316 | ], ['mount_id', 'type', 'value']); |
||
317 | } |
||
318 | |||
319 | public function removeApplicable($mountId, $type, $value) { |
||
320 | $builder = $this->connection->getQueryBuilder(); |
||
321 | $query = $builder->delete('external_applicable') |
||
322 | ->where($builder->expr()->eq('mount_id', $builder->createNamedParameter($mountId, IQueryBuilder::PARAM_INT))) |
||
323 | ->andWhere($builder->expr()->eq('type', $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT))); |
||
324 | |||
325 | View Code Duplication | if (is_null($value)) { |
|
326 | $query = $query->andWhere($builder->expr()->isNull('value')); |
||
327 | } else { |
||
328 | $query = $query->andWhere($builder->expr()->eq('value', $builder->createNamedParameter($value, IQueryBuilder::PARAM_STR))); |
||
329 | } |
||
330 | |||
331 | $query->execute(); |
||
332 | } |
||
333 | |||
334 | private function getMountsFromQuery(IQueryBuilder $query) { |
||
335 | $result = $query->execute(); |
||
336 | $mounts = $result->fetchAll(); |
||
337 | $uniqueMounts = []; |
||
338 | foreach ($mounts as $mount) { |
||
339 | $id = $mount['mount_id']; |
||
340 | if (!isset($uniqueMounts[$id])) { |
||
341 | $uniqueMounts[$id] = $mount; |
||
342 | } |
||
343 | } |
||
344 | $uniqueMounts = array_values($uniqueMounts); |
||
345 | |||
346 | $mountIds = array_map(function ($mount) { |
||
347 | return $mount['mount_id']; |
||
348 | }, $uniqueMounts); |
||
349 | $mountIds = array_values(array_unique($mountIds)); |
||
350 | |||
351 | $applicable = $this->getApplicableForMounts($mountIds); |
||
352 | $config = $this->getConfigForMounts($mountIds); |
||
353 | $options = $this->getOptionsForMounts($mountIds); |
||
354 | |||
355 | return array_map(function ($mount, $applicable, $config, $options) { |
||
356 | $mount['type'] = (int)$mount['type']; |
||
357 | $mount['priority'] = (int)$mount['priority']; |
||
358 | $mount['applicable'] = $applicable; |
||
359 | $mount['config'] = $config; |
||
360 | $mount['options'] = $options; |
||
361 | return $mount; |
||
362 | }, $uniqueMounts, $applicable, $config, $options); |
||
363 | } |
||
364 | |||
365 | /** |
||
366 | * Get mount options from a table grouped by mount id |
||
367 | * |
||
368 | * @param string $table |
||
369 | * @param string[] $fields |
||
370 | * @param int[] $mountIds |
||
371 | * @return array [$mountId => [['field1' => $value1, ...], ...], ...] |
||
372 | */ |
||
373 | private function selectForMounts($table, array $fields, array $mountIds) { |
||
374 | if (count($mountIds) === 0) { |
||
375 | return []; |
||
376 | } |
||
377 | $builder = $this->connection->getQueryBuilder(); |
||
378 | $fields[] = 'mount_id'; |
||
379 | $placeHolders = array_map(function ($id) use ($builder) { |
||
380 | return $builder->createPositionalParameter($id, IQueryBuilder::PARAM_INT); |
||
381 | }, $mountIds); |
||
382 | $query = $builder->select($fields) |
||
383 | ->from($table) |
||
384 | ->where($builder->expr()->in('mount_id', $placeHolders)); |
||
385 | $rows = $query->execute()->fetchAll(); |
||
386 | |||
387 | $result = []; |
||
388 | foreach ($mountIds as $mountId) { |
||
389 | $result[$mountId] = []; |
||
390 | } |
||
391 | foreach ($rows as $row) { |
||
392 | if (isset($row['type'])) { |
||
393 | $row['type'] = (int)$row['type']; |
||
394 | } |
||
395 | $result[$row['mount_id']][] = $row; |
||
396 | } |
||
397 | return $result; |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * @param int[] $mountIds |
||
402 | * @return array [$id => [['type' => $type, 'value' => $value], ...], ...] |
||
403 | */ |
||
404 | public function getApplicableForMounts($mountIds) { |
||
405 | return $this->selectForMounts('external_applicable', ['type', 'value'], $mountIds); |
||
406 | } |
||
407 | |||
408 | /** |
||
409 | * @param int[] $mountIds |
||
410 | * @return array [$id => ['key1' => $value1, ...], ...] |
||
411 | */ |
||
412 | public function getConfigForMounts($mountIds) { |
||
413 | $mountConfigs = $this->selectForMounts('external_config', ['key', 'value'], $mountIds); |
||
414 | return array_map([$this, 'createKeyValueMap'], $mountConfigs); |
||
415 | } |
||
416 | |||
417 | /** |
||
418 | * @param int[] $mountIds |
||
419 | * @return array [$id => ['key1' => $value1, ...], ...] |
||
420 | */ |
||
421 | public function getOptionsForMounts($mountIds) { |
||
422 | $mountOptions = $this->selectForMounts('external_options', ['key', 'value'], $mountIds); |
||
423 | $optionsMap = array_map([$this, 'createKeyValueMap'], $mountOptions); |
||
424 | return array_map(function (array $options) { |
||
425 | return array_map(function ($option) { |
||
426 | return json_decode($option); |
||
427 | }, $options); |
||
428 | }, $optionsMap); |
||
429 | } |
||
430 | |||
431 | /** |
||
432 | * @param array $keyValuePairs [['key'=>$key, 'value=>$value], ...] |
||
433 | * @return array ['key1' => $value1, ...] |
||
434 | */ |
||
435 | private function createKeyValueMap(array $keyValuePairs) { |
||
436 | $decryptedPairts = array_map(function ($pair) { |
||
437 | if ($pair['key'] === 'password') { |
||
438 | $pair['value'] = $this->decryptValue($pair['value']); |
||
439 | } |
||
440 | return $pair; |
||
441 | }, $keyValuePairs); |
||
442 | $keys = array_map(function ($pair) { |
||
443 | return $pair['key']; |
||
444 | }, $decryptedPairts); |
||
445 | $values = array_map(function ($pair) { |
||
446 | return $pair['value']; |
||
447 | }, $decryptedPairts); |
||
448 | |||
449 | return array_combine($keys, $values); |
||
450 | } |
||
451 | |||
452 | private function encryptValue($value) { |
||
453 | return $this->crypto->encrypt($value); |
||
454 | } |
||
455 | |||
456 | private function decryptValue($value) { |
||
457 | try { |
||
458 | return $this->crypto->decrypt($value); |
||
459 | } catch (\Exception $e) { |
||
460 | return $value; |
||
461 | } |
||
462 | } |
||
463 | } |
||
464 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.