Completed
Pull Request — master (#32545)
by Tom
08:55
created

TransferRequestManager::newTransferRequest()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 10
nop 3
dl 0
loc 55
rs 7.7373
c 0
b 0
f 0

How to fix   Long Method   

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:

1
<?php
2
/**
3
 * @author Tom Needham <[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\Files\Service\TransferOwnership;
23
24
use OCA\Files\BackgroundJob\TransferOwnership;
25
use OCP\AppFramework\Db\DoesNotExistException;
26
use OCP\AppFramework\Utility\ITimeFactory;
27
use OCP\BackgroundJob\IJobList;
28
use OCP\Files\IRootFolder;
29
use OCP\Files\NotFoundException;
30
use OCP\Files\NotPermittedException;
31
use OCP\Files\Storage\IPersistentLockingStorage;
32
use OCP\IL10N;
33
use OCP\IURLGenerator;
34
use OCP\IUser;
35
use OCP\IUserManager;
36
use OCP\L10N\IFactory;
37
use OCP\Lock\Persistent\ILock;
38
use OCP\Notification\IManager;
39
use OCP\Notification\INotification;
40
use OCP\Notification\INotifier;
41
use OCP\Util;
42
43
class TransferRequestManager implements INotifier {
44
45
	/** @var IRootFolder */
46
	protected $rootFolder;
47
	/** @var IManager */
48
	protected $notificationManager;
49
	/** @var IUserManager  */
50
	protected $userManager;
51
	/** @var ITimeFactory */
52
	protected $timeFactory;
53
	/** @var TransferRequestMapper  */
54
	protected $requestMapper;
55
	/** @var IURLGenerator  */
56
	protected $urlGenerator;
57
	/** @var IFactory */
58
	protected $factory;
59
	/** @var IJobList */
60
	protected $jobList;
61
62
	public function __construct(
63
		IRootFolder $rootFolder,
64
		IManager $notificationManager,
65
		IUserManager $userManager,
66
		ITimeFactory $timeFactory,
67
		TransferRequestMapper $requestMapper,
68
		IURLGenerator $urlGenerator,
69
		IFactory $factory,
70
		IJobList $jobList) {
71
		$this->rootFolder = $rootFolder;
72
		$this->notificationManager = $notificationManager;
73
		$this->userManager = $userManager;
74
		$this->timeFactory = $timeFactory;
75
		$this->requestMapper = $requestMapper;
76
		$this->urlGenerator = $urlGenerator;
77
		$this->factory = $factory;
78
		$this->jobList = $jobList;
79
	}
80
81
	/**
82
	 * @param IUser $sourceUser
83
	 * @param IUser $destinationUser
84
	 * @param $fileId
85
	 * @throws NotFoundException
86
	 * @throws \Exception
87
	 */
88
	public function newTransferRequest(IUser $sourceUser, IUser $destinationUser, $fileId) {
89
		// Cannot give to self
90
		if ($sourceUser->getUID() === $destinationUser->getUID()) {
91
			throw new \Exception('Cannot transfer to self');
92
		}
93
		// Check node exists
94
		$sourceFolder = $this->rootFolder->getById($fileId)[0];
95
		// Check source user owns the node
96
		if ($sourceFolder->getOwner()->getUID() !== $sourceUser->getUID()) {
97
			throw new NotPermittedException('Cannot move a file you dont own');
98
		}
99
		// Check the folder is on persistent lockable storage otherwise we can't do this in the background
100
		if (!$sourceFolder->getStorage() instanceof IPersistentLockingStorage) {
101
			throw new \Exception('Source folder storage not lockable');
102
		}
103
		// Check therer is no request with the same signature
104
		if (count($this->requestMapper->findRequestWithSameSignature($sourceUser->getUID(), $destinationUser->getUID(), $fileId)) > 0) {
105
			// There is
106
			throw new \Exception('There is already a request to transfer this file/folder');
107
		}
108
		// Check we are not trying to request a transfer for a folder that is inside a current request
109
		$folder = $sourceFolder;
110
		$fileids = [$folder->getId()];
111
		while($folder->getPath() !== '/') {
112
			$folder = $folder->getParent();
113
			$fileids[] = $folder->getId();
114
		}
115
		if (count($this->requestMapper->findOpenRequestForGivenFiles($fileids)) > 0) {
116
			throw new \Exception('This file/folder is already pending an existing transfer');
117
		}
118
119
		// Create the transfer request object
120
		$request = new TransferRequest();
121
		$request->setRequestedTime($this->timeFactory->getTime());
122
		$request->setSourceUserId($sourceUser->getUID());
123
		$request->setDestinationUserId($destinationUser->getUID());
124
		$request->setFileId($fileId);
125
		$request = $this->requestMapper->insert($request);
126
127
		/** @var IPersistentLockingStorage $storage */
128
		$storage = $sourceFolder->getStorage();
129
		try {
130
			$storage->lockNodePersistent($sourceFolder->getInternalPath(), [
131
				'depth' => ILock::LOCK_DEPTH_INFINITE,
132
				'token' => $this->getLockTokenFromRequest($request),
0 ignored issues
show
Compatibility introduced by
$request of type object<OCP\AppFramework\Db\Entity> is not a sub-type of object<OCA\Files\Service...ership\TransferRequest>. It seems like you assume a child class of the class OCP\AppFramework\Db\Entity to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
133
				'timeout' => 60*60*24 // 24 hours to allow a cron run and acceptance
134
			]);
135
		} catch (\Exception $e) {
136
			// Cleanup transfer request and fail
137
			$this->requestMapper->delete($request);
138
			throw $e;
139
		}
140
141
		$this->sendRequestNotification($request);
0 ignored issues
show
Compatibility introduced by
$request of type object<OCP\AppFramework\Db\Entity> is not a sub-type of object<OCA\Files\Service...ership\TransferRequest>. It seems like you assume a child class of the class OCP\AppFramework\Db\Entity to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
142
	}
143
144
	public function acceptRequest(TransferRequest $request) {
145 View Code Duplication
		if ($request->getAcceptedTime() !== null || $request->getActionedTime() !== null || $request->getRejectedTime() !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
			throw new \Exception('Already actioned, accepted or rejected');
147
		}
148
		// Create a background job, update accepted time
149
		$request->setAcceptedTime($this->timeFactory->getTime());
150
		$this->requestMapper->update($request);
151
		$sourcePath = $this->rootFolder->getUserFolder(
152
			$request->getSourceUserId())->getById($request->getFileId())[0]->getInternalPath();
153
		$this->jobList->add(TransferOwnership::class, json_encode([
154
			'requestId' => $request->getId(),
155
		]));
156
		$notification = $this->notificationManager->createNotification();
157
		$notification->setApp('files')
158
			->setUser($request->getDestinationUserId())
159
			->setObject('transfer_request', $request->getId());
160
		$this->notificationManager->markProcessed($notification);
161
	}
162
163
	public function rejectRequest(TransferRequest $request) {
164
		// Cleanup the lock, save reject timestamp
165 View Code Duplication
		if ($request->getAcceptedTime() !== null || $request->getActionedTime() !== null || $request->getRejectedTime() !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
			throw new \Exception('Already actioned, accepted or rejected');
167
		}
168
		// Create a background job, update accepted time
169
		$request->setRejectedTime($this->timeFactory->getTime());
170
		$this->requestMapper->update($request);
171
		$notification = $this->notificationManager->createNotification();
172
		$notification->setApp('files')
173
			->setUser($request->getDestinationUserId())
174
			->setObject('transfer_request', $request->getId());
175
		$this->notificationManager->markProcessed($notification);
176
		$file = $this->rootFolder->getById($request->getFileId())[0];
177
		/** @var IPersistentLockingStorage $storage */
178
		$storage = $file->getStorage();
179
		$storage->unlockNodePersistent($file->getInternalPath(), ['token' => $this->getLockTokenFromRequest($request)]);
180
	}
181
182
	public function deleteRequest(TransferRequest $request) {
183
		// Cleanup the lock and the notification
184
		$this->requestMapper->delete($request);
185
		$notification = $this->notificationManager->createNotification();
186
		$notification->setApp('files')
187
			->setUser($request->getDestinationUserId())
188
			->setObject('transfer_request', $request->getId());
189
		$this->notificationManager->markProcessed($notification);
190
		$file = $this->rootFolder->getById($request->getFileId())[0];
191
		/** @var IPersistentLockingStorage $storage */
192
		$storage = $file->getStorage();
193
		$storage->unlockNodePersistent($file->getInternalPath(), ['token' => $this->getLockTokenFromRequest($request)]);
194
	}
195
196
197
	/**
198
	 * @param TransferRequest $request the request object
199
	 */
200
	protected function sendRequestNotification(TransferRequest $request) {
201
		$time = new \DateTime();
202
		$time->setTimestamp($this->timeFactory->getTime());
203
		$notification = $this->notificationManager->createNotification();
204
		$notification->setApp('files')
205
			->setUser($request->getDestinationUserId())
206
			->setDateTime($time)
207
			->setObject('transfer_request', $request->getId());
208
209
		$notification->setIcon(
210
			$this->urlGenerator->imagePath('core', 'actions/give.svg')
211
		);
212
213
		$sourceUser = $this->userManager->get($request->getSourceUserId());
214
		$folder = $this->rootFolder->getById($request->getFileId())[0];
215
		$notification->setSubject("new_transfer_request");
216
		$notification->setMessage("new_transfer_request", [$sourceUser->getDisplayName(), $folder->getName(), Util::humanFileSize($folder->getSize())]);
217
218
		$endpoint = $this->urlGenerator->linkToRouteAbsolute(
219
			'files.Transfer.accept',
220
			['requestId' => $request->getId()]
221
		);
222
		$declineAction = $notification->createAction();
223
		$declineAction->setLabel('reject');
224
		$declineAction->setLink($endpoint, 'DELETE');
225
		$notification->addAction($declineAction);
226
227
		$acceptAction = $notification->createAction();
228
		$acceptAction->setLabel('accept');
229
		$acceptAction->setLink($endpoint, 'POST');
230
		$acceptAction->setPrimary(true);
231
		$notification->addAction($acceptAction);
232
233
		$this->notificationManager->notify($notification);
234
	}
235
236
	public function prepare(INotification $notification, $languageCode) {
237
		if ($notification->getApp() !== 'files') {
238
			throw new \InvalidArgumentException();
239
		}
240
241
		// Read the language from the notification
242
		$l = $this->factory->get('files', $languageCode);
243
244
		switch ($notification->getObjectType()) {
245
			case 'transfer_request':
246
				$requestId = $notification->getObjectId();
247
				try {
248
					$this->requestMapper->findById($requestId);
249
				} catch (DoesNotExistException $ex) {
250
					$this->notificationManager->markProcessed($notification);
251
					throw new \InvalidArgumentException();
252
				}
253
				return $this->formatNotification($notification, $l);
254
255
			default:
256
				throw new \InvalidArgumentException();
257
		}
258
	}
259
260
	protected function formatNotification(INotification $notification, IL10N $l) {
261
		switch($notification->getObjectType()) {
262
			case 'transfer_request':
263
				$notification->setParsedSubject((string) $l->t('A user would like to transfer a folder to you'));
264
				$notification->setParsedMessage(
265
					(string) $l->t(
266
						'"%1$s" requested to transfer "%2$s" to you (%3$s)"',
267
						$notification->getMessageParameters())
268
				);
269 View Code Duplication
				foreach ($notification->getActions() as $action) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
270
					switch ($action->getLabel()) {
271
						case 'accept':
272
							$action->setParsedLabel(
273
								(string) $l->t('Accept')
274
							);
275
							break;
276
						case 'reject':
277
							$action->setParsedLabel(
278
								(string) $l->t('Decline')
279
							);
280
							break;
281
					}
282
					$notification->addParsedAction($action);
283
				}
284
				return $notification;
285
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
286 View Code Duplication
			case 'transfer_request_actioned_source':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
287
				$notification->setParsedSubject((string) $l->t('Transfer completed'));
288
				$notification->setParsedMessage(
289
					(string) $l->t(
290
						'"%1$s" accepted your transfer of "%2$s" and it was completed',
291
						$notification->getMessageParameters())
292
				);
293
				return $notification;
294
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
295 View Code Duplication
			case 'transfer_request_actioned_destination':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
296
				$notification->setParsedSubject((string) $l->t('Transfer completed'));
297
				$notification->setParsedMessage(
298
					(string) $l->t(
299
						'"%1$s" was transferred to you from "%2$s"',
300
						$notification->getMessageParameters())
301
				);
302
				return $notification;
303
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
304 View Code Duplication
			case 'transfer_request_failed_destination':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
				$notification->setParsedSubject((string) $l->t('Transfer failed'));
306
				$notification->setParsedMessage(
307
					(string) $l->t(
308
						'The transfer of "%1$s" from "%2$s failed. Ask the sender to try again."',
309
						$notification->getMessageParameters())
310
				);
311
				return $notification;
312
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
313 View Code Duplication
			case 'transfer_request_failed_source':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
314
				$notification->setParsedSubject((string) $l->t('Transfer failed'));
315
				$notification->setParsedMessage(
316
					(string) $l->t(
317
						'The transfer of "%1$s" to "%2$s" failed with message: "%3$s"',
318
						$notification->getMessageParameters())
319
				);
320
				return $notification;
321
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
322
			default:
323
				throw new \InvalidArgumentException('Not a notifcation that can be formatted by this class');
324
		}
325
326
	}
