Completed
Push — master ( 7a269a...db1408 )
by Morris
13:03
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\Files_Sharing\Helper;
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
			\OC_Util::setupFS($this->uid);
203
			$shareFolder = Helper::getShareFolder();
204
			$mountPoint = Files::buildNotExistingFileName($shareFolder, $share['name']);
205
			$mountPoint = Filesystem::normalizePath($mountPoint);
206
			$hash = md5($mountPoint);
207
208
			$acceptShare = $this->connection->prepare('
209
				UPDATE `*PREFIX*share_external`
210
				SET `accepted` = ?,
211
					`mountpoint` = ?,
212
					`mountpoint_hash` = ?
213
				WHERE `id` = ? AND `user` = ?');
214
			$acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid));
215
			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept');
216
217
			\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $share['remote']]);
218
219
			$this->processNotification($id);
220
			return true;
221
		}
222
223
		return false;
224
	}
225
226
	/**
227
	 * decline server-to-server share
228
	 *
229
	 * @param int $id
230
	 * @return bool True if the share could be declined, false otherwise
231
	 */
232
	public function declineShare($id) {
233
234
		$share = $this->getShare($id);
235
236
		if ($share) {
237
			$removeShare = $this->connection->prepare('
238
				DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?');
239
			$removeShare->execute(array($id, $this->uid));
240
			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
241
242
			$this->processNotification($id);
243
			return true;
244
		}
245
246
		return false;
247
	}
248
249
	/**
250
	 * @param int $remoteShare
251
	 */
252
	public function processNotification($remoteShare) {
253
		$filter = $this->notificationManager->createNotification();
254
		$filter->setApp('files_sharing')
255
			->setUser($this->uid)
256
			->setObject('remote_share', (int) $remoteShare);
257
		$this->notificationManager->markProcessed($filter);
258
	}
259
260
	/**
261
	 * inform remote server whether server-to-server share was accepted/declined
262
	 *
263
	 * @param string $remote
264
	 * @param string $token
265
	 * @param int $remoteId Share id on the remote host
266
	 * @param string $feedback
267
	 * @return boolean
268
	 */
269
	private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) {
270
271
		$federationEndpoints = $this->discoveryService->discover($remote, 'FEDERATED_SHARING');
272
		$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
273
274
		$url = rtrim($remote, '/') . $endpoint . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT;
275
		$fields = array('token' => $token);
276
277
		$client = $this->clientService->newClient();
278
279
		try {
280
			$response = $client->post(
281
				$url,
282
				[
283
					'body' => $fields,
284
					'connect_timeout' => 10,
285
				]
286
			);
287
		} catch (\Exception $e) {
288
			return false;
289
		}
290
291
		$status = json_decode($response->getBody(), true);
292
293
		return ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200);
294
	}
295
296
	/**
297
	 * remove '/user/files' from the path and trailing slashes
298
	 *
299
	 * @param string $path
300
	 * @return string
301
	 */
302
	protected function stripPath($path) {
303
		$prefix = '/' . $this->uid . '/files';
304
		return rtrim(substr($path, strlen($prefix)), '/');
305
	}
306
307
	public function getMount($data) {
308
		$data['manager'] = $this;
309
		$mountPoint = '/' . $this->uid . '/files' . $data['mountpoint'];
310
		$data['mountpoint'] = $mountPoint;
311
		$data['certificateManager'] = \OC::$server->getCertificateManager($this->uid);
312
		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...
313
	}
314
315
	/**
316
	 * @param array $data
317
	 * @return Mount
318
	 */
319
	protected function mountShare($data) {
320
		$mount = $this->getMount($data);
321
		$this->mountManager->addMount($mount);
322
		return $mount;
323
	}
324
325
	/**
326
	 * @return \OC\Files\Mount\Manager
327
	 */
328
	public function getMountManager() {
329
		return $this->mountManager;
330
	}
331
332
	/**
333
	 * @param string $source
334
	 * @param string $target
335
	 * @return bool
336
	 */
337
	public function setMountPoint($source, $target) {
338
		$source = $this->stripPath($source);
339
		$target = $this->stripPath($target);
340
		$sourceHash = md5($source);
341
		$targetHash = md5($target);
342
343
		$query = $this->connection->prepare('
344
			UPDATE `*PREFIX*share_external`
345
			SET `mountpoint` = ?, `mountpoint_hash` = ?
346
			WHERE `mountpoint_hash` = ?
347
			AND `user` = ?
348
		');
349
		$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $this->uid));
