Completed
Pull Request — master (#522)
by Joas
03:03
created

FilesHooks::unShare()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 11
Code Lines 8

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 11
loc 11
ccs 0
cts 9
cp 0
rs 8.8571
cc 6
eloc 8
nc 5
nop 1
crap 42
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
40
/**
41
 * The class to handle the filesystem hooks
42
 */
43
class FilesHooks {
44
	const USER_BATCH_SIZE = 50;
45
46
	/** @var \OCP\Activity\IManager */
47
	protected $manager;
48
49
	/** @var \OCA\Activity\Data */
50
	protected $activityData;
51
52
	/** @var \OCA\Activity\UserSettings */
53
	protected $userSettings;
54
55
	/** @var \OCP\IGroupManager */
56
	protected $groupManager;
57
58
	/** @var \OCP\IDBConnection */
59
	protected $connection;
60
61
	/** @var \OC\Files\View */
62
	protected $view;
63
64
	/** @var IURLGenerator */
65
	protected $urlGenerator;
66
67
	/** @var string|false */
68
	protected $currentUser;
69
70
	/**
71
	 * Constructor
72
	 *
73
	 * @param IManager $manager
74
	 * @param Data $activityData
75
	 * @param UserSettings $userSettings
76
	 * @param IGroupManager $groupManager
77
	 * @param View $view
78
	 * @param IDBConnection $connection
79
	 * @param IURLGenerator $urlGenerator
80
	 * @param string|false $currentUser
81
	 */
82 49
	public function __construct(IManager $manager, Data $activityData, UserSettings $userSettings, IGroupManager $groupManager, View $view, IDBConnection $connection, IURLGenerator $urlGenerator, $currentUser) {
83 49
		$this->manager = $manager;
84 49
		$this->activityData = $activityData;
85 49
		$this->userSettings = $userSettings;
86 49
		$this->groupManager = $groupManager;
87 49
		$this->view = $view;
88 49
		$this->connection = $connection;
89 49
		$this->urlGenerator = $urlGenerator;
90 49
		$this->currentUser = $currentUser;
91 49
	}
92
93
	/**
94
	 * @return string|false Current UserID if logged in, false otherwise
95
	 */
96 2
	protected function getCurrentUser() {
97 2
		return $this->currentUser;
98
	}
99
100
	/**
101
	 * Store the create hook events
102
	 * @param string $path Path of the file that has been created
103
	 */
104 2
	public function fileCreate($path) {
105 2
		if ($this->getCurrentUser() !== false) {
106 1
			$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CREATED, 'created_self', 'created_by');
107
		} else {
108 1
			$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CREATED, '', 'created_public');
109
		}
110 2
	}
111
112
	/**
113
	 * Store the update hook events
114
	 * @param string $path Path of the file that has been modified
115
	 */
116 1
	public function fileUpdate($path) {
117 1
		$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CHANGED, 'changed_self', 'changed_by');
118 1
	}
119
120
	/**
121
	 * Store the delete hook events
122
	 * @param string $path Path of the file that has been deleted
123
	 */
124 1
	public function fileDelete($path) {
125 1
		$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_DELETED, 'deleted_self', 'deleted_by');
126 1
	}
127
128
	/**
129
	 * Store the restore hook events
130
	 * @param string $path Path of the file that has been restored
131
	 */
132 1
	public function fileRestore($path) {
133 1
		$this->addNotificationsForFileAction($path, Files::TYPE_SHARE_RESTORED, 'restored_self', 'restored_by');
134 1
	}
135
136
	/**
137
	 * Creates the entries for file actions on $file_path
138
	 *
139
	 * @param string $filePath         The file that is being changed
140
	 * @param int    $activityType     The activity type
141
	 * @param string $subject          The subject for the actor
142
	 * @param string $subjectBy        The subject for other users (with "by $actor")
143
	 */
