Cancelled
Push — stable9 ( 8c58dc...eec321 )
by
unknown
465:01 queued 465:01
created

FilesHooks::shareNotificationForSharer()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 16
ccs 12
cts 12
cp 1
rs 9.4285
cc 3
eloc 11
nc 2
nop 4
crap 3
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 1
		} 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
		if (Files::TYPE_SHARE_CREATED) {
151
			try {
152 2
				list($filePath, $uidOwner, $fileId) = $this->getSourcePathAndOwner($filePath);
153 2
			} catch (\OCP\Files\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...
154
				// File not found? Sounds weird, but this happens before 9.1:
155
				// https://github.com/owncloud/core/issues/23212
156
				// Chunk assembling triggered the exact same hooks twice.
157
				// The first call however is before the file is in the database.
158
				// So when trying to get the owner, the file can not be found.
159
				// But since the second hook will come along, we simply ignore this.
160
				return;
161
			}
162 2
		} else {
163
			list($filePath, $uidOwner, $fileId) = $this->getSourcePathAndOwner($filePath);
164
		}
165 2
		if (!$fileId) {
166
			// no owner, possibly deleted or unknown
167
			// skip notifications
168
			return;
169
		}
170 2
		$affectedUsers = $this->getUserPathsFromPath($filePath, $uidOwner);
171 2
		$filteredStreamUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'stream', $activityType);
172 2
		$filteredEmailUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'email', $activityType);
173
174 2
		foreach ($affectedUsers as $user => $path) {
175 2
			if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) {
176 2
				continue;
177
			}
178
179 2
			if ($user === $this->currentUser) {
180 1
				$userSubject = $subject;
181 1
				$userParams = [[$fileId => $path]];
182 1
			} else {
183 1
				$userSubject = $subjectBy;
184 1
				$userParams = [[$fileId => $path], $this->currentUser];
185
			}
186
187 2
			$this->addNotificationsForUser(
188 2
				$user, $userSubject, $userParams,
189 2
				$fileId, $path, true,
190 2
				!empty($filteredStreamUsers[$user]),
191 2
				!empty($filteredEmailUsers[$user]) ? $filteredEmailUsers[$user] : 0,
192
				$activityType
193 2
			);
194 2
		}
195 2
	}
196
197
	/**
198
	 * Returns a "username => path" map for all affected users
199
	 *
200
	 * @param string $path
201
	 * @param string $uidOwner
202
	 * @return array
203
	 */
204
	protected function getUserPathsFromPath($path, $uidOwner) {
205
		return Share::getUsersSharingFile($path, $uidOwner, true, true);
206
	}
207
208
	/**
209
	 * Return the source
210
	 *
211
	 * @param string $path
212
	 * @return array
213
	 */
214
	protected function getSourcePathAndOwner($path) {
215
		$currentUserView = Filesystem::getView();
216
		$uidOwner = $currentUserView->getOwner($path);
217
		$fileId = 0;
218
219
		if ($uidOwner !== $this->currentUser) {
220
			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...
221
			if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
222
				// for federated shares we don't have access to the remote user, use the current one
223
				// which will also make it use the matching local "shared::" federated share storage instead
224
				$uidOwner = $this->currentUser;
225
			} else {
226
				Filesystem::initMountPoints($uidOwner);
227
			}
228
		}
229
		$info = Filesystem::getFileInfo($path);
230
		if ($info !== false) {
231
			$ownerView = new View('/' . $uidOwner . '/files');
232
			$fileId = (int) $info['fileid'];
233
			$path = $ownerView->getPath($fileId);
234
		}
235
236
		return array($path, $uidOwner, $fileId);
237
	}
238
239
	/**
240
	 * Manage sharing events
241
	 * @param array $params The hook params
242
	 */
243 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...
244 3
		if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
245 3
			if ((int) $params['shareType'] === Share::SHARE_TYPE_USER) {
246 1
				$this->shareFileOrFolderWithUser($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], true);
247 3
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_GROUP) {
248 1
				$this->shareFileOrFolderWithGroup($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], (int) $params['id'], true);
249 2
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) {
250 1
				$this->shareFileOrFolderByLink((int) $params['fileSource'], $params['itemType'], $params['uidOwner'], true);
251 1
			}
252 3
		}
253 3
	}
254
255
	/**
256
	 * Manage sharing events
257
	 * @param array $params The hook params
258
	 */
