Completed
Pull Request — master (#32303)
by Victor
09:50
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
		$share->setPermissions($permissions);
311
		$this->federatedShareProvider->update($share);
312
	}
313
314
	/**
315
	 * Update permissions
316
	 *
317
	 * @param IShare $share
318
	 * @param int $permissions
319
	 *
320
	 * @return void
321
	 */
322
	public function updatePermissions(IShare $share, $permissions) {
323
		$share->setPermissions($permissions);
324
		$this->federatedShareProvider->update($share);
325
	}
326
327
	/**
328
	 * @param IShare $share
329
	 * @param callable $callback
330
	 *
331
	 * @throws \OCP\Share\Exceptions\ShareNotFound
332
	 * @throws \OC\HintException
333
	 */
334
	protected function notifyRemote($share, $callback) {
335
		if ($share->getShareOwner() !== $share->getSharedBy()) {
336
			list(, $remote) = $this->addressHandler->splitUserRemote(
337
				$share->getSharedBy()
338
			);
339
			$remoteId = $this->federatedShareProvider->getRemoteId($share);
340
			$callback($remote, $remoteId, $share->getToken());
341
		}
342
	}
343
344
	/**
345
	 * Publish a new activity
346
	 *
347
	 * @param string $affectedUser
348
	 * @param string $subject
349
	 * @param array $subjectParams
350
	 * @param string $objectType
351
	 * @param int $objectId
352
	 * @param string $objectName
353
	 * @param string $link
354
	 *
355
	 * @return void
356
	 */
357
	protected function publishActivity($affectedUser,
358
									   $subject,
359
									   $subjectParams,
360
									   $objectType,
361
									   $objectId,
362
									   $objectName,
363
									   $link
364
	) {
365
		$event = $this->activityManager->generateEvent();
366
		$event->setApp(Activity::FILES_SHARING_APP)
367
			->setType(Activity::TYPE_REMOTE_SHARE)
368
			->setAffectedUser($affectedUser)
369
			->setSubject($subject, $subjectParams)
370
			->setObject($objectType, $objectId, $objectName)
371
			->setLink($link);
372
		$this->activityManager->publish($event);
373
	}
374
375
	/**
376
	 * Get a new notification
377
	 *
378
	 * @param string $uid
379
	 *
380
	 * @return \OCP\Notification\INotification
381
	 */
382
	protected function createNotification($uid) {
383
		$notification = $this->notificationManager->createNotification();
384
		$notification->setApp('files_sharing');
385
		$notification->setUser($uid);
386
		return $notification;
387
	}
388
389
	/**
390
	 * @param int $shareId
391
	 * @return string
392
	 */
393
	protected function getActionLink($shareId) {
394
		$urlGenerator = \OC::$server->getURLGenerator();
395
		$link = $urlGenerator->getAbsoluteURL(
396
			$urlGenerator->linkTo('', self::ACTION_URL . $shareId)
397
		);
398
		return $link;
399
	}
400
401
	/**
402
	 * Get file
403
	 *
404
	 * @param string $user
405
	 * @param int $fileSource
406
	 *
407
	 * @return array with internal path of the file and a absolute link to it
408
	 */
409
	protected function getFile($user, $fileSource) {
410
		\OC_Util::setupFS($user);
411
412
		try {
413
			$file = \OC\Files\Filesystem::getPath($fileSource);
414
		} catch (NotFoundException $e) {
415
			$file = null;
416
		}
417
		// FIXME:  use permalink here, see ViewController for reference
418
		$args = \OC\Files\Filesystem::is_dir($file)
419
			? ['dir' => $file]
420
			: ['dir' => \dirname($file), 'scrollto' => $file];
421
		$link = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
422
423
		return [$file, $link];
424
	}
425
426
	/**
427
	 * Check if we are the initiator or the owner of a re-share
428
	 * and return the correct UID
429
	 *
430
	 * @param IShare $share
431
	 *
432
	 * @return string
433
	 */
434
	protected function getCorrectUid(IShare $share) {
435
		if ($this->userManager->userExists($share->getShareOwner())) {
436
			return $share->getShareOwner();
437
		}
438
439
		return $share->getSharedBy();
440
	}
441
}
442