327
328
	public function actionRequest(TransferRequest $request) {
329
		$request->setActionedTime($this->timeFactory->getTime());
330
		$this->requestMapper->update($request);
331
		// Notify the source user it was accepted
332
		$this->notifyActioned($request);
333
	}
334
335
	/**
336
	 * Cleanup and notify
337
	 * @param TransferRequest $request
338
	 * @throws NotFoundException
339
	 * @throws \OCP\Files\InvalidPathException
340
	 */
341
	public function actionRequestFailure(TransferRequest $request, $message = null) {
342
		// Notify the users that it failed
343
		$this->notifyActionedFailure($request, $message);
344
		$this->cleanupRequest($request);
345
346
	}
347
348
	/**
349
	 * Tell the source user and destination user that the transfer has happened
350
	 * @param TransferRequest $request
351
	 * @throws NotFoundException
352
	 * @throws \OCP\Files\InvalidPathException
353
	 */
354
	public function notifyActioned(TransferRequest $request) {
355
		// Set to now
356
		$time = new \DateTime();
357
		$time->setTimestamp($request->getActionedTime());
358
		$notification = $this->notificationManager->createNotification();
359
		$notification->setApp('files')
360
			->setUser($request->getSourceUserId())
361
			->setDateTime($time)
362
			->setObject('transfer_request', $request->getId());
363
364
		$notification->setIcon(
365
			$this->urlGenerator->imagePath('core', 'actions/give.svg')
366
		);
367
368
		$destinationUser = $this->userManager->get($request->getDestinationUserId());
369
		$folder = $this->rootFolder->getById($request->getFileId())[0];
370
		$notification->setSubject("transfer_request_actioned_source");
371
		$notification->setMessage("transfer_request_actioned_source", [$destinationUser->getDisplayName(), $folder->getName()]);
372
		$this->notificationManager->notify($notification);
373
374
		// Set to now
375
		$time = new \DateTime();
376
		$time->setTimestamp($request->getActionedTime());
377
		$notification = $this->notificationManager->createNotification();
378
		$notification->setApp('files')
379
			->setUser($request->getDestinationUserId())
380
			->setDateTime($time)
381
			->setObject('transfer_request', $request->getId());
382
383
		$notification->setIcon(
384
			$this->urlGenerator->imagePath('core', 'actions/give.svg')
385
		);
386
387
		$sourceUser = $this->userManager->get($request->getSourceUserId());
388
		$folder = $this->rootFolder->getById($request->getFileId())[0];
389
		$notification->setSubject("transfer_request_actioned_destination");
390
		$notification->setMessage("transfer_request_actioned_destination", [$folder->getName(), $sourceUser->getDisplayName()]);
391
		$this->notificationManager->notify($notification);
392
	}