350
351
		return $result;
352
	}
353
354
	public function removeShare($mountPoint) {
355
356
		$mountPointObj = $this->mountManager->find($mountPoint);
357
		$id = $mountPointObj->getStorage()->getCache()->getId('');
358
359
		$mountPoint = $this->stripPath($mountPoint);
360
		$hash = md5($mountPoint);
361
362
		$getShare = $this->connection->prepare('
363
			SELECT `remote`, `share_token`, `remote_id`
364
			FROM  `*PREFIX*share_external`
365
			WHERE `mountpoint_hash` = ? AND `user` = ?');
366
		$result = $getShare->execute(array($hash, $this->uid));
367
368 View Code Duplication
		if ($result) {
369
			$share = $getShare->fetch();
370
			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
371
		}
372
		$getShare->closeCursor();
373
374
		$query = $this->connection->prepare('
375
			DELETE FROM `*PREFIX*share_external`
376
			WHERE `mountpoint_hash` = ?
377
			AND `user` = ?
378
		');
379
		$result = (bool)$query->execute(array($hash, $this->uid));
380
381
		if($result) {
382
			$this->removeReShares($id);
383
		}
384
385
		return $result;
386
	}
387
388
	/**
389
	 * remove re-shares from share table and mapping in the federated_reshares table
390
	 *
391
	 * @param $mountPointId
392
	 */
393
	protected function removeReShares($mountPointId) {
394
		$selectQuery = $this->connection->getQueryBuilder();
395
		$query = $this->connection->getQueryBuilder();
396
		$selectQuery->select('id')->from('share')
397
			->where($selectQuery->expr()->eq('file_source', $query->createNamedParameter($mountPointId)));
398
		$select = $selectQuery->getSQL();
399
400
401
		$query->delete('federated_reshares')
402
			->where($query->expr()->in('share_id', $query->createFunction('(' . $select . ')')));
403
		$query->execute();
404
405
		$deleteReShares = $this->connection->getQueryBuilder();
406
		$deleteReShares->delete('share')
407
			->where($deleteReShares->expr()->eq('file_source', $deleteReShares->createNamedParameter($mountPointId)));
408
		$deleteReShares->execute();
409
	}
410
411
	/**
412
	 * remove all shares for user $uid if the user was deleted
413
	 *
414
	 * @param string $uid
415
	 * @return bool
416
	 */
417
	public function removeUserShares($uid) {
418
		$getShare = $this->connection->prepare('
419
			SELECT `remote`, `share_token`, `remote_id`
420
			FROM  `*PREFIX*share_external`
421
			WHERE `user` = ?');
422
		$result = $getShare->execute(array($uid));
423
424 View Code Duplication
		if ($result) {
425
			$shares = $getShare->fetchAll();
426
			foreach($shares as $share) {
427
				$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
428
			}
429
		}
430
431
		$query = $this->connection->prepare('
432
			DELETE FROM `*PREFIX*share_external`
433
			WHERE `user` = ?
434
		');
435
		return (bool)$query->execute(array($uid));
436
	}
437
438
	/**
439
	 * return a list of shares which are not yet accepted by the user
440
	 *
441
	 * @return array list of open server-to-server shares
442
	 */
443
	public function getOpenShares() {
444
		return $this->getShares(false);
445
	}
446
447
	/**
448
	 * return a list of shares which are accepted by the user
449
	 *
450
	 * @return array list of accepted server-to-server shares
451
	 */
452
	public function getAcceptedShares() {
453
		return $this->getShares(true);
454
	}
455
456
	/**
457
	 * return a list of shares for the user
458
	 *
459
	 * @param bool|null $accepted True for accepted only,
460
	 *                            false for not accepted,
461
	 *                            null for all shares of the user
462
	 * @return array list of open server-to-server shares
463
	 */
464
	private function getShares($accepted) {
465
		$query = 'SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`
466
		          FROM `*PREFIX*share_external` 
467
				  WHERE `user` = ?';
468
		$parameters = [$this->uid];
469
		if (!is_null($accepted)) {
470
			$query .= ' AND `accepted` = ?';
471
			$parameters[] = (int) $accepted;
472
		}
473
		$query .= ' ORDER BY `id` ASC';
474
475
		$shares = $this->connection->prepare($query);
476
		$result = $shares->execute($parameters);
477
478
		return $result ? $shares->fetchAll() : [];
479
	}
480
}
481