Completed
Pull Request — master (#608)
by Sujith
127:21 queued 124:47
created

FilesHooks::share()   C

Complexity

Conditions 7
Paths 10

Size

Total Lines 24
Code Lines 20

Duplication

Lines 18
Ratio 75 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 18
loc 24
ccs 0
cts 24
cp 0
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 20
nc 10
nop 1
crap 56
1
<?php
2
/**
3
 * @author Frank Karlitschek <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Thomas Müller <[email protected]>
6
 *
7
 * @copyright Copyright (c) 2016, ownCloud, Inc.
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
namespace OCA\Activity;
25
26
use OC\Files\Filesystem;
27
use OC\Files\View;
28
use OCA\Activity\Extension\Files;
29
use OCA\Activity\Extension\Files_Sharing;
30
use OCP\Activity\IManager;
31
use OCP\Files\Mount\IMountPoint;
32
use OCP\Files\NotFoundException;
33
use OCP\IDBConnection;
34
use OCP\IGroup;
35
use OCP\IGroupManager;
36
use OCP\IURLGenerator;
37
use OCP\IUser;
38
use OCP\Share;
39
use Symfony\Component\EventDispatcher\GenericEvent;
40
41
/**
42
 * The class to handle the filesystem hooks
43
 */
44
class FilesHooks {
45
	const USER_BATCH_SIZE = 50;
46
47
	/** @var \OCP\Activity\IManager */
48
	protected $manager;
49
50
	/** @var \OCA\Activity\Data */
51
	protected $activityData;
52
53
	/** @var \OCA\Activity\UserSettings */
54
	protected $userSettings;
55
56
	/** @var \OCP\IGroupManager */
57
	protected $groupManager;
58
59
	/** @var \OCP\IDBConnection */
60
	protected $connection;
61
62
	/** @var \OC\Files\View */
63
	protected $view;
64
65
	/** @var IURLGenerator */
66
	protected $urlGenerator;
67
68
	/** @var string|false */
69
	protected $currentUser;
70
71
	/**
72
	 * Constructor
73
	 *
74
	 * @param IManager $manager
75
	 * @param Data $activityData
76
	 * @param UserSettings $userSettings
77
	 * @param IGroupManager $groupManager
78
	 * @param View $view
79
	 * @param IDBConnection $connection
80
	 * @param IURLGenerator $urlGenerator
81
	 * @param string|false $currentUser
82
	 */
83 49
	public function __construct(IManager $manager, Data $activityData, UserSettings $userSettings, IGroupManager $groupManager, View $view, IDBConnection $connection, IURLGenerator $urlGenerator, $currentUser) {
84 49
		$this->manager = $manager;
85 49
		$this->activityData = $activityData;
86 49
		$this->userSettings = $userSettings;
87 49
		$this->groupManager = $groupManager;
88 49
		$this->view = $view;
89 49
		$this->connection = $connection;
90 49
		$this->urlGenerator = $urlGenerator;
91 49
		$this->currentUser = $currentUser;
92 49
	}
93
94
	/**
95
	 * @return string|false Current UserID if logged in, false otherwise
96
	 */
97 2
	protected function getCurrentUser() {
98 2
		return $this->currentUser;
99
	}
100
101
	/**
102
	 * Store the create hook events
103
	 * @param string $path Path of the file that has been created
104
	 */
105 2
	public function fileCreate($path) {
106 2
		if ($this->getCurrentUser() !== false) {
107 1
			$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CREATED, 'created_self', 'created_by');
108 1
		} else {
109 1
			$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CREATED, '', 'created_public');
110
		}
111 2
	}
112
113
	/**
114
	 * Store the update hook events
115
	 * @param string $path Path of the file that has been modified
116
	 */
117 1
	public function fileUpdate($path) {
118 1
		$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CHANGED, 'changed_self', 'changed_by');
119 1
	}
120
121
	/**
122
	 * Store the delete hook events
123
	 * @param string $path Path of the file that has been deleted
124
	 */
125 1
	public function fileDelete($path) {
126 1
		$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_DELETED, 'deleted_self', 'deleted_by');
127 1
	}
128
129
	/**
130
	 * Store the restore hook events
131
	 * @param string $path Path of the file that has been restored
132
	 */
133 1
	public function fileRestore($path) {
134 1
		$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_RESTORED, 'restored_self', 'restored_by');
135 1
	}