393
394
	/**
395
	 * Tell the source user and destination user that the transfer failed
396
	 * @param TransferRequest $request
397
	 * @throws NotFoundException
398
	 * @throws \OCP\Files\InvalidPathException
399
	 */
400
	public function notifyActionedFailure(TransferRequest $request, $message = null) {
401
		// Set to now
402
		$time = new \DateTime();
403
		$time->setTimestamp($this->timeFactory->getTime());
404
		$notification = $this->notificationManager->createNotification();
405
		$notification->setApp('files')
406
			->setUser($request->getSourceUserId())
407
			->setDateTime($time)
408
			->setObject('transfer_request', $request->getId());
409
410
		$notification->setIcon(
411
			$this->urlGenerator->imagePath('core', 'actions/give.svg')
412
		);
413
414
		$destinationUser = $this->userManager->get($request->getDestinationUserId());
415
		$folder = $this->rootFolder->getById($request->getFileId())[0];
416
		$notification->setSubject("transfer_request_failed_source");
417
		$notification->setMessage("transfer_request_failed_source", [$folder->getName(), $destinationUser->getDisplayName(), $message]);
418
		$this->notificationManager->notify($notification);
419
420
		// Set to now
421
		$time = new \DateTime();
422
		$time->setTimestamp($this->timeFactory->getTime());
423
		$notification = $this->notificationManager->createNotification();
424
		$notification->setApp('files')
425
			->setUser($request->getDestinationUserId())
426
			->setDateTime($time)
427
			->setObject('transfer_request', $request->getId());
428
429
		$notification->setIcon(
430
			$this->urlGenerator->imagePath('core', 'actions/give.svg')
431
		);
432
433
		$sourceUser = $this->userManager->get($request->getSourceUserId());
434
		$folder = $this->rootFolder->getById($request->getFileId())[0];
435
		$notification->setSubject("transfer_request_failed_destination");
436
		$notification->setMessage("transfer_request_failed_destination", [$folder->getName(), $sourceUser->getDisplayName()]);
437
		$this->notificationManager->notify($notification);
438
	}