259 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...
260
		if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
261
			if ((int) $params['shareType'] === Share::SHARE_TYPE_USER) {
262
				$this->shareFileOrFolderWithUser($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], false);
263
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_GROUP) {
264
				$this->shareFileOrFolderWithGroup($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], (int) $params['id'], false);
265
			} else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) {
266
				$this->shareFileOrFolderByLink((int) $params['fileSource'], $params['itemType'], $params['uidOwner'], false);
267
			}
268
		}
269
	}
270
271
	/**
272
	 * Sharing a file or folder with a user
273
	 *
274
	 * @param string $shareWith
275
	 * @param int $fileSource File ID that is being shared
276
	 * @param string $itemType File type that is being shared (file or folder)
277
	 * @param string $fileTarget File path
278
	 * @param bool $isSharing True if sharing, false if unsharing
279
	 */
280 2
	protected function shareFileOrFolderWithUser($shareWith, $fileSource, $itemType, $fileTarget, $isSharing) {
281 2
		if ($isSharing) {
282 2
			$actionSharer = 'shared_user_self';
283 2
			$actionOwner = 'reshared_user_by';
284 2
			$actionUser = 'shared_with_by';
285 2
		} else {
286
			$actionSharer = 'unshared_user_self';
287
			$actionOwner = 'unshared_user_by';
288
			$actionUser = 'unshared_by';
289
		}
290
291
		// User performing the share
292 2
		$this->shareNotificationForSharer($actionSharer, $shareWith, $fileSource, $itemType);
293 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...
294
295
		// New shared user
296 2
		$this->addNotificationsForUser(
297 2
			$shareWith, $actionUser, [[$fileSource => $fileTarget], $this->currentUser],
298 2
			(int) $fileSource, $fileTarget, ($itemType === 'file'),
299 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...
300 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...
301 2
		);
302 2
	}
303
304
	/**
305
	 * Sharing a file or folder with a group
306
	 *
307
	 * @param string $shareWith
308
	 * @param int $fileSource File ID that is being shared
309
	 * @param string $itemType File type that is being shared (file or folder)
310
	 * @param string $fileTarget File path
311
	 * @param int $shareId The Share ID of this share
312
	 * @param bool $isSharing True if sharing, false if unsharing
313
	 */
314 6
	protected function shareFileOrFolderWithGroup($shareWith, $fileSource, $itemType, $fileTarget, $shareId, $isSharing) {
315 6
		if ($isSharing) {
316 6
			$actionSharer = 'shared_group_self';
317 6
			$actionOwner = 'reshared_group_by';
318 6
			$actionUser = 'shared_with_by';
319 6
		} else {
320
			$actionSharer = 'unshared_group_self';
321
			$actionOwner = 'unshared_group_by';
322
			$actionUser = 'unshared_by';
323
		}
324
325
		// Members of the new group
326 6
		$group = $this->groupManager->get($shareWith);
327 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...
328 1
			return;
329
		}
330
331
		// User performing the share
332 5
		$this->shareNotificationForSharer($actionSharer, $shareWith, $fileSource, $itemType);
333 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...
334
335 5
		$offset = 0;
336 5
		$users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset);
337 5
		while (!empty($users)) {
338 4
			$this->addNotificationsForGroupUsers($users, $actionUser, $fileSource, $itemType, $fileTarget, $shareId);
339 4
			$offset += self::USER_BATCH_SIZE;
340 4
			$users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset);
341 4
		}
342 5
	}
343
344
	/**
345
	 * @param IUser[] $usersInGroup
346
	 * @param string $actionUser
347
	 * @param int $fileSource File ID that is being shared
348
	 * @param string $itemType File type that is being shared (file or folder)
349
	 * @param string $fileTarget File path
350
	 * @param int $shareId The Share ID of this share
351
	 */
352 4
	protected function addNotificationsForGroupUsers(array $usersInGroup, $actionUser, $fileSource, $itemType, $fileTarget, $shareId) {
353 4
		$affectedUsers = [];
354
355 4
		foreach ($usersInGroup as $user) {
356 4
			$affectedUsers[$user->getUID()] = $fileTarget;
357 4
		}
358
359
		// Remove the triggering user, we already managed his notifications
360 4
		unset($affectedUsers[$this->currentUser]);
361
362 4
		if (empty($affectedUsers)) {
363 1
			return;
364
		}
365
366 3
		$userIds = array_keys($affectedUsers);
367 3
		$filteredStreamUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'stream', Files_Sharing::TYPE_SHARED);