136
137
	/**
138
	 * Creates the entries for file actions on $file_path
139
	 *
140
	 * @param string $filePath         The file that is being changed
141
	 * @param int    $activityType     The activity type
142
	 * @param string $subject          The subject for the actor
143
	 * @param string $subjectBy        The subject for other users (with "by $actor")
144
	 */
145 3
	protected function addNotificationsForFileAction($filePath, $activityType, $subject, $subjectBy) {
146
		// Do not add activities for .part-files
147 3
		if (substr($filePath, -5) === '.part') {
148 1
			return;
149
		}
150
151 2
		list($filePath, $uidOwner, $fileId) = $this->getSourcePathAndOwner($filePath);
152 2
		if (!$fileId) {
153
			// no owner, possibly deleted or unknown
154
			// skip notifications
155
			return;
156
		}
157 2
		$affectedUsers = $this->getUserPathsFromPath($filePath, $uidOwner);
158 2
		$filteredStreamUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'stream', $activityType);
159 2
		$filteredEmailUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'email', $activityType);
160
161 2
		foreach ($affectedUsers as $user => $path) {
162 2
			if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) {
163 2
				continue;
164
			}
165
166 2
			if ($user === $this->currentUser) {
167 1
				$userSubject = $subject;
168 1
				$userParams = [[$fileId => $path]];
169 1
			} else {
170 1
				$userSubject = $subjectBy;
171 1
				$userParams = [[$fileId => $path], $this->currentUser];
172
			}
173
174 2
			$this->addNotificationsForUser(
175 2
				$user, $userSubject, $userParams,
176 2
				$fileId, $path, true,
177 2
				!empty($filteredStreamUsers[$user]),
178 2
				!empty($filteredEmailUsers[$user]) ? $filteredEmailUsers[$user] : 0,
179
				$activityType
180 2
			);
181 2
		}
182 2
	}
183
184
	/**
185
	 * Returns a "username => path" map for all affected users
186
	 *
187
	 * @param string $path
188
	 * @param string $uidOwner
189
	 * @return array
190
	 */
191
	protected function getUserPathsFromPath($path, $uidOwner) {
192
		return Share::getUsersSharingFile($path, $uidOwner, true, true);
193
	}
194
195
	/**
196
	 * Return the source
197
	 *
198
	 * @param string $path
199
	 * @return array
200
	 */
201
	protected function getSourcePathAndOwner($path) {
202
		$currentUserView = Filesystem::getView();
203
		$uidOwner = $currentUserView->getOwner($path);
204
		$fileId = 0;
205
206
		if ($uidOwner !== $this->currentUser) {
207
			list($storage, $internalPath) = $currentUserView->resolvePath($path);
0 ignored issues
show
Unused Code introduced by
The assignment to $internalPath is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
208
			if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
209
				// for federated shares we don't have access to the remote user, use the current one
210
				// which will also make it use the matching local "shared::" federated share storage instead
211
				$uidOwner = $this->currentUser;
212
			} else {
213
				Filesystem::initMountPoints($uidOwner);
214
			}
215
		}
216
		$info = Filesystem::getFileInfo($path);
217
		if ($info !== false) {
218
			$ownerView = new View('/' . $uidOwner . '/files');
219
			$fileId = (int) $info['fileid'];
220
			$path = $ownerView->getPath($fileId);
221
		}
222
223
		return array($path, $uidOwner, $fileId);
224
	}
225
226
	/**
227
	 * Manage sharing events
228
	 * @param GenericEvent $params The hook params
229
	 */
230
	public function share(GenericEvent $params) {
231
		\OC::$server->getLogger()->warning(__METHOD__ . " LOOPING . First take the count = " . count($params->getArguments()));
232
		foreach ($params->getArguments() as $argument) {
233
			\OC::$server->getLogger()->warning(__METHOD__ . " val = $argument");
234
		}
235 View Code Duplication
		if ($params->getArgument('itemType') === 'file' || $params->getArgument('itemType') === 'folder') {
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...
236
			if ((int) $params->getArgument('shareType') === Share::SHARE_TYPE_USER) {
237
				$this->shareFileOrFolderWithUser($params->getArgument('shareWith'),
238
					(int) $params->getArgument('fileSource'),
239
					$params->getArgument('itemType'),
240
					$params->getArgument('fileTarget'), true);
241
			} else if ((int) $params->getArgument('shareType') === Share::SHARE_TYPE_GROUP) {
242
				$this->shareFileOrFolderWithGroup($params->getArgument('shareWith'),
243
					(int) $params->getArgument('fileSource'),
244
					$params->getArgument('itemType'),
245
					$params->getArgument('fileTarget'),
246
					(int) $params->getArgument('id'), true);
247
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) {
248
				$this->shareFileOrFolderByLink((int) $params->getArgument('fileSource'),
249
					$params->getArgument('itemType'),
250
					$params->getArgument('uidOwner'), true);
251
			}
252
		}
253
	}
