Completed
Push — master ( dccb89...31024b )
by Morris
12:39
created

Manager::addShare()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 57
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 37
nc 12
nop 8
dl 0
loc 57
rs 8.7433
c 0
b 0
f 0

How to fix   Long Method    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
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Jörn Friedrich Dreyer <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 * @author Stefan Weil <[email protected]>
13
 *
14
 * @license AGPL-3.0
15
 *
16
 * This code is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License, version 3,
18
 * as published by the Free Software Foundation.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License, version 3,
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
27
 *
28
 */
29
30
namespace OCA\Files_Sharing\External;
31
32
use OC\Files\Filesystem;
33
use OCA\FederatedFileSharing\DiscoveryManager;
34
use OCP\Files;
35
use OCP\Files\Storage\IStorageFactory;
36
use OCP\Http\Client\IClientService;
37
use OCP\IDBConnection;
38
use OCP\Notification\IManager;
39
use OCP\OCS\IDiscoveryService;
40
41
class Manager {
42
	const STORAGE = '\OCA\Files_Sharing\External\Storage';
43
44
	/**
45
	 * @var string
46
	 */
47
	private $uid;
48
49
	/**
50
	 * @var IDBConnection
51
	 */
52
	private $connection;
53
54
	/**
55
	 * @var \OC\Files\Mount\Manager
56
	 */
57
	private $mountManager;
58
59
	/**
60
	 * @var IStorageFactory
61
	 */
62
	private $storageLoader;
63
64
	/**
65
	 * @var IClientService
66
	 */
67
	private $clientService;
68
69
	/**
70
	 * @var IManager
71
	 */
72
	private $notificationManager;
73
74
	/**
75
	 * @var IDiscoveryService
76
	 */
77
	private $discoveryService;
78
79
	/**
80
	 * @param IDBConnection $connection
81
	 * @param \OC\Files\Mount\Manager $mountManager
82
	 * @param IStorageFactory $storageLoader
83
	 * @param IClientService $clientService
84
	 * @param IManager $notificationManager
85
	 * @param IDiscoveryService $discoveryService
86
	 * @param string $uid
87
	 */
88
	public function __construct(IDBConnection $connection,
89
								\OC\Files\Mount\Manager $mountManager,
90
								IStorageFactory $storageLoader,
91
								IClientService $clientService,
92
								IManager $notificationManager,
93
								IDiscoveryService $discoveryService,
94
								$uid) {
95
		$this->connection = $connection;
96
		$this->mountManager = $mountManager;
97
		$this->storageLoader = $storageLoader;
98
		$this->clientService = $clientService;
99
		$this->uid = $uid;
100
		$this->notificationManager = $notificationManager;
101
		$this->discoveryService = $discoveryService;
102
	}
103
104
	/**
105
	 * add new server-to-server share
106
	 *
107
	 * @param string $remote
108
	 * @param string $token
109
	 * @param string $password
110
	 * @param string $name
111
	 * @param string $owner
112
	 * @param boolean $accepted
113
	 * @param string $user
114
	 * @param int $remoteId
115
	 * @return Mount|null
116
	 */
117
	public function addShare($remote, $token, $password, $name, $owner, $accepted=false, $user = null, $remoteId = -1) {
118
119
		$user = $user ? $user : $this->uid;
120
		$accepted = $accepted ? 1 : 0;
121
		$name = Filesystem::normalizePath('/' . $name);
122
123
		if (!$accepted) {
124
			// To avoid conflicts with the mount point generation later,
125
			// we only use a temporary mount point name here. The real
126
			// mount point name will be generated when accepting the share,
127
			// using the original share item name.
128
			$tmpMountPointName = '{{TemporaryMountPointName#' . $name . '}}';
129
			$mountPoint = $tmpMountPointName;
130
			$hash = md5($tmpMountPointName);
131
			$data = [
132
				'remote'		=> $remote,
133
				'share_token'	=> $token,
134
				'password'		=> $password,
135
				'name'			=> $name,
136
				'owner'			=> $owner,
137
				'user'			=> $user,
138
				'mountpoint'	=> $mountPoint,
139
				'mountpoint_hash'	=> $hash,
140
				'accepted'		=> $accepted,
141
				'remote_id'		=> $remoteId,
142
			];
143
144
			$i = 1;
145
			while (!$this->connection->insertIfNotExist('*PREFIX*share_external', $data, ['user', 'mountpoint_hash'])) {
146
				// The external share already exists for the user
147
				$data['mountpoint'] = $tmpMountPointName . '-' . $i;
148
				$data['mountpoint_hash'] = md5($data['mountpoint']);
149
				$i++;
150
			}
151
			return null;
152
		}
153
154
		$mountPoint = Files::buildNotExistingFileName('/', $name);
155
		$mountPoint = Filesystem::normalizePath('/' . $mountPoint);
156
		$hash = md5($mountPoint);
157
158
		$query = $this->connection->prepare('
159
				INSERT INTO `*PREFIX*share_external`
160
					(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`)
161
				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
162
			');
163
		$query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId));
164
165
		$options = array(
166
			'remote'	=> $remote,
167
			'token'		=> $token,
168
			'password'	=> $password,
169
			'mountpoint'	=> $mountPoint,
170
			'owner'		=> $owner
171
		);
172
		return $this->mountShare($options);
173
	}
174
175
	/**
176
	 * get share
177
	 *
178
	 * @param int $id share id
179
	 * @return mixed share of false
180
	 */
181
	public function getShare($id) {
182
		$getShare = $this->connection->prepare('
183
			SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`
184
			FROM  `*PREFIX*share_external`
185
			WHERE `id` = ? AND `user` = ?');
186
		$result = $getShare->execute(array($id, $this->uid));
187
188
		return $result ? $getShare->fetch() : false;
189
	}
190
191
	/**
192
	 * accept server-to-server share
193
	 *
194
	 * @param int $id
195
	 * @return bool True if the share could be accepted, false otherwise
196
	 */
197
	public function acceptShare($id) {
198
199
		$share = $this->getShare($id);
200
201
		if ($share) {
202
			$mountPoint = Files::buildNotExistingFileName('/', $share['name']);
203
			$mountPoint = Filesystem::normalizePath('/' . $mountPoint);
204
			$hash = md5($mountPoint);
205
206
			$acceptShare = $this->connection->prepare('
207
				UPDATE `*PREFIX*share_external`
208
				SET `accepted` = ?,
209
					`mountpoint` = ?,
210
					`mountpoint_hash` = ?
211
				WHERE `id` = ? AND `user` = ?');
212
			$acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid));
213
			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept');
214
215
			\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $share['remote']]);
216
217
			$this->processNotification($id);
218
			return true;
219
		}
220
221
		return false;
222
	}