144 3
	protected function addNotificationsForFileAction($filePath, $activityType, $subject, $subjectBy) {
145
		// Do not add activities for .part-files
146 3
		if (substr($filePath, -5) === '.part') {
147 1
			return;
148
		}
149
150 2
		list($filePath, $uidOwner, $fileId) = $this->getSourcePathAndOwner($filePath);
151 2
		$affectedUsers = $this->getUserPathsFromPath($filePath, $uidOwner);
152 2
		$filteredStreamUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'stream', $activityType);
153 2
		$filteredEmailUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'email', $activityType);
154
155 2
		foreach ($affectedUsers as $user => $path) {
156 2
			if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) {
157 2
				continue;
158
			}
159
160 2
			if ($user === $this->currentUser) {
161 1
				$userSubject = $subject;
162 1
				$userParams = [[$fileId => $path]];
163
			} else {
164 1
				$userSubject = $subjectBy;
165 1
				$userParams = [[$fileId => $path], $this->currentUser];
166
			}
167
168 2
			$this->addNotificationsForUser(
169
				$user, $userSubject, $userParams,
170 2
				$fileId, $path, true,
171 2
				!empty($filteredStreamUsers[$user]),
172 2
				!empty($filteredEmailUsers[$user]) ? $filteredEmailUsers[$user] : 0,
173
				$activityType
174
			);
175
		}
176 2
	}
177
178
	/**
179
	 * Returns a "username => path" map for all affected users
180
	 *
181
	 * @param string $path
182
	 * @param string $uidOwner
183
	 * @return array
184
	 */
185
	protected function getUserPathsFromPath($path, $uidOwner) {
186
		return Share::getUsersSharingFile($path, $uidOwner, true, true);
187
	}
188
189
	/**
190
	 * Return the source
191
	 *
192
	 * @param string $path
193
	 * @return array
194
	 */
195
	protected function getSourcePathAndOwner($path) {
196
		$uidOwner = Filesystem::getOwner($path);
197
		$fileId = 0;
198
199
		if ($uidOwner !== $this->currentUser) {
200
			Filesystem::initMountPoints($uidOwner);
201
		}
202
		$info = Filesystem::getFileInfo($path);
203
		if ($info !== false) {
204
			$ownerView = new View('/' . $uidOwner . '/files');
205
			$fileId = (int) $info['fileid'];
206
			$path = $ownerView->getPath($fileId);
207
		}
208
209
		return array($path, $uidOwner, $fileId);
210
	}
211
212
	/**
213
	 * Manage sharing events
214
	 * @param array $params The hook params
215
	 */
216 3 View Code Duplication
	public function share($params) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
217 3
		if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
218 3
			if ((int) $params['shareType'] === Share::SHARE_TYPE_USER) {
219 1
				$this->shareFileOrFolderWithUser($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], true);
220 2
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_GROUP) {
221 1
				$this->shareFileOrFolderWithGroup($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], (int) $params['id'], true);
222 1
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) {
223 1
				$this->shareFileOrFolderByLink((int) $params['fileSource'], $params['itemType'], $params['uidOwner'], true);
224
			}
225
		}
226 3
	}
227
228
	/**
229
	 * Manage sharing events
230
	 * @param array $params The hook params
231
	 */
232 View Code Duplication
	public function unShare($params) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
233
		if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
234
			if ((int) $params['shareType'] === Share::SHARE_TYPE_USER) {
235
				$this->shareFileOrFolderWithUser($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], false);
236
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_GROUP) {
237
				$this->shareFileOrFolderWithGroup($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], (int) $params['id'], false);
238
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) {
239
				$this->shareFileOrFolderByLink((int) $params['fileSource'], $params['itemType'], $params['uidOwner'], false);
240
			}
241
		}
242
	}
243
244
	/**
245
	 * Sharing a file or folder with a user
246
	 *
247
	 * @param string $shareWith
248
	 * @param int $fileSource File ID that is being shared
249
	 * @param string $itemType File type that is being shared (file or folder)
250
	 * @param string $fileTarget File path
251
	 * @param bool $isSharing True if sharing, false if unsharing
252
	 */