254
255
	/**
256
	 * Manage sharing events
257
	 * @param GenericEvent $params The hook params
258
	 */
259
	public function unShare(GenericEvent $params) {
260 View Code Duplication
		if ($params->getArgument('itemType') === 'file' || $params->getArgument('itemType') === 'folder') {
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...
261
			if ((int) $params->getArgument('shareType') === Share::SHARE_TYPE_USER) {
262
				$this->shareFileOrFolderWithUser($params->getArgument('shareWith'),
263
					(int) $params->getArgument('fileSource'),
264
					$params->getArgument('itemType'),
265
					$params->getArgument('fileTarget'), false);
266
			} else if ((int) $params->getArgument('shareType') === Share::SHARE_TYPE_GROUP) {
267
				$this->shareFileOrFolderWithGroup($params->getArgument('shareWith'),
268
					(int) $params->getArgument('fileSource'),
269
					$params->getArgument('itemType'),
270
					$params->getArgument('fileTarget'),
271
					(int) $params->getArgument('id'), false);
272
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) {
273
				$this->shareFileOrFolderByLink((int) $params->getArgument('fileSource'),
274
					$params->getArgument('itemType'),
275
					$params->getArgument('uidOwner'), false);
276
			}
277
		}
278
	}
279
280
	/**
281
	 * Sharing a file or folder with a user
282
	 *
283
	 * @param string $shareWith
284
	 * @param int $fileSource File ID that is being shared
285
	 * @param string $itemType File type that is being shared (file or folder)
286
	 * @param string $fileTarget File path
287
	 * @param bool $isSharing True if sharing, false if unsharing
288
	 */
289 2
	protected function shareFileOrFolderWithUser($shareWith, $fileSource, $itemType, $fileTarget, $isSharing) {
290 2
		if ($isSharing) {
291 2
			$actionSharer = 'shared_user_self';
292 2
			$actionOwner = 'reshared_user_by';
293 2
			$actionUser = 'shared_with_by';
294 2
		} else {
295
			$actionSharer = 'unshared_user_self';
296
			$actionOwner = 'unshared_user_by';
297
			$actionUser = 'unshared_by';
298
		}
299
300
		// User performing the share
301 2
		$this->shareNotificationForSharer($actionSharer, $shareWith, $fileSource, $itemType);
302 2
		$this->shareNotificationForOriginalOwners($this->currentUser, $actionOwner, $shareWith, $fileSource, $itemType);
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\FilesHooks:...tionForOriginalOwners() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
303
304
		// New shared user
305 2
		$this->addNotificationsForUser(
306 2
			$shareWith, $actionUser, [[$fileSource => $fileTarget], $this->currentUser],
307 2
			(int) $fileSource, $fileTarget, ($itemType === 'file'),
308 2
			$this->userSettings->getUserSetting($shareWith, 'stream', Files_Sharing::TYPE_SHARED),
0 ignored issues
show
Bug introduced by
It seems like $this->userSettings->get...s_Sharing::TYPE_SHARED) targeting OCA\Activity\UserSettings::getUserSetting() can also be of type integer; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
309 2
			$this->userSettings->getUserSetting($shareWith, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($shareWith, 'setting', 'batchtime') : 0
0 ignored issues
show
Bug introduced by
It seems like $this->userSettings->get...ting', 'batchtime') : 0 can also be of type boolean; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
310 2
		);
311 2
	}
312
313
	/**
314
	 * Sharing a file or folder with a group
315
	 *
316
	 * @param string $shareWith
317
	 * @param int $fileSource File ID that is being shared
318
	 * @param string $itemType File type that is being shared (file or folder)
319
	 * @param string $fileTarget File path
320
	 * @param int $shareId The Share ID of this share
321
	 * @param bool $isSharing True if sharing, false if unsharing
322
	 */
