Completed
Pull Request — master (#32218)
by Thomas
50:41 queued 37:30
created

FedShareManager::unshare()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 27
rs 9.488
c 0
b 0
f 0
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;
23
24
use OCA\Files_Sharing\Activity;
25
use OCP\Activity\IManager as ActivityManager;
26
use OCP\Files\NotFoundException;
27
use OCP\IUserManager;
28
use OCP\Notification\IManager as NotificationManager;
29
use OCP\Share\IShare;
30
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
31
use Symfony\Component\EventDispatcher\GenericEvent;
32
33
/**
34
 * Class FedShareManager holds the share logic
35
 *
36
 * @package OCA\FederatedFileSharing
37
 */
38
class FedShareManager {
39
	const ACTION_URL = 'ocs/v1.php/apps/files_sharing/api/v1/remote_shares/pending/';
40
41
	/**
42
	 * @var FederatedShareProvider
43
	 */
44
	private $federatedShareProvider;
45
46
	/**
47
	 * @var Notifications
48
	 */
49
	private $notifications;
50
51
	/**
52
	 * @var IUserManager
53
	 */
54
	private $userManager;
55
56
	/**
57
	 * @var ActivityManager
58
	 */
59
	private $activityManager;
60
61
	/**
62
	 * @var NotificationManager
63
	 */
64
	private $notificationManager;
65
66
	/**
67
	 * @var AddressHandler
68
	 */
69
	private $addressHandler;
70
71
	/**
72
	 * @var EventDispatcherInterface
73
	 */
74
	private $eventDispatcher;
75
76
	/**
77
	 * FedShareManager constructor.
78
	 *
79
	 * @param FederatedShareProvider $federatedShareProvider
80
	 * @param Notifications $notifications
81
	 * @param IUserManager $userManager
82
	 * @param ActivityManager $activityManager
83
	 * @param NotificationManager $notificationManager
84
	 * @param AddressHandler $addressHandler
85
	 * @param EventDispatcherInterface $eventDispatcher
86
	 */
87
	public function __construct(FederatedShareProvider $federatedShareProvider,
88
								Notifications $notifications,
89
								IUserManager $userManager,
90
								ActivityManager $activityManager,
91
								NotificationManager $notificationManager,
92
								AddressHandler $addressHandler,
93
								EventDispatcherInterface $eventDispatcher
94
	) {
95
		$this->federatedShareProvider = $federatedShareProvider;
96
		$this->notifications = $notifications;
97
		$this->userManager = $userManager;
98
		$this->activityManager = $activityManager;
99
		$this->notificationManager = $notificationManager;
100
		$this->addressHandler = $addressHandler;
101
		$this->eventDispatcher = $eventDispatcher;
102
	}
103
104
	/**
105
	 * Create an incoming share
106
	 *
107
	 * @param string $shareWith
108
	 * @param string $remote
109
	 * @param int $remoteId
110
	 * @param string $owner
111
	 * @param string $name
112
	 * @param int $ownerFederatedId
113
	 * @param int $sharedByFederatedId
114
	 * @param string $sharedBy
115
	 * @param string $token
116
	 *
117
	 * @return void
118
	 */
119
	public function createShare($shareWith,
120
								$remote,
121
								$remoteId,
122
								$owner,
123
								$name,
124
								$ownerFederatedId,
125
								$sharedByFederatedId,
126
								$sharedBy,
127
								$token
128
	) {
129
		if ($ownerFederatedId === null) {
130
			$ownerFederatedId = $owner . '@' . $this->addressHandler->normalizeRemote($remote);
131
		}
132
		// if the owner of the share and the initiator are the same user
133
		// we also complete the federated share ID for the initiator
134
		if ($sharedByFederatedId === null && $owner === $sharedBy) {
135
			$sharedByFederatedId = $ownerFederatedId;
136
		}
137
138
		$shareId = $this->federatedShareProvider->addShare(
139
			$remote, $token, $name, $owner, $shareWith, $remoteId
140
		);
141
142
		$this->eventDispatcher->dispatch(
143
			'\OCA\FederatedFileSharing::remote_shareReceived',
144
			new GenericEvent(
145
				null,
146
				[
147
					'name' => $name,
148
					'targetuser' => $sharedByFederatedId,
149
					'owner' => $owner,
150
					'sharewith' => $shareWith,
151
					'sharedby' => $sharedBy,
152
					'remoteid' => $remoteId
153
				]
154
			)
155
		);
156
		$this->publishActivity(
157
			$shareWith,
158
			Activity::SUBJECT_REMOTE_SHARE_RECEIVED,
159
			[$ownerFederatedId, \trim($name, '/')],
160
			'files',
161
			'',
162
			'',
163
			''
164
		);
165
		$link = $this->getActionLink($shareId);
166
		$params = [$ownerFederatedId, $sharedByFederatedId, \trim($name, '/')];
167
		$notification = $this->createNotification($shareWith);
168
		$notification->setDateTime(new \DateTime())
169
			->setObject('remote_share', $shareId)
170
			->setSubject('remote_share', $params)
171
			->setMessage('remote_share', $params);
172
		$declineAction = $notification->createAction();
173
		$declineAction->setLabel('decline')
174
			->setLink($link, 'DELETE');
175
		$notification->addAction($declineAction);
176
		$acceptAction = $notification->createAction();
177
		$acceptAction->setLabel('accept')
178
			->setLink($link, 'POST');
179
		$notification->addAction($acceptAction);
180
		$this->notificationManager->notify($notification);
181
	}
182
183
	/**
184
	 * @param IShare $share
185
	 * @param int $remoteId
186
	 * @param string $shareWith
187
	 * @param int $permissions
188
	 *
189
	 * @return IShare
190
	 *
191
	 * @throws \OCP\Share\Exceptions\ShareNotFound
192
	 */
193
	public function reShare(IShare $share, $remoteId, $shareWith, $permissions) {
194
		$share->setPermissions($share->getPermissions() & $permissions);
195
		// the recipient of the initial share is now the initiator for the re-share
196
		$share->setSharedBy($share->getSharedWith());
197
		$share->setSharedWith($shareWith);
198
		$result = $this->federatedShareProvider->create($share);
199
		$this->federatedShareProvider->storeRemoteId(
200
			(int)$result->getId(),
201
			$remoteId
202
		);
203
		return $result;
204
	}
205
206
	/**
207
	 *
208
	 *
209
	 * @param IShare $share
210
	 *
211
	 * @throws \OCP\Files\InvalidPathException
212
	 * @throws \OCP\Files\NotFoundException
213
	 */
214 View Code Duplication
	public function acceptShare(IShare $share) {
215
		$uid = $this->getCorrectUid($share);
216
		$fileId = $share->getNode()->getId();
217
		list($file, $link) = $this->getFile($uid, $fileId);
218
		$this->publishActivity(
219
			$uid,
220
			Activity::SUBJECT_REMOTE_SHARE_ACCEPTED,
221
			[$share->getSharedWith(), \basename($file)],
222
			'files',
223
			$fileId,
224
			$file,
225
			$link
226
		);
227
		$this->notifyRemote($share, [$this->notifications, 'sendAcceptShare']);
228
	}
229
230
	/**
231
	 * Delete declined share and create a activity
232
	 *
233
	 * @param IShare $share
234
	 *
235
	 * @throws \OCP\Files\InvalidPathException
236
	 * @throws \OCP\Files\NotFoundException
237
	 */
238 View Code Duplication
	public function declineShare(IShare $share) {
239
		$this->notifyRemote($share, [$this->notifications, 'sendDeclineShare']);
240
		$uid = $this->getCorrectUid($share);
241
		$fileId = $share->getNode()->getId();
242
		$this->federatedShareProvider->removeShareFromTable($share);
243
		list($file, $link) = $this->getFile($uid, $fileId);
244
		$this->publishActivity(
245
			$uid,
246
			Activity::SUBJECT_REMOTE_SHARE_DECLINED,
247
			[$share->getSharedWith(), \basename($file)],
248
			'files',
249
			$fileId,
250
			$file,
251
			$link
252
		);
253
	}
254
255
	/**
256
	 * Unshare an item
257
	 *
258
	 * @param int $id
259
	 * @param string $token
260
	 *
261
	 * @return void
262
	 */
263
	public function unshare($id, $token) {
264
		$shareRow = $this->federatedShareProvider->unshare($id, $token);
265
		if ($shareRow === false) {
266
			return;
267
		}
268
		$remote = $this->addressHandler->normalizeRemote($shareRow['remote']);
269
		$owner = $shareRow['owner'] . '@' . $remote;
270
		$mountpoint = $shareRow['mountpoint'];
271
		$user = $shareRow['user'];
272
		if ($shareRow['accepted']) {
273
			$path = \trim($mountpoint, '/');
274
		} else {
275
			$path = \trim($shareRow['name'], '/');
276
		}
277
		$notification = $this->createNotification($user);
278
		$notification->setObject('remote_share', (int) $shareRow['id']);
279
		$this->notificationManager->markProcessed($notification);
280
		$this->publishActivity(
281
			$user,
282
			Activity::SUBJECT_REMOTE_SHARE_UNSHARED,
283
			[$owner, $path],
284
			'files',
285
			'',
286
			'',
287
			''
288
		);
289
	}
290
291
	/**
292
	 * @param IShare $share
293
	 *
294
	 * @return void
295
	 */
296
	public function revoke(IShare $share) {
297
		$this->federatedShareProvider->removeShareFromTable($share);
298
	}
299
300
	/**
301
	 * Update permissions
302
	 *
303
	 * @param IShare $share
304
	 * @param int $permissions
305
	 *
306
	 * @return void
307
	 */
308
	public function updatePermissions(IShare $share, $permissions) {
309
		$share->setPermissions($permissions);
310
		$this->federatedShareProvider->update($share);
311
	}
312
313
	/**
314
	 * @param IShare $share
315
	 * @param callable $callback
316
	 *
317
	 * @throws \OCP\Share\Exceptions\ShareNotFound
318
	 * @throws \OC\HintException
319
	 */
320
	protected function notifyRemote($share, $callback) {
321
		if ($share->getShareOwner() !== $share->getSharedBy()) {
322
			list(, $remote) = $this->addressHandler->splitUserRemote(
323
				$share->getSharedBy()
324
			);
325
			$remoteId = $this->federatedShareProvider->getRemoteId($share);
326
			$callback($remote, $remoteId, $share->getToken());
327
		}
328
	}
329
330
	/**
331
	 * Publish a new activity
332
	 *
333
	 * @param string $affectedUser
334
	 * @param string $subject
335
	 * @param array $subjectParams
336
	 * @param string $objectType
337
	 * @param int $objectId
338
	 * @param string $objectName
339
	 * @param string $link
340
	 *
341
	 * @return void
342
	 */
343
	protected function publishActivity($affectedUser,
344
									   $subject,
345
									   $subjectParams,
346
									   $objectType,
347
									   $objectId,
348
									   $objectName,
349
									   $link
350
	) {
351
		$event = $this->activityManager->generateEvent();
352
		$event->setApp(Activity::FILES_SHARING_APP)
353
			->setType(Activity::TYPE_REMOTE_SHARE)
354
			->setAffectedUser($affectedUser)
355
			->setSubject($subject, $subjectParams)
356
			->setObject($objectType, $objectId, $objectName)
357
			->setLink($link);
358
		$this->activityManager->publish($event);
359
	}
360
361
	/**
362
	 * Get a new notification
363
	 *
364
	 * @param string $uid
365
	 *
366
	 * @return \OCP\Notification\INotification
367
	 */
368
	protected function createNotification($uid) {
369
		$notification = $this->notificationManager->createNotification();
370
		$notification->setApp('files_sharing');
371
		$notification->setUser($uid);
372
		return $notification;
373
	}
374
375
	/**
376
	 * @param int $shareId
377
	 * @return string
378
	 */
379
	protected function getActionLink($shareId) {
380
		$urlGenerator = \OC::$server->getURLGenerator();
381
		$link = $urlGenerator->getAbsoluteURL(
382
			$urlGenerator->linkTo('', self::ACTION_URL . $shareId)
383
		);
384
		return $link;
385
	}
386
387
	/**
388
	 * Get file
389
	 *
390
	 * @param string $user
391
	 * @param int $fileSource
392
	 *
393
	 * @return array with internal path of the file and a absolute link to it
394
	 */
395
	protected function getFile($user, $fileSource) {
396
		\OC_Util::setupFS($user);
397
398
		try {
399
			$file = \OC\Files\Filesystem::getPath($fileSource);
400
		} catch (NotFoundException $e) {
401
			$file = null;
402
		}
403
		// FIXME:  use permalink here, see ViewController for reference
404
		$args = \OC\Files\Filesystem::is_dir($file)
405
			? ['dir' => $file]
406
			: ['dir' => \dirname($file), 'scrollto' => $file];
407
		$link = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
408
409
		return [$file, $link];
410
	}
411
412
	/**
413
	 * Check if we are the initiator or the owner of a re-share
414
	 * and return the correct UID
415
	 *
416
	 * @param IShare $share
417
	 *
418
	 * @return string
419
	 */
420
	protected function getCorrectUid(IShare $share) {
421
		if ($this->userManager->userExists($share->getShareOwner())) {
422
			return $share->getShareOwner();
423
		}
424
425
		return $share->getSharedBy();
426
	}
427
}
428