253 2
	protected function shareFileOrFolderWithUser($shareWith, $fileSource, $itemType, $fileTarget, $isSharing) {
254 2
		if ($isSharing) {
255 2
			$actionSharer = 'shared_user_self';
256 2
			$actionOwner = 'reshared_user_by';
257 2
			$actionUser = 'shared_with_by';
258
		} else {
259
			$actionSharer = 'unshared_user_self';
260
			$actionOwner = 'unshared_user_by';
261
			$actionUser = 'unshared_by';
262
		}
263
264
		// User performing the share
265 2
		$this->shareNotificationForSharer($actionSharer, $shareWith, $fileSource, $itemType);
266 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...
267
268
		// New shared user
269 2
		$this->addNotificationsForUser(
270 2
			$shareWith, $actionUser, [[$fileSource => $fileTarget], $this->currentUser],
271 2
			(int) $fileSource, $fileTarget, ($itemType === 'file'),
272 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...
273 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...
274
		);
275 2
	}
276
277
	/**
278
	 * Sharing a file or folder with a group
279
	 *
280
	 * @param string $shareWith
281
	 * @param int $fileSource File ID that is being shared
282
	 * @param string $itemType File type that is being shared (file or folder)
283
	 * @param string $fileTarget File path
284
	 * @param int $shareId The Share ID of this share
285
	 * @param bool $isSharing True if sharing, false if unsharing
286
	 */
287 6
	protected function shareFileOrFolderWithGroup($shareWith, $fileSource, $itemType, $fileTarget, $shareId, $isSharing) {
288 6
		if ($isSharing) {
289 6
			$actionSharer = 'shared_group_self';
290 6
			$actionOwner = 'reshared_group_by';
291 6
			$actionUser = 'shared_with_by';
292
		} else {
293
			$actionSharer = 'unshared_group_self';
294
			$actionOwner = 'unshared_group_by';
295
			$actionUser = 'unshared_by';
296
		}
297
298
		// Members of the new group
299 6
		$group = $this->groupManager->get($shareWith);
300 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...
301 1
			return;
302
		}
303
304
		// User performing the share
305 5
		$this->shareNotificationForSharer($actionSharer, $shareWith, $fileSource, $itemType);
306 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...
307
308 5
		$offset = 0;
309 5
		$users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset);
310 5
		while (!empty($users)) {
311 4
			$this->addNotificationsForGroupUsers($users, $actionUser, $fileSource, $itemType, $fileTarget, $shareId);
312 4
			$offset += self::USER_BATCH_SIZE;
313 4
			$users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset);
314
		}
315 5
	}
316
317
	/**
318
	 * @param IUser[] $usersInGroup
319
	 * @param string $actionUser
320
	 * @param int $fileSource File ID that is being shared
321
	 * @param string $itemType File type that is being shared (file or folder)
322
	 * @param string $fileTarget File path
323
	 * @param int $shareId The Share ID of this share
324
	 */
325 4
	protected function addNotificationsForGroupUsers(array $usersInGroup, $actionUser, $fileSource, $itemType, $fileTarget, $shareId) {
326 4
		$affectedUsers = [];
327
328 4
		foreach ($usersInGroup as $user) {
329 4
			$affectedUsers[$user->getUID()] = $fileTarget;
330
		}
331
332
		// Remove the triggering user, we already managed his notifications
333 4
		unset($affectedUsers[$this->currentUser]);
334
335 4
		if (empty($affectedUsers)) {
336 1
			return;
337
		}
338
339 3
		$userIds = array_keys($affectedUsers);
340 3
		$filteredStreamUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'stream', Files_Sharing::TYPE_SHARED);
341 3
		$filteredEmailUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'email', Files_Sharing::TYPE_SHARED);
342
343 3
		$affectedUsers = $this->fixPathsForShareExceptions($affectedUsers, $shareId);