368 3
		$filteredEmailUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'email', Files_Sharing::TYPE_SHARED);
369
370 3
		$affectedUsers = $this->fixPathsForShareExceptions($affectedUsers, $shareId);
371 3
		foreach ($affectedUsers as $user => $path) {
372 3
			if (empty($filteredStreamUsersInGroup[$user]) && empty($filteredEmailUsersInGroup[$user])) {
373 2
				continue;
374
			}
375
376 1
			$this->addNotificationsForUser(
377 1
				$user, $actionUser, [[$fileSource => $path], $this->currentUser],
378 1
				$fileSource, $path, ($itemType === 'file'),
379 1
				!empty($filteredStreamUsersInGroup[$user]),
380 1
				!empty($filteredEmailUsersInGroup[$user]) ? $filteredEmailUsersInGroup[$user] : 0
381 1
			);
382 3
		}
383 3
	}
384
385
	/**
386
	 * Check when there was a naming conflict and the target is different
387
	 * for some of the users
388
	 *
389
	 * @param array $affectedUsers
390
	 * @param int $shareId
391
	 * @return mixed
392
	 */
393
	protected function fixPathsForShareExceptions(array $affectedUsers, $shareId) {
394
		$queryBuilder = $this->connection->getQueryBuilder();
395
		$queryBuilder->select(['share_with', 'file_target'])
396
			->from('share')
397
			->where($queryBuilder->expr()->eq('parent', $queryBuilder->createParameter('parent')))
398
			->setParameter('parent', (int) $shareId);
399
		$query = $queryBuilder->execute();
400
401
		while ($row = $query->fetch()) {
402
			$affectedUsers[$row['share_with']] = $row['file_target'];
403
		}
404
405
		return $affectedUsers;
406
	}
407
408
	/**
409
	 * Sharing a file or folder via link/public
410
	 *
411
	 * @param int $fileSource File ID that is being shared
412
	 * @param string $itemType File type that is being shared (file or folder)
413
	 * @param string $linkOwner
414
	 * @param bool $isSharing True if sharing, false if unsharing
415
	 */
416 2
	protected function shareFileOrFolderByLink($fileSource, $itemType, $linkOwner, $isSharing) {
417 2
		if ($isSharing) {
418 2
			$actionSharer = 'shared_link_self';
419 2
			$actionOwner = 'reshared_link_by';
420 2
		} else if ($this->currentUser !== $linkOwner) {
421
			// Link expired
422
			$actionSharer = 'link_expired';
423
			$actionOwner = 'link_by_expired';
424
			$this->currentUser = $linkOwner;
425
			\OC::$server->getUserFolder($linkOwner);
426
		} else {
427
			$actionSharer = 'unshared_link_self';
428
			$actionOwner = 'unshared_link_by';
429
		}
430
431 2
		$this->view->chroot('/' . $this->currentUser . '/files');
432
433
		try {
434 2
			$path = $this->view->getPath($fileSource);
435 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...
436 1
			return;
437
		}
438
439 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...
440
441 1
		$this->addNotificationsForUser(
442 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...
443 1
			(int) $fileSource, $path, ($itemType === 'file'),
444 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...
445 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...
446 1
		);
447 1
	}
448
449
	/**
450
	 * Add notifications for the user that shares a file/folder
451
	 *
452
	 * @param string $subject
453
	 * @param string $shareWith
454
	 * @param int $fileSource
455
	 * @param string $itemType
456
	 */
457 2
	protected function shareNotificationForSharer($subject, $shareWith, $fileSource, $itemType) {
458 2
		$this->view->chroot('/' . $this->currentUser . '/files');
459
460
		try {
461 2
			$path = $this->view->getPath($fileSource);
462 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...
463 1
			return;
464
		}
465
466 1
		$this->addNotificationsForUser(
467 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...
468 1
			$fileSource, $path, ($itemType === 'file'),
469 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...
470 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...
471 1
		);
472 1
	}
473
474
	/**
475
	 * Add notifications for the user that shares a file/folder
476
	 *
477
	 * @param string $owner
478
	 * @param string $subject
479
	 * @param string $shareWith
480
	 * @param int $fileSource
481
	 * @param string $itemType
482
	 */
