Passed
Push — master ( a54c4b...17bc35 )
by Joas
11:21 queued 10s
created

StoragesController::createStorage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
nc 2
nop 8
dl 0
loc 28
rs 9.7666
c 0
b 0
f 0

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
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Jesús Macias <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Juan Pablo Villafáñez <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Robin McCorkell <[email protected]>
10
 * @author Roeland Jago Douma <[email protected]>
11
 * @author Vincent Petry <[email protected]>
12
 *
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
29
namespace OCA\Files_External\Controller;
30
31
32
use OCA\Files_External\Lib\Auth\AuthMechanism;
33
use OCA\Files_External\Lib\Backend\Backend;
34
use OCA\Files_External\Lib\DefinitionParameter;
35
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
36
use OCA\Files_External\Lib\StorageConfig;
37
use OCA\Files_External\NotFoundException;
38
use OCA\Files_External\Service\StoragesService;
39
use OCP\AppFramework\Controller;
40
use OCP\AppFramework\Http;
41
use OCP\AppFramework\Http\DataResponse;
42
use OCP\Files\StorageNotAvailableException;
43
use OCP\IL10N;
44
use OCP\ILogger;
45
use OCP\IRequest;
46
47
/**
48
 * Base class for storages controllers
49
 */
50
abstract class StoragesController extends Controller {
51
52
	/**
53
	 * L10N service
54
	 *
55
	 * @var IL10N
56
	 */
57
	protected $l10n;
58
59
	/**
60
	 * Storages service
61
	 *
62
	 * @var StoragesService
63
	 */
64
	protected $service;
65
66
	/**
67
	 * @var ILogger
68
	 */
69
	protected $logger;
70
71
	/**
72
	 * Creates a new storages controller.
73
	 *
74
	 * @param string $AppName application name
75
	 * @param IRequest $request request object
76
	 * @param IL10N $l10n l10n service
77
	 * @param StoragesService $storagesService storage service
78
	 * @param ILogger $logger
79
	 */
80
	public function __construct(
81
		$AppName,
82
		IRequest $request,
83
		IL10N $l10n,
84
		StoragesService $storagesService,
85
		ILogger $logger
86
	) {
87
		parent::__construct($AppName, $request);
88
		$this->l10n = $l10n;
89
		$this->service = $storagesService;
90
		$this->logger = $logger;
91
	}
92
93
	/**
94
	 * Create a storage from its parameters
95
	 *
96
	 * @param string $mountPoint storage mount point
97
	 * @param string $backend backend identifier
98
	 * @param string $authMechanism authentication mechanism identifier
99
	 * @param array $backendOptions backend-specific options
100
	 * @param array|null $mountOptions mount-specific options
101
	 * @param array|null $applicableUsers users for which to mount the storage
102
	 * @param array|null $applicableGroups groups for which to mount the storage
103
	 * @param int|null $priority priority
104
	 *
105
	 * @return StorageConfig|DataResponse
106
	 */
107
	protected function createStorage(
108
		$mountPoint,
109
		$backend,
110
		$authMechanism,
111
		$backendOptions,
112
		$mountOptions = null,
113
		$applicableUsers = null,
114
		$applicableGroups = null,
115
		$priority = null
116
	) {
117
		try {
118
			return $this->service->createStorage(
119
				$mountPoint,
120
				$backend,
121
				$authMechanism,
122
				$backendOptions,
123
				$mountOptions,
124
				$applicableUsers,
125
				$applicableGroups,
126
				$priority
127
			);
128
		} catch (\InvalidArgumentException $e) {
129
			$this->logger->logException($e);
130
			return new DataResponse(
131
				[
132
					'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
133
				],
134
				Http::STATUS_UNPROCESSABLE_ENTITY
135
			);
136
		}
137
	}
138
139
	/**
140
	 * Validate storage config
141
	 *
142
	 * @param StorageConfig $storage storage config
143
	 *1
144
	 * @return DataResponse|null returns response in case of validation error
145
	 */
146
	protected function validate(StorageConfig $storage) {
147
		$mountPoint = $storage->getMountPoint();
148
		if ($mountPoint === '') {
149
			return new DataResponse(
150
				[
151
					'message' => (string)$this->l10n->t('Invalid mount point'),
152
				],
153
				Http::STATUS_UNPROCESSABLE_ENTITY
154
			);
155
		}
156
157
		if ($storage->getBackendOption('objectstore')) {
158
			// objectstore must not be sent from client side
159
			return new DataResponse(
160
				[
161
					'message' => (string)$this->l10n->t('Objectstore forbidden'),
162
				],
163
				Http::STATUS_UNPROCESSABLE_ENTITY
164
			);
165
		}
166
167
		/** @var Backend */
168
		$backend = $storage->getBackend();
169
		/** @var AuthMechanism */
170
		$authMechanism = $storage->getAuthMechanism();
171
		if ($backend->checkDependencies()) {
172
			// invalid backend
173
			return new DataResponse(
174
				[
175
					'message' => (string)$this->l10n->t('Invalid storage backend "%s"', [
176
						$backend->getIdentifier(),
177
					]),
178
				],
179
				Http::STATUS_UNPROCESSABLE_ENTITY
180
			);
181
		}
182
183
		if (!$backend->isVisibleFor($this->service->getVisibilityType())) {
0 ignored issues
show
Bug introduced by
$this->service->getVisibilityType() of type string is incompatible with the type integer expected by parameter $visibility of OCA\Files_External\Lib\B...Backend::isVisibleFor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

183
		if (!$backend->isVisibleFor(/** @scrutinizer ignore-type */ $this->service->getVisibilityType())) {
Loading history...
184
			// not permitted to use backend
185
			return new DataResponse(
186
				[
187
					'message' => (string)$this->l10n->t('Not permitted to use backend "%s"', [
188
						$backend->getIdentifier(),
189
					]),
190
				],
191
				Http::STATUS_UNPROCESSABLE_ENTITY
192
			);
193
		}
194
		if (!$authMechanism->isVisibleFor($this->service->getVisibilityType())) {
0 ignored issues
show
Bug introduced by
$this->service->getVisibilityType() of type string is incompatible with the type integer expected by parameter $visibility of OCA\Files_External\Lib\A...chanism::isVisibleFor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

194
		if (!$authMechanism->isVisibleFor(/** @scrutinizer ignore-type */ $this->service->getVisibilityType())) {
Loading history...
195
			// not permitted to use auth mechanism
196
			return new DataResponse(
197
				[
198
					'message' => (string)$this->l10n->t('Not permitted to use authentication mechanism "%s"', [
199
						$authMechanism->getIdentifier(),
200
					]),
201
				],
202
				Http::STATUS_UNPROCESSABLE_ENTITY
203
			);
204
		}
205
206
		if (!$backend->validateStorage($storage)) {
207
			// unsatisfied parameters
208
			return new DataResponse(
209
				[
210
					'message' => (string)$this->l10n->t('Unsatisfied backend parameters'),
211
				],
212
				Http::STATUS_UNPROCESSABLE_ENTITY
213
			);
214
		}
215
		if (!$authMechanism->validateStorage($storage)) {
216
			// unsatisfied parameters
217
			return new DataResponse(
218
				[
219
					'message' => (string)$this->l10n->t('Unsatisfied authentication mechanism parameters'),
220
				],
221
				Http::STATUS_UNPROCESSABLE_ENTITY
222
			);
223
		}
224
225
		return null;
226
	}
227
228
	protected function manipulateStorageConfig(StorageConfig $storage) {
229
		/** @var AuthMechanism */
230
		$authMechanism = $storage->getAuthMechanism();
231
		$authMechanism->manipulateStorageConfig($storage);
232
		/** @var Backend */
233
		$backend = $storage->getBackend();
234
		$backend->manipulateStorageConfig($storage);
235
	}
236
237
	/**
238
	 * Check whether the given storage is available / valid.
239
	 *
240
	 * Note that this operation can be time consuming depending
241
	 * on whether the remote storage is available or not.
242
	 *
243
	 * @param StorageConfig $storage storage configuration
244
	 * @param bool $testOnly whether to storage should only test the connection or do more things
245
	 */
246
	protected function updateStorageStatus(StorageConfig &$storage, $testOnly = true) {
247
		try {
248
			$this->manipulateStorageConfig($storage);
249
250
			/** @var Backend */
251
			$backend = $storage->getBackend();
252
			// update status (can be time-consuming)
253
			$storage->setStatus(
254
				\OC_Mount_Config::getBackendStatus(
255
					$backend->getStorageClass(),
256
					$storage->getBackendOptions(),
257
					false,
258
					$testOnly
259
				)
260
			);
261
		} catch (InsufficientDataForMeaningfulAnswerException $e) {
262
			$status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE;
263
			$storage->setStatus(
264
				$status,
265
				$this->l10n->t('Insufficient data: %s', [$e->getMessage()])
266
			);
267
		} catch (StorageNotAvailableException $e) {
268
			$storage->setStatus(
269
				$e->getCode(),
270
				$this->l10n->t('%s', [$e->getMessage()])
271
			);
272
		} catch (\Exception $e) {
273
			// FIXME: convert storage exceptions to StorageNotAvailableException
274
			$storage->setStatus(
275
				StorageNotAvailableException::STATUS_ERROR,
276
				get_class($e) . ': ' . $e->getMessage()
277
			);
278
		}
279
	}
280
281
	/**
282
	 * Get all storage entries
283
	 *
284
	 * @return DataResponse
285
	 */
286
	public function index() {
287
		$storages = $this->formatStoragesForUI($this->service->getStorages());
288
289
		return new DataResponse(
290
			$storages,
291
			Http::STATUS_OK
292
		);
293
	}
294
295
	protected function formatStoragesForUI(array $storages): array {
296
		return array_map(function ($storage) {
297
			return $this->formatStorageForUI($storage);
298
		}, $storages);
299
	}
300
301
	protected function formatStorageForUI(StorageConfig $storage): StorageConfig {
302
		/** @var DefinitionParameter[] $parameters */
303
		$parameters = array_merge($storage->getBackend()->getParameters(), $storage->getAuthMechanism()->getParameters());
304
305
		$options = $storage->getBackendOptions();
306
		foreach ($options as $key => $value) {
307
			foreach ($parameters as $parameter) {
308
				if ($parameter->getName() === $key && $parameter->getType() === DefinitionParameter::VALUE_PASSWORD) {
309
					$storage->setBackendOption($key, DefinitionParameter::UNMODIFIED_PLACEHOLDER);
310
					break;
311
				}
312
			}
313
		}
314
315
		return $storage;
316
	}
317
318
	/**
319
	 * Get an external storage entry.
320
	 *
321
	 * @param int $id storage id
322
	 * @param bool $testOnly whether to storage should only test the connection or do more things
323
	 *
324
	 * @return DataResponse
325
	 */
326
	public function show($id, $testOnly = true) {
327
		try {
328
			$storage = $this->service->getStorage($id);
329
330
			$this->updateStorageStatus($storage, $testOnly);
331
		} catch (NotFoundException $e) {
332
			return new DataResponse(
333
				[
334
					'message' => (string)$this->l10n->t('Storage with ID "%d" not found', [$id]),
335
				],
336
				Http::STATUS_NOT_FOUND
337
			);
338
		}
339
340
		return new DataResponse(
341
			$this->formatStorageForUI($storage),
342
			Http::STATUS_OK
343
		);
344
	}
345
346
	/**
347
	 * Deletes the storage with the given id.
348
	 *
349
	 * @param int $id storage id
350
	 *
351
	 * @return DataResponse
352
	 */
353
	public function destroy($id) {
354
		try {
355
			$this->service->removeStorage($id);
356
		} catch (NotFoundException $e) {
357
			return new DataResponse(
358
				[
359
					'message' => (string)$this->l10n->t('Storage with ID "%d" not found', [$id]),
360
				],
361
				Http::STATUS_NOT_FOUND
362
			);
363
		}
364
365
		return new DataResponse([], Http::STATUS_NO_CONTENT);
366
	}
367
368
}
369