344 3
		foreach ($affectedUsers as $user => $path) {
345 3
			if (empty($filteredStreamUsersInGroup[$user]) && empty($filteredEmailUsersInGroup[$user])) {
346 2
				continue;
347
			}
348
349 1
			$this->addNotificationsForUser(
350 1
				$user, $actionUser, [[$fileSource => $path], $this->currentUser],
351 1
				$fileSource, $path, ($itemType === 'file'),
352 1
				!empty($filteredStreamUsersInGroup[$user]),
353 1
				!empty($filteredEmailUsersInGroup[$user]) ? $filteredEmailUsersInGroup[$user] : 0
354
			);
355
		}
356 3
	}
357
358
	/**
359
	 * Check when there was a naming conflict and the target is different
360
	 * for some of the users
361
	 *
362
	 * @param array $affectedUsers
363
	 * @param int $shareId
364
	 * @return mixed
365
	 */
366
	protected function fixPathsForShareExceptions(array $affectedUsers, $shareId) {
367
		$queryBuilder = $this->connection->getQueryBuilder();
368
		$queryBuilder->select(['share_with', 'file_target'])
369
			->from('share')
370
			->where($queryBuilder->expr()->eq('parent', $queryBuilder->createParameter('parent')))
371
			->setParameter('parent', (int) $shareId);
372
		$query = $queryBuilder->execute();
373
374
		while ($row = $query->fetch()) {
375
			$affectedUsers[$row['share_with']] = $row['file_target'];
376
		}
377
378
		return $affectedUsers;
379
	}
380
381
	/**
382
	 * Sharing a file or folder via link/public
383
	 *
384
	 * @param int $fileSource File ID that is being shared
385
	 * @param string $itemType File type that is being shared (file or folder)
386
	 * @param string $linkOwner
387
	 * @param bool $isSharing True if sharing, false if unsharing
388
	 */
389 2
	protected function shareFileOrFolderByLink($fileSource, $itemType, $linkOwner, $isSharing) {
390 2
		if ($isSharing) {
391 2
			$actionSharer = 'shared_link_self';
392 2
			$actionOwner = 'reshared_link_by';
393
		} else if ($this->currentUser !== $linkOwner) {
394
			// Link expired
395
			$actionSharer = 'link_expired';
396
			$actionOwner = 'link_by_expired';
397
			$this->currentUser = $linkOwner;
398
			\OC::$server->getUserFolder($linkOwner);
399
		} else {
400
			$actionSharer = 'unshared_link_self';
401
			$actionOwner = 'unshared_link_by';
402
		}
403
404 2
		$this->view->chroot('/' . $this->currentUser . '/files');
405
406
		try {
407 2
			$path = $this->view->getPath($fileSource);
408 1
		} 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...
409 1
			return;
410
		}
411
412 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...
413
414 1
		$this->addNotificationsForUser(
415 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...
416 1
			(int) $fileSource, $path, ($itemType === 'file'),
417 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...
418 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...
419
		);
420 1
	}
421
422
	/**
423
	 * Add notifications for the user that shares a file/folder
424
	 *
425
	 * @param string $subject
426
	 * @param string $shareWith
427
	 * @param int $fileSource
428
	 * @param string $itemType
429
	 */
430 2
	protected function shareNotificationForSharer($subject, $shareWith, $fileSource, $itemType) {
431 2
		$this->view->chroot('/' . $this->currentUser . '/files');
432
433
		try {
434 2
			$path = $this->view->getPath($fileSource);
435 1
		} 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...
436 1
			return;
437
		}
438
439 1
		$this->addNotificationsForUser(
440 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...
441 1
			$fileSource, $path, ($itemType === 'file'),
442 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...
443 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...
444
		);
445 1
	}
446
447
	/**
448
	 * Add notifications for the user that shares a file/folder
449
	 *
450
	 * @param string $owner
451
	 * @param string $subject
452
	 * @param string $shareWith
453
	 * @param int $fileSource
454
	 * @param string $itemType
455
	 */
456 2
	protected function reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType) {
457 2
		$this->view->chroot('/' . $owner . '/files');
458
459
		try {
460 2
			$path = $this->view->getPath($fileSource);
461 1
		} 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...
462 1
			return;
463
		}