323 6
	protected function shareFileOrFolderWithGroup($shareWith, $fileSource, $itemType, $fileTarget, $shareId, $isSharing) {
324 6
		if ($isSharing) {
325 6
			$actionSharer = 'shared_group_self';
326 6
			$actionOwner = 'reshared_group_by';
327 6
			$actionUser = 'shared_with_by';
328 6
		} else {
329
			$actionSharer = 'unshared_group_self';
330
			$actionOwner = 'unshared_group_by';
331
			$actionUser = 'unshared_by';
332
		}
333
334
		// Members of the new group
335 6
		$group = $this->groupManager->get($shareWith);
336 6
		if (!($group instanceof IGroup)) {
0 ignored issues
show
Bug introduced by
The class OCP\IGroup does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
337 1
			return;
338
		}
339
340
		// User performing the share
341 5
		$this->shareNotificationForSharer($actionSharer, $shareWith, $fileSource, $itemType);
342 5
		$this->shareNotificationForOriginalOwners($this->currentUser, $actionOwner, $shareWith, $fileSource, $itemType);
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\FilesHooks:...tionForOriginalOwners() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
343
344 5
		$offset = 0;
345 5
		$users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset);
346 5
		while (!empty($users)) {
347 4
			$this->addNotificationsForGroupUsers($users, $actionUser, $fileSource, $itemType, $fileTarget, $shareId);
348 4
			$offset += self::USER_BATCH_SIZE;
349 4
			$users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset);
350 4
		}
351 5
	}
352
353
	/**
354
	 * @param IUser[] $usersInGroup
355
	 * @param string $actionUser
356
	 * @param int $fileSource File ID that is being shared
357
	 * @param string $itemType File type that is being shared (file or folder)
358
	 * @param string $fileTarget File path
359
	 * @param int $shareId The Share ID of this share
360
	 */
361 4
	protected function addNotificationsForGroupUsers(array $usersInGroup, $actionUser, $fileSource, $itemType, $fileTarget, $shareId) {
362 4
		$affectedUsers = [];
363
364 4
		foreach ($usersInGroup as $user) {
365 4
			$affectedUsers[$user->getUID()] = $fileTarget;
366 4
		}
367
368
		// Remove the triggering user, we already managed his notifications
369 4
		unset($affectedUsers[$this->currentUser]);
370
371 4
		if (empty($affectedUsers)) {
372 1
			return;
373
		}
374
375 3
		$userIds = array_keys($affectedUsers);
376 3
		$filteredStreamUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'stream', Files_Sharing::TYPE_SHARED);
377 3
		$filteredEmailUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'email', Files_Sharing::TYPE_SHARED);
378
379 3
		$affectedUsers = $this->fixPathsForShareExceptions($affectedUsers, $shareId);
380 3
		foreach ($affectedUsers as $user => $path) {
381 3
			if (empty($filteredStreamUsersInGroup[$user]) && empty($filteredEmailUsersInGroup[$user])) {
382 2
				continue;
383
			}
384
385 1
			$this->addNotificationsForUser(
386 1
				$user, $actionUser, [[$fileSource => $path], $this->currentUser],
387 1
				$fileSource, $path, ($itemType === 'file'),
388 1
				!empty($filteredStreamUsersInGroup[$user]),
389 1
				!empty($filteredEmailUsersInGroup[$user]) ? $filteredEmailUsersInGroup[$user] : 0
390 1
			);
391 3
		}
392 3
	}
393
394
	/**
395
	 * Check when there was a naming conflict and the target is different
396
	 * for some of the users
397
	 *
398
	 * @param array $affectedUsers
399
	 * @param int $shareId
400
	 * @return mixed
401
	 */
402
	protected function fixPathsForShareExceptions(array $affectedUsers, $shareId) {
403
		$queryBuilder = $this->connection->getQueryBuilder();
404
		$queryBuilder->select(['share_with', 'file_target'])
405
			->from('share')
406
			->where($queryBuilder->expr()->eq('parent', $queryBuilder->createParameter('parent')))
407
			->setParameter('parent', (int) $shareId);
408
		$query = $queryBuilder->execute();
409
410
		while ($row = $query->fetch()) {
411
			$affectedUsers[$row['share_with']] = $row['file_target'];
412
		}
413
414
		return $affectedUsers;
415
	}
416
417
	/**
418
	 * Sharing a file or folder via link/public
419
	 *
420
	 * @param int $fileSource File ID that is being shared
421
	 * @param string $itemType File type that is being shared (file or folder)
422
	 * @param string $linkOwner
423
	 * @param bool $isSharing True if sharing, false if unsharing
424
	 */