223
224
	/**
225
	 * decline server-to-server share
226
	 *
227
	 * @param int $id
228
	 * @return bool True if the share could be declined, false otherwise
229
	 */
230
	public function declineShare($id) {
231
232
		$share = $this->getShare($id);
233
234
		if ($share) {
235
			$removeShare = $this->connection->prepare('
236
				DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?');
237
			$removeShare->execute(array($id, $this->uid));
238
			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
239
240
			$this->processNotification($id);
241
			return true;
242
		}
243
244
		return false;
245
	}
246
247
	/**
248
	 * @param int $remoteShare
249
	 */
250
	public function processNotification($remoteShare) {
251
		$filter = $this->notificationManager->createNotification();
252
		$filter->setApp('files_sharing')
253
			->setUser($this->uid)
254
			->setObject('remote_share', (int) $remoteShare);
255
		$this->notificationManager->markProcessed($filter);
256
	}
257
258
	/**
259
	 * inform remote server whether server-to-server share was accepted/declined
260
	 *
261
	 * @param string $remote
262
	 * @param string $token
263
	 * @param int $remoteId Share id on the remote host
264
	 * @param string $feedback
265
	 * @return boolean
266
	 */
267
	private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) {
268
269
		$federationEndpoints = $this->discoveryService->discover($remote, 'FEDERATED_SHARING');
270
		$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
271
272
		$url = rtrim($remote, '/') . $endpoint . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT;
273
		$fields = array('token' => $token);
274
275
		$client = $this->clientService->newClient();
276
277
		try {
278
			$response = $client->post(
279
				$url,
280
				[
281
					'body' => $fields,
282
					'connect_timeout' => 10,
283
				]
284
			);
285
		} catch (\Exception $e) {
286
			return false;
287
		}
288
289
		$status = json_decode($response->getBody(), true);
290
291
		return ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200);
292
	}
293
294
	/**
295
	 * remove '/user/files' from the path and trailing slashes
296
	 *
297
	 * @param string $path
298
	 * @return string
299
	 */
300
	protected function stripPath($path) {
301
		$prefix = '/' . $this->uid . '/files';
302
		return rtrim(substr($path, strlen($prefix)), '/');
303
	}
304
305
	public function getMount($data) {
306
		$data['manager'] = $this;
307
		$mountPoint = '/' . $this->uid . '/files' . $data['mountpoint'];
308
		$data['mountpoint'] = $mountPoint;
309
		$data['certificateManager'] = \OC::$server->getCertificateManager($this->uid);
310
		return new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
0 ignored issues
show
Documentation introduced by
$this->storageLoader is of type object<OCP\Files\Storage\IStorageFactory>, but the function expects a object<OC\Files\Storage\StorageFactory>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
311
	}
312
313
	/**
314
	 * @param array $data
315
	 * @return Mount
316
	 */
317
	protected function mountShare($data) {
318
		$mount = $this->getMount($data);
319
		$this->mountManager->addMount($mount);
320
		return $mount;
321
	}
322
323
	/**
324
	 * @return \OC\Files\Mount\Manager
325
	 */
326
	public function getMountManager() {
327
		return $this->mountManager;
328
	}