464
465 1
		$this->addNotificationsForUser(
466 1
			$owner, $subject, [[$fileSource => $path], $this->currentUser, $shareWith],
467 1
			$fileSource, $path, ($itemType === 'file'),
468 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...
469 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...
470
		);
471 1
	}
472
473
	/**
474
	 * Add notifications for the owners whose files have been reshared
475
	 *
476
	 * @param string $currentOwner
477
	 * @param string $subject
478
	 * @param string $shareWith
479
	 * @param int $fileSource
480
	 * @param string $itemType
481
	 */
482 10
	protected function shareNotificationForOriginalOwners($currentOwner, $subject, $shareWith, $fileSource, $itemType) {
483
		// Get the full path of the current user
484 10
		$this->view->chroot('/' . $currentOwner . '/files');
485
486
		try {
487 10
			$path = $this->view->getPath($fileSource);
488 1
		} 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...
489 1
			return;
490
		}
491
492
		/**
493
		 * Get the original owner and his path
494
		 */
495 9
		$owner = $this->view->getOwner($path);
496 9
		if ($owner !== $currentOwner) {
497 7
			$this->reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType);
498
		}
499
500
		/**
501
		 * Get the sharee who shared the item with the currentUser
502
		 */
503 9
		$this->view->chroot('/' . $currentOwner . '/files');
504 9
		$mount = $this->view->getMount($path);
505 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...
506 1
			return;
507
		}
508
509 8
		$storage = $mount->getStorage();
510 8
		if (!$storage->instanceOfStorage('OC\Files\Storage\Shared')) {
511 1
			return;
512
		}
513
514
		/** @var \OC\Files\Storage\Shared $storage */
515 7
		$shareOwner = $storage->getSharedFrom();
516 7
		if ($shareOwner === '' || $shareOwner === null || $shareOwner === $owner || $shareOwner === $currentOwner) {
517 5
			return;
518
		}
519
520 2
		$this->reshareNotificationForSharer($shareOwner, $subject, $shareWith, $fileSource, $itemType);
521 2
	}
522
523
	/**
524
	 * Adds the activity and email for a user when the settings require it
525
	 *
526
	 * @param string $user
527
	 * @param string $subject
528
	 * @param array $subjectParams
529
	 * @param int $fileId
530
	 * @param string $path
531
	 * @param bool $isFile If the item is a file, we link to the parent directory
532
	 * @param bool $streamSetting
533
	 * @param int $emailSetting
534
	 * @param string $type
535
	 */
536 11
	protected function addNotificationsForUser($user, $subject, $subjectParams, $fileId, $path, $isFile, $streamSetting, $emailSetting, $type = Files_Sharing::TYPE_SHARED) {
537 11
		if (!$streamSetting && !$emailSetting) {
538 1
			return;
539
		}
540
541 10
		$selfAction = $user === $this->currentUser;
542 10
		$app = $type === Files_Sharing::TYPE_SHARED ? 'files_sharing' : 'files';
543 10
		$link = $this->urlGenerator->linkToRouteAbsolute('files.view.index', array(
544 10
			'dir' => ($isFile) ? dirname($path) : $path,
545
		));
546
547 10
		$objectType = ($fileId) ? 'files' : '';
548
549 10
		$event = $this->manager->generateEvent();
550 10
		$event->setApp($app)
551 10
			->setType($type)
552 10
			->setAffectedUser($user)
553 10
			->setAuthor($this->currentUser)
554 10
			->setTimestamp(time())
555 10
			->setSubject($subject, $subjectParams)
556 10
			->setObject($objectType, $fileId, $path)
557 10
			->setLink($link);
558
559
		// Add activity to stream
560 10
		if ($streamSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser, 'setting', 'self'))) {
561 3
			$this->activityData->send($event);
562
		}
563
564
		// Add activity to mail queue
565 10
		if ($emailSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser, 'setting', 'selfemail'))) {
566 5
			$latestSend = time() + $emailSetting;
567 5
			$this->activityData->storeMail($event, $latestSend);
568
		}
569 10
	}
570
}
571