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

FedShareManager::revoke()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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