425 2
	protected function shareFileOrFolderByLink($fileSource, $itemType, $linkOwner, $isSharing) {
426 2
		if ($isSharing) {
427 2
			$actionSharer = 'shared_link_self';
428 2
			$actionOwner = 'reshared_link_by';
429 2
		} else if ($this->currentUser !== $linkOwner) {
430
			// Link expired
431
			$actionSharer = 'link_expired';
432
			$actionOwner = 'link_by_expired';
433
			$this->currentUser = $linkOwner;
434
			\OC::$server->getUserFolder($linkOwner);
435
		} else {
436
			$actionSharer = 'unshared_link_self';
437
			$actionOwner = 'unshared_link_by';
438
		}
439
440 2
		$this->view->chroot('/' . $this->currentUser . '/files');
441
442
		try {
443 2
			$path = $this->view->getPath($fileSource);
444 2
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
445 1
			return;
446
		}
447
448 1
		$this->shareNotificationForOriginalOwners($this->currentUser, $actionOwner, '', $fileSource, $itemType);
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\FilesHooks:...tionForOriginalOwners() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
449
450 1
		$this->addNotificationsForUser(
451 1
			$this->currentUser, $actionSharer, [[$fileSource => $path]],
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
452 1
			(int) $fileSource, $path, ($itemType === 'file'),
453 1
			$this->userSettings->getUserSetting($this->currentUser, 'stream', Files_Sharing::TYPE_SHARED),
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\UserSettings::getUserSetting() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Bug introduced by
It seems like $this->userSettings->get...s_Sharing::TYPE_SHARED) targeting OCA\Activity\UserSettings::getUserSetting() can also be of type integer; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
454 1
			$this->userSettings->getUserSetting($this->currentUser, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($this->currentUser, 'setting', 'batchtime') : 0
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\UserSettings::getUserSetting() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Bug introduced by
It seems like $this->userSettings->get...ting', 'batchtime') : 0 can also be of type boolean; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
455 1
		);
456 1
	}
457
458
	/**
459
	 * Add notifications for the user that shares a file/folder
460
	 *
461
	 * @param string $subject
462
	 * @param string $shareWith
463
	 * @param int $fileSource
464
	 * @param string $itemType
465
	 */
466 2
	protected function shareNotificationForSharer($subject, $shareWith, $fileSource, $itemType) {
467 2
		$this->view->chroot('/' . $this->currentUser . '/files');
468
469
		try {
470 2
			$path = $this->view->getPath($fileSource);
471 2
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
472 1
			return;
473
		}
474
475 1
		$this->addNotificationsForUser(
476 1
			$this->currentUser, $subject, [[$fileSource => $path], $shareWith],
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
477 1
			$fileSource, $path, ($itemType === 'file'),
478 1
			$this->userSettings->getUserSetting($this->currentUser, 'stream', Files_Sharing::TYPE_SHARED),
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\UserSettings::getUserSetting() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Bug introduced by
It seems like $this->userSettings->get...s_Sharing::TYPE_SHARED) targeting OCA\Activity\UserSettings::getUserSetting() can also be of type integer; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
479 1
			$this->userSettings->getUserSetting($this->currentUser, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($this->currentUser, 'setting', 'batchtime') : 0
0 ignored issues
show
Security Bug introduced by
It seems like $this->currentUser can also be of type false; however, OCA\Activity\UserSettings::getUserSetting() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Bug introduced by
It seems like $this->userSettings->get...ting', 'batchtime') : 0 can also be of type boolean; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
480 1
		);
481 1
	}
482
483
	/**
484
	 * Add notifications for the user that shares a file/folder
485
	 *
486
	 * @param string $owner
487
	 * @param string $subject
488
	 * @param string $shareWith
489
	 * @param int $fileSource
490
	 * @param string $itemType
491
	 */
492 2
	protected function reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType) {
493 2
		$this->view->chroot('/' . $owner . '/files');
494
495
		try {
496 2
			$path = $this->view->getPath($fileSource);
497 2
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
498 1
			return;
499
		}
500
501 1
		$this->addNotificationsForUser(
502 1
			$owner, $subject, [[$fileSource => $path], $this->currentUser, $shareWith],
503 1
			$fileSource, $path, ($itemType === 'file'),
504 1
			$this->userSettings->getUserSetting($owner, 'stream', Files_Sharing::TYPE_SHARED),
0 ignored issues
show
Bug introduced by
It seems like $this->userSettings->get...s_Sharing::TYPE_SHARED) targeting OCA\Activity\UserSettings::getUserSetting() can also be of type integer; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
505 1
			$this->userSettings->getUserSetting($owner, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($owner, 'setting', 'batchtime') : 0
0 ignored issues
show
Bug introduced by
It seems like $this->userSettings->get...ting', 'batchtime') : 0 can also be of type boolean; however, OCA\Activity\FilesHooks::addNotificationsForUser() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
506 1
		);
507 1
	}
