Completed
Pull Request — master (#32303)
by Victor
10:05
created

OcmController::createShare()   C

Complexity

Conditions 13
Paths 39

Size

Total Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 39
nop 11
dl 0
loc 98
rs 5.3369
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
 * @author Viktar Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2018, ownCloud GmbH
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OCA\FederatedFileSharing\Controller;
23
24
use OCA\FederatedFileSharing\Address;
25
use OCA\FederatedFileSharing\AddressHandler;
26
use OCA\FederatedFileSharing\Middleware\OcmMiddleware;
27
use OCA\FederatedFileSharing\Ocm\Exception\BadRequestException;
28
use OCA\FederatedFileSharing\Ocm\Exception\NotImplementedException;
29
use OCA\FederatedFileSharing\Ocm\Notification\FileNotification;
30
use OCP\AppFramework\Http\JSONResponse;
31
use OCA\FederatedFileSharing\FedShareManager;
32
use OCA\FederatedFileSharing\Ocm\Exception\OcmException;
33
use OCP\AppFramework\Controller;
34
use OCP\AppFramework\Http;
35
use OCP\ILogger;
36
use OCP\IRequest;
37
use OCP\IURLGenerator;
38
use OCP\IUserManager;
39
40
/**
41
 * Class OcmController
42
 *
43
 * @package OCA\FederatedFileSharing\Controller
44
 */
45
class OcmController extends Controller {
46
	const API_VERSION = '1.0-proposal1';
47
48
	/**
49
	 * @var OcmMiddleware
50
	 */
51
	private $ocmMiddleware;
52
53
	/**
54
	 * @var IURLGenerator
55
	 */
56
	protected $urlGenerator;
57
58
	/**
59
	 * @var IUserManager
60
	 */
61
	protected $userManager;
62
63
	/**
64
	 * @var AddressHandler
65
	 */
66
	protected $addressHandler;
67
68
	/**
69
	 * @var FedShareManager
70
	 */
71
	protected $fedShareManager;
72
73
	/**
74
	 * @var ILogger
75
	 */
76
	protected $logger;
77
78
	/**
79
	 * OcmController constructor.
80
	 *
81
	 * @param string $appName
82
	 * @param IRequest $request
83
	 * @param OcmMiddleware $ocmMiddleware
84
	 * @param IURLGenerator $urlGenerator
85
	 * @param IUserManager $userManager
86
	 * @param AddressHandler $addressHandler
87
	 * @param FedShareManager $fedShareManager
88
	 * @param ILogger $logger
89
	 */
90 View Code Duplication
	public function __construct($appName,
91
									IRequest $request,
92
									OcmMiddleware $ocmMiddleware,
93
									IURLGenerator $urlGenerator,
94
									IUserManager $userManager,
95
									AddressHandler $addressHandler,
96
									FedShareManager $fedShareManager,
97
									ILogger $logger
98
	) {
99
		parent::__construct($appName, $request);
100
101
		$this->ocmMiddleware = $ocmMiddleware;
102
		$this->urlGenerator = $urlGenerator;
103
		$this->userManager = $userManager;
104
		$this->addressHandler = $addressHandler;
105
		$this->fedShareManager = $fedShareManager;
106
		$this->logger = $logger;
107
	}
108
109
	/**
110
	 * @NoCSRFRequired
111
	 * @PublicPage
112
	 *
113
	 * EndPoint discovery
114
	 * Responds to /ocm-provider/ requests
115
	 *
116
	 * @return array
117
	 */
118
	public function discovery() {
119
		$endPoint = $this->urlGenerator->linkToRouteAbsolute(
120
			"{$this->appName}.ocm.index"
121
		);
122
		return [
123
			'enabled' => true,
124
			'apiVersion' => self::API_VERSION,
125
			'endPoint' => \rtrim($endPoint, '/'),
126
			'shareTypes' => [
127
				[
128
					'name' => FileNotification::RESOURCE_TYPE_FILE,
129
					'protocols' => $this->getProtocols()
130
				]
131
			]
132
		];
133
	}
134
135
	/**
136
	 * @NoCSRFRequired
137
	 * @PublicPage
138
	 *
139
	 * @param string $shareWith identifier of the user or group
140
	 * 							to share the resource with
141
	 * @param string $name name of the shared resource
142
	 * @param string $description share description (optional)
143
	 * @param string $providerId Identifier of the resource at the provider side
144
	 * @param string $owner identifier of the user that owns the resource
145
	 * @param string $ownerDisplayName display name of the owner
146
	 * @param string $sender Provider specific identifier of the user that wants
147
	 *							to share the resource
148
	 * @param string $senderDisplayName Display name of the user that wants
149
	 * 									to share the resource
150
	 * @param string $shareType Share type ('user' is supported atm)
151
	 * @param string $resourceType only 'file' is supported atm
152
	 * @param array $protocol
153
	 * 		[
154
	 * 			'name' => (string) protocol name. Only 'webdav' is supported atm,
155
	 * 			'options' => [
156
	 * 				protocol specific options
157
	 * 				only `webdav` options are supported atm
158
	 * 				e.g. `uri`,	`access_token`, `password`, `permissions` etc.
159
	 *
160
	 * 				For backward compatibility the webdav protocol will use
161
	 * 				the 'sharedSecret" as username and password
162
	 * 			]
163
	 *
164
	 * @return JSONResponse
165
	 */
166
	public function createShare($shareWith,
167
								$name,
168
								$description,
0 ignored issues
show
Unused Code introduced by
The parameter $description is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
169
								$providerId,
170
								$owner,
171
								$ownerDisplayName,
172
								$sender,
173
								$senderDisplayName,
174
								$shareType,
175
								$resourceType,
176
								$protocol
177
178
	) {
179
		try {
180
			$this->ocmMiddleware->assertIncomingSharingEnabled();
181
			$this->ocmMiddleware->assertNotNull(
182
				[
183
					'shareWith' => $shareWith,
184
					'name' => $name,
185
					'providerId' => $providerId,
186
					'owner' => $owner,
187
					'shareType' => $shareType,
188
					'resourceType' => $resourceType
189
				]
190
			);
191
			if (!\is_array($protocol)
192
				|| !isset($protocol['name'])
193
				|| !isset($protocol['options'])
194
				|| !\is_array($protocol['options'])
195
				|| !isset($protocol['options']['sharedSecret'])
196
			) {
197
				throw new BadRequestException(
198
					'server can not add remote share, missing parameter'
199
				);
200
			}
201
			if (!\OCP\Util::isValidFileName($name)) {
202
				throw new BadRequestException(
203
					'The mountpoint name contains invalid characters.'
204
				);
205
			}
206
207
			if ($this->isSupportedProtocol($protocol['name']) === false) {
208
				throw new NotImplementedException(
209
					"Protocol {$protocol['name']} is not supported"
210
				);
211
			}
212
213
			if ($this->isSupportedShareType($shareType) === false) {
214
				throw new NotImplementedException(
215
					"ShareType {$shareType} is not supported"
216
				);
217
			}
218
219
			if ($this->isSupportedResourceType($resourceType) === false) {
220
				throw new NotImplementedException(
221
					"ResourceType {$resourceType} is not supported"
222
				);
223
			}
224
225
			$shareWithAddress = new Address($shareWith);
226
			$localShareWith = $shareWithAddress->toLocalUid();
227
			if (!$this->userManager->userExists($localShareWith)) {
228
				throw new BadRequestException("User $localShareWith does not exist");
229
			}
230
231
			$ownerAddress = new Address($owner, $ownerDisplayName);
232
			$sharedByAddress = new Address($sender, $senderDisplayName);
233
234
			$this->fedShareManager->createShare(
235
				$ownerAddress,
236
				$sharedByAddress,
237
				$localShareWith,
238
				$providerId,
239
				$name,
240
				$protocol['options']['sharedSecret']
241
			);
242
		} catch (OcmException $e) {
243
			return new JSONResponse(
244
				['message' => $e->getMessage()],
245
				$e->getHttpStatusCode()
246
			);
247
		} catch (\Exception $e) {
248
			$this->logger->error(
249
				"server can not add remote share, {$e->getMessage()}",
250
				['app' => 'federatefilesharing']
251
			);
252
			return new JSONResponse(
253
				[
254
					'message' => "internal server error, was not able to add share from {$owner}"
255
				],
256
				Http::STATUS_INTERNAL_SERVER_ERROR
257
			);
258
		}
259
		return new JSONResponse(
260
			[],
261
			Http::STATUS_CREATED
262
		);
263
	}
264
265
	/**
266
	 * @NoCSRFRequired
267
	 * @PublicPage
268
	 *
269
	 * @param string $notificationType notification type (SHARE_REMOVED, etc)
270
	 * @param string $resourceType only 'file' is supported atm
271
	 * @param string $providerId Identifier of the resource at the provider side
272
	 * @param array $notification
273
	 * 		[
274
	 * 			optional additional parameters, depending on the notification
275
	 * 				and the resource type
276
	 * 		]
277
	 *
278
	 * @return JSONResponse
279
	 */
280
	public function processNotification($notificationType,
281
										$resourceType,
282
										$providerId,
283
										$notification
284
	) {
285
		try {
286
			if (!\is_array($notification)) {
287
				throw new BadRequestException(
288
					'server can not add remote share, missing parameter'
289
				);
290
			}
291
292
			$notification = \array_merge(
293
				['sharedSecret' => null],
294
				$notification
295
			);
296
297
			$this->ocmMiddleware->assertNotNull(
298
				[
299
					'notificationType' => $notificationType,
300
					'resourceType' => $resourceType,
301
					'providerId' => $providerId,
302
					'sharedSecret' => $notification['sharedSecret']
303
				]
304
			);
305
306
			if ($this->isSupportedResourceType($resourceType) === false) {
307
				throw new NotImplementedException(
308
					"ResourceType {$resourceType} is not supported"
309
				);
310
			}
311
312
			switch ($notificationType) {
313 View Code Duplication
				case FileNotification::NOTIFICATION_TYPE_SHARE_ACCEPTED:
0 ignored issues
show
Duplication introduced by
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...
314
					$this->ocmMiddleware->assertOutgoingSharingEnabled();
315
					$share = $this->ocmMiddleware->getValidShare(
316
						$providerId, $notification['sharedSecret']
317
					);
318
					$this->fedShareManager->acceptShare($share);
319
					break;
320 View Code Duplication
				case FileNotification::NOTIFICATION_TYPE_SHARE_DECLINED:
0 ignored issues
show
Duplication introduced by
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...
321
					$this->ocmMiddleware->assertOutgoingSharingEnabled();
322
					$share = $this->ocmMiddleware->getValidShare(
323
						$providerId, $notification['sharedSecret']
324
					);
325
					$this->fedShareManager->declineShare($share);
326
					break;
327
				case FileNotification::NOTIFICATION_TYPE_REQUEST_RESHARE:
328
					$this->ocmMiddleware->assertOutgoingSharingEnabled();
329
					$this->ocmMiddleware->assertNotNull(
330
						[
331
							'shareWith' => $notification['shareWith'],
332
							'senderId' => $notification['senderId'],
333
						]
334
					);
335
					$share = $this->ocmMiddleware->getValidShare(
336
						$providerId, $notification['sharedSecret']
337
					);
338
339
					// don't allow to share a file back to the owner
340
					$owner = $share->getShareOwner();
341
					$ownerAddress = $this->addressHandler->getLocalUserFederatedAddress($owner);
342
					$shareWithAddress = new Address($notification['shareWith']);
343
					$this->ocmMiddleware->assertNotSameUser($ownerAddress, $shareWithAddress);
344
					$this->ocmMiddleware->assertSharingPermissionSet($share);
345
346
					$reShare = $this->fedShareManager->reShare(
347
						$share, $notification['senderId'],
348
						$notification['shareWith']
349
					);
350
					return new JSONResponse(
351
						[
352
							'sharedSecret' => $reShare->getToken(),
353
							'providerId' => $reShare->getId()
354
						],
355
						Http::STATUS_CREATED
356
					);
357
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
358
				case FileNotification::NOTIFICATION_TYPE_RESHARE_CHANGE_PERMISSION:
359
					$this->ocmMiddleware->assertNotNull(
360
						[
361
							'permission' => $notification['permission']
362
						]
363
					);
364
					$share = $this->ocmMiddleware->getValidShare(
365
						$providerId, $notification['sharedSecret']
366
					);
367
					$this->fedShareManager->updateOcmPermissions(
368
						$share,
369
						$notification['permission']
370
					);
371
					break;
372
				case FileNotification::NOTIFICATION_TYPE_SHARE_UNSHARED:
373
					$this->fedShareManager->unshare(
374
						$providerId, $notification['sharedSecret']
375
					);
376
					break;
377
				case FileNotification::NOTIFICATION_TYPE_RESHARE_UNDO:
378
					// owner or sender unshared a resource
379
					$share = $this->ocmMiddleware->getValidShare(
380
						$providerId, $notification['sharedSecret']
381
					);
382
					$this->fedShareManager->undoReshare($share);
383
					break;
384
				default:
385
					return new JSONResponse(
386
						['message' => "Notification of type {$notificationType} is not supported"],
387
						Http::STATUS_NOT_IMPLEMENTED
388
					);
389
			}
390
		} catch (OcmException $e) {
391
			return new JSONResponse(
392
				['message' => $e->getMessage()],
393
				$e->getHttpStatusCode()
394
			);
395
		} catch (\Exception $e) {
396
			$this->logger->error(
397
				"server can not process notification, {$e->getMessage()}",
398
				['app' => 'federatefilesharing']
399
			);
400
			return new JSONResponse(
401
				[
402
					'message' => "internal server error, was not able to process notification"
403
				],
404
				Http::STATUS_INTERNAL_SERVER_ERROR
405
			);
406
		}
407
		return new JSONResponse(
408
			[],
409
			Http::STATUS_CREATED
410
		);
411
	}
412
413
	/**
414
	 * Get list of supported protocols
415
	 *
416
	 * @return array
417
	 */
418
	protected function getProtocols() {
419
		return [
420
			'webdav' => '/public.php/webdav/'
421
		];
422
	}
423
424
	/**
425
	 * @param string $resourceType
426
	 *
427
	 * @return bool
428
	 */
429
	protected function isSupportedResourceType($resourceType) {
430
		return $resourceType === FileNotification::RESOURCE_TYPE_FILE;
431
	}
432
433
	/**
434
	 * @param string $shareType
435
	 * @return bool
436
	 */
437
	protected function isSupportedShareType($shareType) {
438
		// TODO: make it a constant
439
		return $shareType === 'user';
440
	}
441
442
	/**
443
	 * @param string $protocolName
444
	 * @return bool
445
	 */
446
	protected function isSupportedProtocol($protocolName) {
447
		$supportedProtocols = $this->getProtocols();
448
		$supportedProtocolNames = \array_keys($supportedProtocols);
449
		return \in_array($protocolName, $supportedProtocolNames);
450
	}
451
}
452