483 2
	protected function reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType) {
484 2
		$this->view->chroot('/' . $owner . '/files');
485
486
		try {
487 2
			$path = $this->view->getPath($fileSource);
488 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...
489 1
			return;
490
		}
491
492 1
		$this->addNotificationsForUser(
493 1
			$owner, $subject, [[$fileSource => $path], $this->currentUser, $shareWith],
494 1
			$fileSource, $path, ($itemType === 'file'),
495 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...
496 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...
497 1
		);
498 1
	}
499
500
	/**
501
	 * Add notifications for the owners whose files have been reshared
502
	 *
503
	 * @param string $currentOwner
504
	 * @param string $subject
505
	 * @param string $shareWith
506
	 * @param int $fileSource
507
	 * @param string $itemType
508
	 */
509 10
	protected function shareNotificationForOriginalOwners($currentOwner, $subject, $shareWith, $fileSource, $itemType) {
510
		// Get the full path of the current user
511 10
		$this->view->chroot('/' . $currentOwner . '/files');
512
513
		try {
514 10
			$path = $this->view->getPath($fileSource);
515 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...
516 1
			return;
517
		}
518
519
		/**
520
		 * Get the original owner and his path
521
		 */
522 9
		$owner = $this->view->getOwner($path);
523 9
		if ($owner !== $currentOwner) {
524 7
			$this->reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType);
525 7
		}
526
527
		/**
528
		 * Get the sharee who shared the item with the currentUser
529
		 */
530 9
		$this->view->chroot('/' . $currentOwner . '/files');
531 9
		$mount = $this->view->getMount($path);
532 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...
533 1
			return;
534
		}
535
536 8
		$storage = $mount->getStorage();
537 8
		if (!$storage->instanceOfStorage('OC\Files\Storage\Shared')) {
538 1
			return;
539
		}
540
541
		/** @var \OC\Files\Storage\Shared $storage */
542 7
		$shareOwner = $storage->getSharedFrom();
543 7
		if ($shareOwner === '' || $shareOwner === null || $shareOwner === $owner || $shareOwner === $currentOwner) {
544 5
			return;
545
		}
546
547 2
		$this->reshareNotificationForSharer($shareOwner, $subject, $shareWith, $fileSource, $itemType);
548 2
	}
549
550
	/**
551
	 * Adds the activity and email for a user when the settings require it
552
	 *
553
	 * @param string $user
554
	 * @param string $subject
555
	 * @param array $subjectParams
556
	 * @param int $fileId
557
	 * @param string $path
558
	 * @param bool $isFile If the item is a file, we link to the parent directory
559
	 * @param bool $streamSetting
560
	 * @param int $emailSetting
561
	 * @param string $type
562
	 */
563 11
	protected function addNotificationsForUser($user, $subject, $subjectParams, $fileId, $path, $isFile, $streamSetting, $emailSetting, $type = Files_Sharing::TYPE_SHARED) {
564 11
		if (!$streamSetting && !$emailSetting) {
565 1
			return;
566
		}
567
568 10
		$selfAction = $user === $this->currentUser;
569 10
		$app = $type === Files_Sharing::TYPE_SHARED ? 'files_sharing' : 'files';
570 10
		$link = $this->urlGenerator->linkToRouteAbsolute('files.view.index', array(
571 10
			'dir' => ($isFile) ? dirname($path) : $path,
572 10
		));
573
574 10
		$objectType = ($fileId) ? 'files' : '';
575
576 10
		$event = $this->manager->generateEvent();
577 10
		$event->setApp($app)
578 10
			->setType($type)
579 10
			->setAffectedUser($user)
580 10
			->setAuthor($this->currentUser)
581 10
			->setTimestamp(time())
582 10
			->setSubject($subject, $subjectParams)
583 10
			->setObject($objectType, $fileId, $path)
584 10
			->setLink($link);
585
586
		// Add activity to stream
587 10
		if ($streamSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser, 'setting', 'self'))) {
588 3
			$this->activityData->send($event);
589 3
		}
590
591
		// Add activity to mail queue
592 10
		if ($emailSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser, 'setting', 'selfemail'))) {
593 5
			$latestSend = time() + $emailSetting;
594 5
			$this->activityData->storeMail($event, $latestSend);
595 5
		}
596 10
	}
597
}
598