508
509
	/**
510
	 * Add notifications for the owners whose files have been reshared
511
	 *
512
	 * @param string $currentOwner
513
	 * @param string $subject
514
	 * @param string $shareWith
515
	 * @param int $fileSource
516
	 * @param string $itemType
517
	 */
518 10
	protected function shareNotificationForOriginalOwners($currentOwner, $subject, $shareWith, $fileSource, $itemType) {
519
		// Get the full path of the current user
520 10
		$this->view->chroot('/' . $currentOwner . '/files');
521
522
		try {
523 10
			$path = $this->view->getPath($fileSource);
524 10
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
525 1
			return;
526
		}
527
528
		/**
529
		 * Get the original owner and his path
530
		 */
531 9
		$owner = $this->view->getOwner($path);
532 9
		if ($owner !== $currentOwner) {
533 7
			$this->reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType);
534 7
		}
535
536
		/**
537
		 * Get the sharee who shared the item with the currentUser
538
		 */
539 9
		$this->view->chroot('/' . $currentOwner . '/files');
540 9
		$mount = $this->view->getMount($path);
541 9
		if (!($mount instanceof IMountPoint)) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\Mount\IMountPoint does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
542 1
			return;
543
		}
544
545 8
		$storage = $mount->getStorage();
546 8
		if (!$storage->instanceOfStorage('OC\Files\Storage\Shared')) {
547 1
			return;
548
		}
549
550
		/** @var \OC\Files\Storage\Shared $storage */
551 7
		$shareOwner = $storage->getSharedFrom();
552 7
		if ($shareOwner === '' || $shareOwner === null || $shareOwner === $owner || $shareOwner === $currentOwner) {
553 5
			return;
554
		}
555
556 2
		$this->reshareNotificationForSharer($shareOwner, $subject, $shareWith, $fileSource, $itemType);
557 2
	}
558
559
	/**
560
	 * Adds the activity and email for a user when the settings require it
561
	 *
562
	 * @param string $user
563
	 * @param string $subject
564
	 * @param array $subjectParams
565
	 * @param int $fileId
566
	 * @param string $path
567
	 * @param bool $isFile If the item is a file, we link to the parent directory
568
	 * @param bool $streamSetting
569
	 * @param int $emailSetting
570
	 * @param string $type
571
	 */
572 11
	protected function addNotificationsForUser($user, $subject, $subjectParams, $fileId, $path, $isFile, $streamSetting, $emailSetting, $type = Files_Sharing::TYPE_SHARED) {
573 11
		if (!$streamSetting && !$emailSetting) {
574 1
			return;
575
		}
576
577 10
		$selfAction = $user === $this->currentUser;
578 10
		$app = $type === Files_Sharing::TYPE_SHARED ? 'files_sharing' : 'files';
579 10
		$link = $this->urlGenerator->linkToRouteAbsolute('files.view.index', array(
580 10
			'dir' => ($isFile) ? dirname($path) : $path,
581 10
		));
582
583 10
		$objectType = ($fileId) ? 'files' : '';
584
585 10
		$event = $this->manager->generateEvent();
586 10
		$event->setApp($app)
587 10
			->setType($type)
588 10
			->setAffectedUser($user)
589 10
			->setAuthor($this->currentUser)
590 10
			->setTimestamp(time())
591 10
			->setSubject($subject, $subjectParams)
592 10
			->setObject($objectType, $fileId, $path)
593 10
			->setLink($link);
594
595
		// Add activity to stream
596 10
		if ($streamSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser, 'setting', 'self'))) {
597 3
			$this->activityData->send($event);
598 3
		}
599
600
		// Add activity to mail queue
601 10
		if ($emailSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser, 'setting', 'selfemail'))) {
602 5
			$latestSend = time() + $emailSetting;
603 5
			$this->activityData->storeMail($event, $latestSend);
604 5
		}
605 10
	}
606
}
607