439
440
	/**
441
	 * Background job for cleaning up old requests, removes notifications, request and locks
442
	 */
443
	public function cleanup() {
444
		// Delete request that are older than 24 hours
445
		$oldRequests = $this->requestMapper->findOpenRequestsOlderThan(1);
446
		/** @var TransferRequest $request */
447
		foreach ($oldRequests as $request) {
448
			$this->cleanupRequest($request);
449
		}
450
	}
451
452
	/**
453
	 * Delete request, delete lock, and delete requested notification
454
	 * @param TransferRequest $request
455
	 */
456
	protected function cleanupRequest(TransferRequest $request) {
457
		// Remove the lock
458
		try {
459
			$file = $this->rootFolder->getById($request->getFileId())[0];
460
			/** @var IPersistentLockingStorage $storage */
461
			$storage = $file->getStorage();
462
			$storage->unlockNodePersistent($file->getInternalPath(), ['token' => $this->getLockTokenFromRequest($request)]);
463
		} catch (\Exception $e) {
464
			\OC::$server->getLogger()->logException($e, ['app' => 'files']);
465
		}
466
		// Now remove the request
467
		$this->requestMapper->delete($request);
468
		// And lets remove the notification to save confusion
469
		$notification = $this->notificationManager->createNotification();
470
		$notification->setApp('files')
471
			->setUser($request->getDestinationUserId())
472
			->setObject('transfer_request', $request->getId());
473
		$this->notificationManager->markProcessed($notification);
474
	}
475
476
	/**
477
	 * Helper to get the lock token id associated with a request
478
	 * @param TransferRequest $request
479
	 * @return string
480
	 */
481
	protected function getLockTokenFromRequest(TransferRequest $request) {
482
		return 'transfer-request-'.$request->getId();
483
	}
484
485
	/**
486
	 * Helper to get a request object from the mapper without another dep injection
487
	 * @param $requestId
488
	 * @return TransferRequest|\OCP\AppFramework\Db\Entity
489
	 * @throws DoesNotExistException
490
	 * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
491
	 */
492
	public function getRequestById($requestId) {
493
		return $this->requestMapper->findById($requestId);
494
	}
495
496
497
}