329
330
	/**
331
	 * @param string $source
332
	 * @param string $target
333
	 * @return bool
334
	 */
335
	public function setMountPoint($source, $target) {
336
		$source = $this->stripPath($source);
337
		$target = $this->stripPath($target);
338
		$sourceHash = md5($source);
339
		$targetHash = md5($target);
340
341
		$query = $this->connection->prepare('
342
			UPDATE `*PREFIX*share_external`
343
			SET `mountpoint` = ?, `mountpoint_hash` = ?
344
			WHERE `mountpoint_hash` = ?
345
			AND `user` = ?
346
		');
347
		$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $this->uid));
348
349
		return $result;
350
	}
351
352
	public function removeShare($mountPoint) {
353
354
		$mountPointObj = $this->mountManager->find($mountPoint);
355
		$id = $mountPointObj->getStorage()->getCache()->getId('');
356
357
		$mountPoint = $this->stripPath($mountPoint);
358
		$hash = md5($mountPoint);
359
360
		$getShare = $this->connection->prepare('
361
			SELECT `remote`, `share_token`, `remote_id`
362
			FROM  `*PREFIX*share_external`
363
			WHERE `mountpoint_hash` = ? AND `user` = ?');
364
		$result = $getShare->execute(array($hash, $this->uid));
365
366 View Code Duplication
		if ($result) {
367
			$share = $getShare->fetch();
368
			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
369
		}
370
		$getShare->closeCursor();
371
372
		$query = $this->connection->prepare('
373
			DELETE FROM `*PREFIX*share_external`
374
			WHERE `mountpoint_hash` = ?
375
			AND `user` = ?
376
		');
377
		$result = (bool)$query->execute(array($hash, $this->uid));
378
379
		if($result) {
380
			$this->removeReShares($id);
381
		}
382
383
		return $result;
384
	}
385
386
	/**
387
	 * remove re-shares from share table and mapping in the federated_reshares table
388
	 *
389
	 * @param $mountPointId
390
	 */
391
	protected function removeReShares($mountPointId) {
392
		$selectQuery = $this->connection->getQueryBuilder();
393
		$query = $this->connection->getQueryBuilder();
394
		$selectQuery->select('id')->from('share')
395
			->where($selectQuery->expr()->eq('file_source', $query->createNamedParameter($mountPointId)));
396
		$select = $selectQuery->getSQL();
397
398
399
		$query->delete('federated_reshares')
400
			->where($query->expr()->in('share_id', $query->createFunction('(' . $select . ')')));
401
		$query->execute();
402
403
		$deleteReShares = $this->connection->getQueryBuilder();
404
		$deleteReShares->delete('share')
405
			->where($deleteReShares->expr()->eq('file_source', $deleteReShares->createNamedParameter($mountPointId)));
406
		$deleteReShares->execute();
407
	}
408
409
	/**
410
	 * remove all shares for user $uid if the user was deleted
411
	 *
412
	 * @param string $uid
413
	 * @return bool
414
	 */
415
	public function removeUserShares($uid) {
416
		$getShare = $this->connection->prepare('
417
			SELECT `remote`, `share_token`, `remote_id`
418
			FROM  `*PREFIX*share_external`
419
			WHERE `user` = ?');
420
		$result = $getShare->execute(array($uid));
421
422 View Code Duplication
		if ($result) {
423
			$shares = $getShare->fetchAll();
424
			foreach($shares as $share) {
425
				$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
426
			}
427
		}
428
429
		$query = $this->connection->prepare('
430
			DELETE FROM `*PREFIX*share_external`
431
			WHERE `user` = ?
432
		');
433
		return (bool)$query->execute(array($uid));
434
	}
435
436
	/**
437
	 * return a list of shares which are not yet accepted by the user
438
	 *
439
	 * @return array list of open server-to-server shares
440
	 */
441
	public function getOpenShares() {
442
		return $this->getShares(false);
443
	}
444
445
	/**
446
	 * return a list of shares which are accepted by the user
447
	 *
448
	 * @return array list of accepted server-to-server shares
449
	 */
450
	public function getAcceptedShares() {
451
		return $this->getShares(true);
452
	}
453
454
	/**
455
	 * return a list of shares for the user
456
	 *
457
	 * @param bool|null $accepted True for accepted only,
458
	 *                            false for not accepted,
459
	 *                            null for all shares of the user
460
	 * @return array list of open server-to-server shares
461
	 */
462
	private function getShares($accepted) {
463
		$query = 'SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`
464
		          FROM `*PREFIX*share_external` 
465
				  WHERE `user` = ?';
466
		$parameters = [$this->uid];
467
		if (!is_null($accepted)) {
468
			$query .= ' AND `accepted` = ?';
469
			$parameters[] = (int) $accepted;
470
		}
471
		$query .= ' ORDER BY `id` ASC';
472
473
		$shares = $this->connection->prepare($query);
474
		$result = $shares->execute($parameters);
475
476
		return $result ? $shares->fetchAll() : [];
477
	}
478
}
479