This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @copyright Copyright (c) 2016, ownCloud, Inc. |
||
4 | * |
||
5 | * @author Frank Karlitschek <[email protected]> |
||
6 | * @author Joas Schilling <[email protected]> |
||
7 | * @author Thomas Müller <[email protected]> |
||
8 | * |
||
9 | * @license AGPL-3.0 |
||
10 | * |
||
11 | * This code is free software: you can redistribute it and/or modify |
||
12 | * it under the terms of the GNU Affero General Public License, version 3, |
||
13 | * as published by the Free Software Foundation. |
||
14 | * |
||
15 | * This program is distributed in the hope that it will be useful, |
||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | * GNU Affero General Public License for more details. |
||
19 | * |
||
20 | * You should have received a copy of the GNU Affero General Public License, version 3, |
||
21 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
||
22 | * |
||
23 | */ |
||
24 | |||
25 | namespace OCA\Activity; |
||
26 | |||
27 | use OC\Files\Filesystem; |
||
28 | use OC\Files\View; |
||
29 | use OCA\Activity\BackgroundJob\RemoteActivity; |
||
30 | use OCA\Activity\Extension\Files; |
||
31 | use OCA\Activity\Extension\Files_Sharing; |
||
32 | use OCP\Activity\IManager; |
||
33 | use OCP\Files\IRootFolder; |
||
34 | use OCP\Files\Mount\IMountPoint; |
||
35 | use OCP\Files\Node; |
||
36 | use OCP\Files\NotFoundException; |
||
37 | use OCP\IDBConnection; |
||
38 | use OCP\IGroup; |
||
39 | use OCP\IGroupManager; |
||
40 | use OCP\ILogger; |
||
41 | use OCP\IURLGenerator; |
||
42 | use OCP\IUser; |
||
43 | use OCP\Share; |
||
44 | use OCP\Share\IShare; |
||
45 | use OCP\Share\IShareHelper; |
||
46 | |||
47 | /** |
||
48 | * The class to handle the filesystem hooks |
||
49 | */ |
||
50 | class FilesHooks { |
||
51 | const USER_BATCH_SIZE = 50; |
||
52 | |||
53 | /** @var \OCP\Activity\IManager */ |
||
54 | protected $manager; |
||
55 | |||
56 | /** @var \OCA\Activity\Data */ |
||
57 | protected $activityData; |
||
58 | |||
59 | /** @var \OCA\Activity\UserSettings */ |
||
60 | protected $userSettings; |
||
61 | |||
62 | /** @var \OCP\IGroupManager */ |
||
63 | protected $groupManager; |
||
64 | |||
65 | /** @var \OCP\IDBConnection */ |
||
66 | protected $connection; |
||
67 | |||
68 | /** @var \OC\Files\View */ |
||
69 | protected $view; |
||
70 | |||
71 | /** @var IRootFolder */ |
||
72 | protected $rootFolder; |
||
73 | |||
74 | /** @var IShareHelper */ |
||
75 | protected $shareHelper; |
||
76 | |||
77 | /** @var IURLGenerator */ |
||
78 | protected $urlGenerator; |
||
79 | |||
80 | /** @var ILogger */ |
||
81 | protected $logger; |
||
82 | |||
83 | /** @var CurrentUser */ |
||
84 | protected $currentUser; |
||
85 | |||
86 | /** @var string|bool */ |
||
87 | protected $moveCase = false; |
||
88 | /** @var array */ |
||
89 | protected $oldAccessList; |
||
90 | /** @var string */ |
||
91 | protected $oldParentPath; |
||
92 | /** @var string */ |
||
93 | protected $oldParentOwner; |
||
94 | /** @var string */ |
||
95 | protected $oldParentId; |
||
96 | |||
97 | /** |
||
98 | * Constructor |
||
99 | * |
||
100 | * @param IManager $manager |
||
101 | * @param Data $activityData |
||
102 | * @param UserSettings $userSettings |
||
103 | * @param IGroupManager $groupManager |
||
104 | * @param View $view |
||
105 | * @param IRootFolder $rootFolder |
||
106 | * @param IShareHelper $shareHelper |
||
107 | * @param IDBConnection $connection |
||
108 | * @param IURLGenerator $urlGenerator |
||
109 | * @param ILogger $logger |
||
110 | * @param CurrentUser $currentUser |
||
111 | */ |
||
112 | 49 | public function __construct(IManager $manager, |
|
113 | Data $activityData, |
||
114 | UserSettings $userSettings, |
||
115 | IGroupManager $groupManager, |
||
116 | View $view, |
||
117 | IRootFolder $rootFolder, |
||
118 | IShareHelper $shareHelper, |
||
119 | IDBConnection $connection, |
||
120 | IURLGenerator $urlGenerator, |
||
121 | ILogger $logger, |
||
122 | CurrentUser $currentUser) { |
||
123 | 49 | $this->manager = $manager; |
|
124 | 49 | $this->activityData = $activityData; |
|
125 | 49 | $this->userSettings = $userSettings; |
|
126 | 49 | $this->groupManager = $groupManager; |
|
127 | 49 | $this->view = $view; |
|
128 | 49 | $this->rootFolder = $rootFolder; |
|
129 | 49 | $this->shareHelper = $shareHelper; |
|
130 | 49 | $this->connection = $connection; |
|
131 | 49 | $this->urlGenerator = $urlGenerator; |
|
132 | 49 | $this->logger = $logger; |
|
133 | 49 | $this->currentUser = $currentUser; |
|
134 | 49 | } |
|
135 | |||
136 | /** |
||
137 | * Store the create hook events |
||
138 | * @param string $path Path of the file that has been created |
||
139 | */ |
||
140 | 4 | public function fileCreate($path) { |
|
141 | 4 | if ($path === '/' || $path === '' || $path === null) { |
|
142 | 2 | return; |
|
143 | } |
||
144 | |||
145 | 2 | if ($this->currentUser->getUserIdentifier() !== '') { |
|
146 | 1 | $this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CREATED, 'created_self', 'created_by'); |
|
147 | } else { |
||
148 | 1 | $this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CREATED, '', 'created_public'); |
|
149 | } |
||
150 | 2 | } |
|
151 | |||
152 | /** |
||
153 | * Store the update hook events |
||
154 | * @param string $path Path of the file that has been modified |
||
155 | */ |
||
156 | 1 | public function fileUpdate($path) { |
|
157 | 1 | $this->addNotificationsForFileAction($path, Files::TYPE_SHARE_CHANGED, 'changed_self', 'changed_by'); |
|
158 | 1 | } |
|
159 | |||
160 | /** |
||
161 | * Store the delete hook events |
||
162 | * @param string $path Path of the file that has been deleted |
||
163 | */ |
||
164 | 1 | public function fileDelete($path) { |
|
165 | 1 | $this->addNotificationsForFileAction($path, Files::TYPE_SHARE_DELETED, 'deleted_self', 'deleted_by'); |
|
166 | 1 | } |
|
167 | |||
168 | /** |
||
169 | * Store the restore hook events |
||
170 | * @param string $path Path of the file that has been restored |
||
171 | */ |
||
172 | 1 | public function fileRestore($path) { |
|
173 | 1 | $this->addNotificationsForFileAction($path, Files::TYPE_SHARE_RESTORED, 'restored_self', 'restored_by'); |
|
174 | 1 | } |
|
175 | |||
176 | /** |
||
177 | * Creates the entries for file actions on $file_path |
||
178 | * |
||
179 | * @param string $filePath The file that is being changed |
||
180 | * @param int $activityType The activity type |
||
181 | * @param string $subject The subject for the actor |
||
182 | * @param string $subjectBy The subject for other users (with "by $actor") |
||
183 | */ |
||
184 | 3 | protected function addNotificationsForFileAction($filePath, $activityType, $subject, $subjectBy) { |
|
185 | // Do not add activities for .part-files |
||
186 | 3 | if (substr($filePath, -5) === '.part') { |
|
187 | 1 | return; |
|
188 | } |
||
189 | |||
190 | 2 | list($filePath, $uidOwner, $fileId) = $this->getSourcePathAndOwner($filePath); |
|
191 | 2 | if ($fileId === 0) { |
|
192 | // Could not find the file for the owner ... |
||
193 | return; |
||
194 | } |
||
195 | |||
196 | 2 | $accessList = $this->getUserPathsFromPath($filePath, $uidOwner); |
|
197 | |||
198 | 2 | $this->generateRemoteActivity($accessList['remotes'], $activityType, time(), $this->currentUser->getCloudId(), $accessList['ownerPath']); |
|
199 | |||
200 | 2 | $affectedUsers = $accessList['users']; |
|
201 | 2 | $filteredStreamUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'stream', $activityType); |
|
202 | 2 | $filteredEmailUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'email', $activityType); |
|
203 | |||
204 | 2 | foreach ($affectedUsers as $user => $path) { |
|
205 | 2 | $user = (string) $user; |
|
206 | 2 | if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) { |
|
207 | 2 | continue; |
|
208 | } |
||
209 | |||
210 | 2 | if ($user === $this->currentUser->getUID()) { |
|
211 | 1 | $userSubject = $subject; |
|
212 | 1 | $userParams = [[$fileId => $path]]; |
|
213 | } else { |
||
214 | 1 | $userSubject = $subjectBy; |
|
215 | 1 | $userParams = [[$fileId => $path], $this->currentUser->getUserIdentifier()]; |
|
216 | } |
||
217 | |||
218 | 2 | $this->addNotificationsForUser( |
|
219 | 2 | $user, $userSubject, $userParams, |
|
220 | 2 | $fileId, $path, true, |
|
221 | 2 | !empty($filteredStreamUsers[$user]), |
|
222 | 2 | $filteredEmailUsers[$user] ?? false, |
|
223 | $activityType |
||
224 | ); |
||
225 | } |
||
226 | 2 | } |
|
227 | |||
228 | 2 | protected function generateRemoteActivity(array $remoteUsers, $type, $time, $actor, $ownerPath = false) { |
|
229 | 2 | foreach ($remoteUsers as $remoteUser => $info) { |
|
230 | if ($actor === $remoteUser) { |
||
231 | // Current user receives the notification on their own instance already |
||
232 | continue; |
||
233 | } |
||
234 | |||
235 | $arguments = [ |
||
236 | $remoteUser, |
||
237 | $info['token'], |
||
238 | $ownerPath !== false ? substr($ownerPath, strlen($info['node_path'])) : $info['node_path'], |
||
239 | $type, |
||
240 | $time, |
||
241 | $actor, |
||
242 | ]; |
||
243 | |||
244 | if (isset($info['second_path'])) { |
||
245 | $arguments[] = $info['second_path']; |
||
246 | } |
||
247 | |||
248 | \OC::$server->getJobList()->add(RemoteActivity::class, $arguments); |
||
249 | } |
||
250 | 2 | } |
|
251 | |||
252 | /** |
||
253 | * Collect some information for move/renames |
||
254 | * |
||
255 | * @param string $oldPath Path of the file that has been moved |
||
256 | * @param string $newPath Path of the file that has been moved |
||
257 | */ |
||
258 | public function fileMove($oldPath, $newPath) { |
||
259 | if (substr($oldPath, -5) === '.part' || substr($newPath, -5) === '.part') { |
||
260 | // Do not add activities for .part-files |
||
261 | $this->moveCase = false; |
||
262 | return; |
||
263 | } |
||
264 | |||
265 | $oldDir = dirname($oldPath); |
||
266 | $newDir = dirname($newPath); |
||
267 | |||
268 | if ($oldDir === $newDir) { |
||
269 | /** |
||
270 | * a/b moved to a/c |
||
271 | * |
||
272 | * Cases: |
||
273 | * - a/b shared: no visible change |
||
274 | * - a/ shared: rename |
||
275 | */ |
||
276 | $this->moveCase = 'rename'; |
||
277 | return; |
||
278 | } |
||
279 | |||
280 | if (strpos($oldDir, $newDir) === 0) { |
||
281 | /** |
||
282 | * a/b/c moved to a/c |
||
283 | * |
||
284 | * Cases: |
||
285 | * - a/b/c shared: no visible change |
||
286 | * - a/b/ shared: delete |
||
287 | * - a/ shared: move/rename |
||
288 | */ |
||
289 | $this->moveCase = 'moveUp'; |
||
290 | } else if (strpos($newDir, $oldDir) === 0) { |
||
291 | /** |
||
292 | * a/b moved to a/c/b |
||
293 | * |
||
294 | * Cases: |
||
295 | * - a/b shared: no visible change |
||
296 | * - a/c/ shared: add |
||
297 | * - a/ shared: move/rename |
||
298 | */ |
||
299 | $this->moveCase = 'moveDown'; |
||
300 | } else { |
||
301 | /** |
||
302 | * a/b/c moved to a/d/c |
||
303 | * |
||
304 | * Cases: |
||
305 | * - a/b/c shared: no visible change |
||
306 | * - a/b/ shared: delete |
||
307 | * - a/d/ shared: add |
||
308 | * - a/ shared: move/rename |
||
309 | */ |
||
310 | $this->moveCase = 'moveCross'; |
||
311 | } |
||
312 | |||
313 | list($this->oldParentPath, $this->oldParentOwner, $this->oldParentId) = $this->getSourcePathAndOwner($oldDir); |
||
314 | if ($this->oldParentId === 0) { |
||
315 | // Could not find the file for the owner ... |
||
316 | $this->moveCase = false; |
||
317 | return; |
||
318 | } |
||
319 | $this->oldAccessList = $this->getUserPathsFromPath($this->oldParentPath, $this->oldParentOwner); |
||
320 | } |
||
321 | |||
322 | |||
323 | /** |
||
324 | * Store the move hook events |
||
325 | * |
||
326 | * @param string $oldPath Path of the file that has been moved |
||
327 | * @param string $newPath Path of the file that has been moved |
||
328 | */ |
||
329 | public function fileMovePost($oldPath, $newPath) { |
||
330 | // Do not add activities for .part-files |
||
331 | if ($this->moveCase === false) { |
||
332 | return; |
||
333 | } |
||
334 | |||
335 | switch ($this->moveCase) { |
||
336 | case 'rename': |
||
337 | $this->fileRenaming($oldPath, $newPath); |
||
338 | break; |
||
339 | case 'moveUp': |
||
340 | case 'moveDown': |
||
341 | case 'moveCross': |
||
342 | $this->fileMoving($oldPath, $newPath); |
||
343 | break; |
||
344 | } |
||
345 | |||
346 | $this->moveCase = false; |
||
347 | } |
||
348 | |||
349 | |||
350 | /** |
||
351 | * Renaming a file inside the same folder (a/b to a/c) |
||
352 | * |
||
353 | * @param string $oldPath |
||
354 | * @param string $newPath |
||
355 | */ |
||
356 | protected function fileRenaming($oldPath, $newPath) { |
||
357 | $dirName = dirname($newPath); |
||
358 | $fileName = basename($newPath); |
||
359 | $oldFileName = basename($oldPath); |
||
360 | |||
361 | list(, , $fileId) = $this->getSourcePathAndOwner($newPath); |
||
362 | list($parentPath, $parentOwner, $parentId) = $this->getSourcePathAndOwner($dirName); |
||
363 | if ($fileId === 0 || $parentId === 0) { |
||
364 | // Could not find the file for the owner ... |
||
365 | return; |
||
366 | } |
||
367 | $accessList = $this->getUserPathsFromPath($parentPath, $parentOwner); |
||
368 | |||
369 | $renameRemotes = []; |
||
370 | foreach ($accessList['remotes'] as $remote => $info) { |
||
371 | $renameRemotes[$remote] = [ |
||
372 | 'token' => $info['token'], |
||
373 | 'node_path' => substr($newPath, strlen($info['node_path'])), |
||
374 | 'second_path' => substr($oldPath, strlen($info['node_path'])), |
||
375 | ]; |
||
376 | } |
||
377 | $this->generateRemoteActivity($renameRemotes, Files::TYPE_SHARE_CHANGED, time(), $this->currentUser->getCloudId()); |
||
378 | |||
379 | $affectedUsers = $accessList['users']; |
||
380 | $filteredStreamUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'stream', Files::TYPE_SHARE_CHANGED); |
||
381 | $filteredEmailUsers = $this->userSettings->filterUsersBySetting(array_keys($affectedUsers), 'email', Files::TYPE_SHARE_CHANGED); |
||
382 | |||
383 | foreach ($affectedUsers as $user => $path) { |
||
384 | if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) { |
||
385 | continue; |
||
386 | } |
||
387 | |||
388 | if ($user === $this->currentUser->getUID()) { |
||
389 | $userSubject = 'renamed_self'; |
||
390 | $userParams = [ |
||
391 | [$fileId => $path . '/' . $fileName], |
||
392 | [$fileId => $path . '/' . $oldFileName], |
||
393 | ]; |
||
394 | } else { |
||
395 | $userSubject = 'renamed_by'; |
||
396 | $userParams = [ |
||
397 | [$fileId => $path . '/' . $fileName], |
||
398 | $this->currentUser->getUserIdentifier(), |
||
399 | [$fileId => $path . '/' . $oldFileName], |
||
400 | ]; |
||
401 | } |
||
402 | |||
403 | $this->addNotificationsForUser( |
||
404 | $user, $userSubject, $userParams, |
||
405 | $fileId, $path . '/' . $fileName, true, |
||
406 | !empty($filteredStreamUsers[$user]), |
||
407 | $filteredEmailUsers[$user] ?? false, |
||
408 | Files::TYPE_SHARE_CHANGED |
||
409 | ); |
||
410 | } |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Moving a file from one folder to another |
||
415 | * |
||
416 | * @param string $oldPath |
||
417 | * @param string $newPath |
||
418 | */ |
||
419 | protected function fileMoving($oldPath, $newPath) { |
||
420 | $dirName = dirname($newPath); |
||
421 | $fileName = basename($newPath); |
||
422 | $oldFileName = basename($oldPath); |
||
423 | |||
424 | list(, , $fileId) = $this->getSourcePathAndOwner($newPath); |
||
425 | list($parentPath, $parentOwner, $parentId) = $this->getSourcePathAndOwner($dirName); |
||
426 | if ($fileId === 0 || $parentId === 0) { |
||
427 | // Could not find the file for the owner ... |
||
428 | return; |
||
429 | } |
||
430 | $accessList = $this->getUserPathsFromPath($parentPath, $parentOwner); |
||
431 | $affectedUsers = $accessList['users']; |
||
432 | $oldUsers = $this->oldAccessList['users']; |
||
433 | |||
434 | $beforeUsers = array_keys($oldUsers); |
||
435 | $afterUsers = array_keys($affectedUsers); |
||
436 | |||
437 | $deleteUsers = array_diff($beforeUsers, $afterUsers); |
||
438 | $this->generateDeleteActivities($deleteUsers, $oldUsers, $fileId, $oldFileName); |
||
439 | |||
440 | $addUsers = array_diff($afterUsers, $beforeUsers); |
||
441 | $this->generateAddActivities($addUsers, $affectedUsers, $fileId, $fileName); |
||
442 | |||
443 | $moveUsers = array_intersect($beforeUsers, $afterUsers); |
||
444 | $this->generateMoveActivities($moveUsers, $oldUsers, $affectedUsers, $fileId, $oldFileName, $parentId, $fileName); |
||
445 | |||
446 | $beforeRemotes = $this->oldAccessList['remotes']; |
||
447 | $afterRemotes = $accessList['remotes']; |
||
448 | |||
449 | $addRemotes = $deleteRemotes = $moveRemotes = []; |
||
450 | foreach ($afterRemotes as $remote => $info) { |
||
451 | if (isset($beforeRemotes[$remote])) { |
||
452 | // Move |
||
453 | $info['node_path'] = substr($newPath, strlen($info['node_path'])); |
||
454 | $info['second_path'] = substr($oldPath, strlen($beforeRemotes[$remote]['node_path'])); |
||
455 | $moveRemotes[$remote] = $info; |
||
456 | } else { |
||
457 | $info['node_path'] = substr($newPath, strlen($info['node_path'])); |
||
458 | $addRemotes[$remote] = $info; |
||
459 | } |
||
460 | } |
||
461 | |||
462 | foreach ($beforeRemotes as $remote => $info) { |
||
463 | if (!isset($afterRemotes[$remote])) { |
||
464 | $info['node_path'] = substr($oldPath, strlen($info['node_path'])); |
||
465 | $deleteRemotes[$remote] = $info; |
||
466 | } |
||
467 | } |
||
468 | |||
469 | $this->generateRemoteActivity($deleteRemotes, Files::TYPE_SHARE_DELETED, time(), $this->currentUser->getCloudId()); |
||
470 | $this->generateRemoteActivity($addRemotes, Files::TYPE_SHARE_CREATED, time(), $this->currentUser->getCloudId()); |
||
471 | $this->generateRemoteActivity($moveRemotes, Files::TYPE_SHARE_CHANGED, time(), $this->currentUser->getCloudId()); |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * @param string[] $users |
||
476 | * @param string[] $pathMap |
||
477 | * @param int $fileId |
||
478 | * @param string $oldFileName |
||
479 | */ |
||
480 | View Code Duplication | protected function generateDeleteActivities($users, $pathMap, $fileId, $oldFileName) { |
|
0 ignored issues
–
show
|
|||
481 | if (empty($users)) { |
||
482 | return; |
||
483 | } |
||
484 | |||
485 | $filteredStreamUsers = $this->userSettings->filterUsersBySetting($users, 'stream', Files::TYPE_SHARE_DELETED); |
||
486 | $filteredEmailUsers = $this->userSettings->filterUsersBySetting($users, 'email', Files::TYPE_SHARE_DELETED); |
||
487 | |||
488 | foreach ($users as $user) { |
||
489 | if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) { |
||
490 | continue; |
||
491 | } |
||
492 | |||
493 | $path = $pathMap[$user]; |
||
494 | |||
495 | if ($user === $this->currentUser->getUID()) { |
||
496 | $userSubject = 'deleted_self'; |
||
497 | $userParams = [[$fileId => $path . '/' . $oldFileName]]; |
||
498 | } else { |
||
499 | $userSubject = 'deleted_by'; |
||
500 | $userParams = [[$fileId => $path . '/' . $oldFileName], $this->currentUser->getUserIdentifier()]; |
||
501 | } |
||
502 | |||
503 | $this->addNotificationsForUser( |
||
504 | $user, $userSubject, $userParams, |
||
505 | $fileId, $path . '/' . $oldFileName, true, |
||
506 | !empty($filteredStreamUsers[$user]), |
||
507 | $filteredEmailUsers[$user] ?? false, |
||
508 | Files::TYPE_SHARE_DELETED |
||
509 | ); |
||
510 | } |
||
511 | } |
||
512 | |||
513 | /** |
||
514 | * @param string[] $users |
||
515 | * @param string[] $pathMap |
||
516 | * @param int $fileId |
||
517 | * @param string $fileName |
||
518 | */ |
||
519 | View Code Duplication | protected function generateAddActivities($users, $pathMap, $fileId, $fileName) { |
|
0 ignored issues
–
show
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. ![]() |
|||
520 | if (empty($users)) { |
||
521 | return; |
||
522 | } |
||
523 | |||
524 | $filteredStreamUsers = $this->userSettings->filterUsersBySetting($users, 'stream', Files::TYPE_SHARE_CREATED); |
||
525 | $filteredEmailUsers = $this->userSettings->filterUsersBySetting($users, 'email', Files::TYPE_SHARE_CREATED); |
||
526 | |||
527 | foreach ($users as $user) { |
||
528 | if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) { |
||
529 | continue; |
||
530 | } |
||
531 | |||
532 | $path = $pathMap[$user]; |
||
533 | |||
534 | if ($user === $this->currentUser->getUID()) { |
||
535 | $userSubject = 'created_self'; |
||
536 | $userParams = [[$fileId => $path . '/' . $fileName]]; |
||
537 | } else { |
||
538 | $userSubject = 'created_by'; |
||
539 | $userParams = [[$fileId => $path . '/' . $fileName], $this->currentUser->getUserIdentifier()]; |
||
540 | } |
||
541 | |||
542 | $this->addNotificationsForUser( |
||
543 | $user, $userSubject, $userParams, |
||
544 | $fileId, $path . '/' . $fileName, true, |
||
545 | !empty($filteredStreamUsers[$user]), |
||
546 | $filteredEmailUsers[$user] ?? false, |
||
547 | Files::TYPE_SHARE_CREATED |
||
548 | ); |
||
549 | } |
||
550 | } |
||
551 | |||
552 | /** |
||
553 | * @param string[] $users |
||
554 | * @param string[] $beforePathMap |
||
555 | * @param string[] $afterPathMap |
||
556 | * @param int $fileId |
||
557 | * @param string $oldFileName |
||
558 | * @param int $newParentId |
||
559 | * @param string $fileName |
||
560 | */ |
||
561 | protected function generateMoveActivities($users, $beforePathMap, $afterPathMap, $fileId, $oldFileName, $newParentId, $fileName) { |
||
562 | if (empty($users)) { |
||
563 | return; |
||
564 | } |
||
565 | |||
566 | $filteredStreamUsers = $this->userSettings->filterUsersBySetting($users, 'stream', Files::TYPE_SHARE_CHANGED); |
||
567 | $filteredEmailUsers = $this->userSettings->filterUsersBySetting($users, 'email', Files::TYPE_SHARE_CHANGED); |
||
568 | |||
569 | foreach ($users as $user) { |
||
570 | if (empty($filteredStreamUsers[$user]) && empty($filteredEmailUsers[$user])) { |
||
571 | continue; |
||
572 | } |
||
573 | |||
574 | if ($oldFileName === $fileName) { |
||
575 | $userParams = [[$newParentId => $afterPathMap[$user] . '/']]; |
||
576 | } else { |
||
577 | $userParams = [[$fileId => $afterPathMap[$user] . '/' . $fileName]]; |
||
578 | } |
||
579 | |||
580 | if ($user === $this->currentUser->getUID()) { |
||
581 | $userSubject = 'moved_self'; |
||
582 | } else { |
||
583 | $userSubject = 'moved_by'; |
||
584 | $userParams[] = $this->currentUser->getUserIdentifier(); |
||
585 | } |
||
586 | $userParams[] = [$fileId => $beforePathMap[$user] . '/' . $oldFileName]; |
||
587 | |||
588 | $this->addNotificationsForUser( |
||
589 | $user, $userSubject, $userParams, |
||
590 | $fileId, $afterPathMap[$user] . '/' . $fileName, true, |
||
591 | !empty($filteredStreamUsers[$user]), |
||
592 | $filteredEmailUsers[$user] ?? false, |
||
593 | Files::TYPE_SHARE_CHANGED |
||
594 | ); |
||
595 | } |
||
596 | } |
||
597 | |||
598 | /** |
||
599 | * Returns a "username => path" map for all affected users |
||
600 | * |
||
601 | * @param string $path |
||
602 | * @param string $uidOwner |
||
603 | * @return array |
||
604 | */ |
||
605 | protected function getUserPathsFromPath($path, $uidOwner) { |
||
606 | try { |
||
607 | $node = $this->rootFolder->getUserFolder($uidOwner)->get($path); |
||
608 | } catch (NotFoundException $e) { |
||
0 ignored issues
–
show
The class
OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your 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. ![]() |
|||
609 | return []; |
||
610 | } |
||
611 | |||
612 | if (!$node instanceof Node) { |
||
0 ignored issues
–
show
The class
OCP\Files\Node 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 dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. ![]() |
|||
613 | return []; |
||
614 | } |
||
615 | |||
616 | $accessList = $this->shareHelper->getPathsForAccessList($node); |
||
617 | |||
618 | $path = $node->getPath(); |
||
619 | $sections = explode('/', $path, 4); |
||
620 | |||
621 | $accessList['ownerPath'] = '/'; |
||
622 | if (isset($sections[3])) { |
||
623 | // Not the case when a file in root is renamed |
||
624 | $accessList['ownerPath'] .= $sections[3]; |
||
625 | } |
||
626 | |||
627 | return $accessList; |
||
628 | } |
||
629 | |||
630 | /** |
||
631 | * Return the source |
||
632 | * |
||
633 | * @param string $path |
||
634 | * @return array |
||
635 | */ |
||
636 | protected function getSourcePathAndOwner($path) { |
||
637 | $view = Filesystem::getView(); |
||
638 | $owner = $view->getOwner($path); |
||
639 | $owner = !is_string($owner) || $owner === '' ? null : $owner; |
||
640 | $fileId = 0; |
||
641 | $currentUser = $this->currentUser->getUID(); |
||
642 | |||
643 | if ($owner === null || $owner !== $currentUser) { |
||
644 | /** @var \OCP\Files\Storage\IStorage $storage */ |
||
645 | list($storage,) = $view->resolvePath($path); |
||
646 | |||
647 | if ($owner !== null && !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) { |
||
648 | Filesystem::initMountPoints($owner); |
||
649 | } else { |
||
650 | // Probably a remote user, let's try to at least generate activities |
||
651 | // for the current user |
||
652 | if ($currentUser === null) { |
||
653 | list(,$owner,) = explode('/', $view->getAbsolutePath($path), 3); |
||
654 | } else { |
||
655 | $owner = $currentUser; |
||
656 | } |
||
657 | } |
||
658 | } |
||
659 | |||
660 | $info = Filesystem::getFileInfo($path); |
||
661 | if ($info !== false) { |
||
662 | $ownerView = new View('/' . $owner . '/files'); |
||
663 | $fileId = (int) $info['fileid']; |
||
664 | $path = $ownerView->getPath($fileId); |
||
665 | } |
||
666 | |||
667 | return array($path, $owner, $fileId); |
||
668 | } |
||
669 | |||
670 | /** |
||
671 | * Manage sharing events |
||
672 | * @param array $params The hook params |
||
673 | */ |
||
674 | 3 | public function share($params) { |
|
675 | 3 | if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { |
|
676 | 3 | if ((int) $params['shareType'] === Share::SHARE_TYPE_USER) { |
|
677 | 1 | $this->shareWithUser($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget']); |
|
678 | 2 | } else if ((int) $params['shareType'] === Share::SHARE_TYPE_GROUP) { |
|
679 | 1 | $this->shareWithGroup($params['shareWith'], (int) $params['fileSource'], $params['itemType'], $params['fileTarget'], (int) $params['id']); |
|
680 | 1 | } else if ((int) $params['shareType'] === Share::SHARE_TYPE_LINK) { |
|
681 | 1 | $this->shareByLink((int) $params['fileSource'], $params['itemType'], $params['uidOwner']); |
|
682 | } |
||
683 | } |
||
684 | 3 | } |
|
685 | |||
686 | /** |
||
687 | * Sharing a file or folder with a user |
||
688 | * |
||
689 | * @param string $shareWith |
||
690 | * @param int $fileSource File ID that is being shared |
||
691 | * @param string $itemType File type that is being shared (file or folder) |
||
692 | * @param string $fileTarget File path |
||
693 | */ |
||
694 | 2 | protected function shareWithUser($shareWith, $fileSource, $itemType, $fileTarget) { |
|
695 | // User performing the share |
||
696 | 2 | $this->shareNotificationForSharer('shared_user_self', $shareWith, $fileSource, $itemType); |
|
697 | 2 | View Code Duplication | if ($this->currentUser->getUID() !== null) { |
0 ignored issues
–
show
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. ![]() |
|||
698 | 2 | $this->shareNotificationForOriginalOwners($this->currentUser->getUID(), 'reshared_user_by', $shareWith, $fileSource, $itemType); |
|
699 | } |
||
700 | |||
701 | // New shared user |
||
702 | 2 | $this->addNotificationsForUser( |
|
703 | 2 | $shareWith, 'shared_with_by', [[$fileSource => $fileTarget], $this->currentUser->getUserIdentifier()], |
|
704 | 2 | (int) $fileSource, $fileTarget, $itemType === 'file', |
|
705 | 2 | $this->userSettings->getUserSetting($shareWith, 'stream', Files_Sharing::TYPE_SHARED), |
|
0 ignored issues
–
show
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. ![]() |
|||
706 | 2 | $this->userSettings->getUserSetting($shareWith, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($shareWith, 'setting', 'batchtime') : false |
|
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
707 | ); |
||
708 | 2 | } |
|
709 | |||
710 | /** |
||
711 | * Sharing a file or folder with a group |
||
712 | * |
||
713 | * @param string $shareWith |
||
714 | * @param int $fileSource File ID that is being shared |
||
715 | * @param string $itemType File type that is being shared (file or folder) |
||
716 | * @param string $fileTarget File path |
||
717 | * @param int $shareId The Share ID of this share |
||
718 | */ |
||
719 | 6 | protected function shareWithGroup($shareWith, $fileSource, $itemType, $fileTarget, $shareId) { |
|
720 | // Members of the new group |
||
721 | 6 | $group = $this->groupManager->get($shareWith); |
|
722 | 6 | if (!($group instanceof IGroup)) { |
|
0 ignored issues
–
show
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 dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. ![]() |
|||
723 | 1 | return; |
|
724 | } |
||
725 | |||
726 | // User performing the share |
||
727 | 5 | $this->shareNotificationForSharer('shared_group_self', $shareWith, $fileSource, $itemType); |
|
728 | 5 | View Code Duplication | if ($this->currentUser->getUID() !== null) { |
0 ignored issues
–
show
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. ![]() |
|||
729 | 5 | $this->shareNotificationForOriginalOwners($this->currentUser->getUID(), 'reshared_group_by', $shareWith, $fileSource, $itemType); |
|
730 | } |
||
731 | |||
732 | 5 | $offset = 0; |
|
733 | 5 | $users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset); |
|
734 | 5 | while (!empty($users)) { |
|
735 | 4 | $this->addNotificationsForGroupUsers($users, 'shared_with_by', $fileSource, $itemType, $fileTarget, $shareId); |
|
736 | 4 | $offset += self::USER_BATCH_SIZE; |
|
737 | 4 | $users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset); |
|
738 | } |
||
739 | 5 | } |
|
740 | |||
741 | /** |
||
742 | * Sharing a file or folder via link/public |
||
743 | * |
||
744 | * @param int $fileSource File ID that is being shared |
||
745 | * @param string $itemType File type that is being shared (file or folder) |
||
746 | * @param string $linkOwner |
||
747 | */ |
||
748 | 2 | protected function shareByLink($fileSource, $itemType, $linkOwner) { |
|
749 | 2 | $this->view->chroot('/' . $linkOwner . '/files'); |
|
750 | |||
751 | try { |
||
752 | 2 | $path = $this->view->getPath($fileSource); |
|
753 | 1 | } catch (NotFoundException $e) { |
|
0 ignored issues
–
show
The class
OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your 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. ![]() |
|||
754 | 1 | return; |
|
755 | } |
||
756 | |||
757 | 1 | $this->shareNotificationForOriginalOwners($linkOwner, 'reshared_link_by', '', $fileSource, $itemType); |
|
758 | |||
759 | 1 | $this->addNotificationsForUser( |
|
760 | 1 | $linkOwner, 'shared_link_self', [[$fileSource => $path]], |
|
761 | 1 | (int) $fileSource, $path, $itemType === 'file', |
|
762 | 1 | $this->userSettings->getUserSetting($linkOwner, 'stream', Files_Sharing::TYPE_SHARED), |
|
0 ignored issues
–
show
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. ![]() |
|||
763 | 1 | $this->userSettings->getUserSetting($linkOwner, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($linkOwner, 'setting', 'batchtime') : false |
|
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
764 | ); |
||
765 | 1 | } |
|
766 | |||
767 | /** |
||
768 | * Manage unsharing events |
||
769 | * @param IShare $share |
||
770 | * @throws \OCP\Files\NotFoundException |
||
771 | */ |
||
772 | public function unShare(IShare $share) { |
||
773 | if (in_array($share->getNodeType(), ['file', 'folder'], true)) { |
||
774 | if ($share->getShareType() === Share::SHARE_TYPE_USER) { |
||
775 | $this->unshareFromUser($share); |
||
776 | } else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) { |
||
777 | $this->unshareFromGroup($share); |
||
778 | } else if ($share->getShareType() === Share::SHARE_TYPE_LINK) { |
||
779 | $this->unshareLink($share); |
||
780 | } |
||
781 | } |
||
782 | } |
||
783 | |||
784 | /** |
||
785 | * Unharing a file or folder from a user |
||
786 | * |
||
787 | * @param IShare $share |
||
788 | * @throws \OCP\Files\NotFoundException |
||
789 | */ |
||
790 | protected function unshareFromUser(IShare $share) { |
||
791 | if ($share->getSharedWith() === $this->currentUser->getUID()) { |
||
792 | $this->selfUnshareFromUser($share); |
||
793 | return; |
||
794 | } |
||
795 | |||
796 | // User performing the share |
||
797 | $this->shareNotificationForSharer('unshared_user_self', $share->getSharedWith(), $share->getNodeId(), $share->getNodeType()); |
||
798 | |||
799 | // Owner |
||
800 | View Code Duplication | if ($this->currentUser->getUID() !== null) { |
|
0 ignored issues
–
show
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. ![]() |
|||
801 | $this->shareNotificationForOriginalOwners($this->currentUser->getUID(), 'unshared_user_by', $share->getSharedWith(), $share->getNodeId(), $share->getNodeType()); |
||
802 | } |
||
803 | |||
804 | // Recipient |
||
805 | $this->addNotificationsForUser( |
||
806 | $share->getSharedWith(), 'unshared_by', [[$share->getNodeId() => $share->getTarget()], $this->currentUser->getUserIdentifier()], |
||
807 | $share->getNodeId(), $share->getTarget(), $share->getNodeType() === 'file', |
||
808 | $this->userSettings->getUserSetting($share->getSharedWith(), 'stream', Files_Sharing::TYPE_SHARED), |
||
0 ignored issues
–
show
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. ![]() |
|||
809 | $this->userSettings->getUserSetting($share->getSharedWith(), 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($share->getSharedWith(), 'setting', 'batchtime') : false |
||
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
810 | ); |
||
811 | } |
||
812 | |||
813 | /** |
||
814 | * Unharing a file or folder from a user |
||
815 | * |
||
816 | * @param IShare $share |
||
817 | * @throws \OCP\Files\NotFoundException |
||
818 | */ |
||
819 | protected function selfUnshareFromUser(IShare $share) { |
||
820 | // User performing the share |
||
821 | $this->shareNotificationForSharer('self_unshared', $share->getSharedWith(), $share->getNodeId(), $share->getNodeType()); |
||
822 | |||
823 | // Owner |
||
824 | View Code Duplication | if ($this->currentUser->getUID() !== null) { |
|
0 ignored issues
–
show
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. ![]() |
|||
825 | $this->shareNotificationForOriginalOwners($this->currentUser->getUID(), 'self_unshared_by', $share->getSharedWith(), $share->getNodeId(), $share->getNodeType()); |
||
826 | } |
||
827 | } |
||
828 | |||
829 | /** |
||
830 | * Unsharing a file or folder from a group |
||
831 | * |
||
832 | * @param IShare $share |
||
833 | * @throws \OCP\Files\NotFoundException |
||
834 | */ |
||
835 | protected function unshareFromGroup(IShare $share) { |
||
836 | // Members of the new group |
||
837 | $group = $this->groupManager->get($share->getSharedWith()); |
||
838 | if (!($group instanceof IGroup)) { |
||
0 ignored issues
–
show
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 dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. ![]() |
|||
839 | return; |
||
840 | } |
||
841 | |||
842 | // User performing the share |
||
843 | $this->shareNotificationForSharer('unshared_group_self', $share->getSharedWith(), $share->getNodeId(), $share->getNodeType()); |
||
844 | View Code Duplication | if ($this->currentUser->getUID() !== null) { |
|
0 ignored issues
–
show
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. ![]() |
|||
845 | $this->shareNotificationForOriginalOwners($this->currentUser->getUID(), 'unshared_group_by', $share->getSharedWith(), $share->getNodeId(), $share->getNodeType()); |
||
846 | } |
||
847 | |||
848 | $offset = 0; |
||
849 | $users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset); |
||
850 | while (!empty($users)) { |
||
851 | $this->addNotificationsForGroupUsers($users, 'unshared_by', $share->getNodeId(), $share->getNodeType(), $share->getTarget(), $share->getId()); |
||
852 | $offset += self::USER_BATCH_SIZE; |
||
853 | $users = $group->searchUsers('', self::USER_BATCH_SIZE, $offset); |
||
854 | } |
||
855 | } |
||
856 | |||
857 | /** |
||
858 | * Sharing a file or folder via link/public |
||
859 | * |
||
860 | * @param IShare $share |
||
861 | * @throws \OCP\Files\NotFoundException |
||
862 | */ |
||
863 | protected function unshareLink(IShare $share) { |
||
864 | $owner = $share->getSharedBy(); |
||
865 | if ($this->currentUser->getUID() === null) { |
||
866 | // Link expired |
||
867 | $actionSharer = 'link_expired'; |
||
868 | $actionOwner = 'link_by_expired'; |
||
869 | } else { |
||
870 | $actionSharer = 'unshared_link_self'; |
||
871 | $actionOwner = 'unshared_link_by'; |
||
872 | } |
||
873 | |||
874 | $this->addNotificationsForUser( |
||
875 | $owner, $actionSharer, [[$share->getNodeId() => $share->getTarget()]], |
||
876 | $share->getNodeId(), $share->getTarget(), $share->getNodeType() === 'file', |
||
877 | $this->userSettings->getUserSetting($owner, 'stream', Files_Sharing::TYPE_SHARED), |
||
0 ignored issues
–
show
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. ![]() |
|||
878 | $this->userSettings->getUserSetting($owner, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($owner, 'setting', 'batchtime') : false |
||
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
879 | ); |
||
880 | |||
881 | if ($share->getSharedBy() !== $share->getShareOwner()) { |
||
882 | $owner = $share->getShareOwner(); |
||
883 | $this->addNotificationsForUser( |
||
884 | $owner, $actionOwner, [[$share->getNodeId() => $share->getTarget()], $share->getSharedBy()], |
||
885 | $share->getNodeId(), $share->getTarget(), $share->getNodeType() === 'file', |
||
886 | $this->userSettings->getUserSetting($owner, 'stream', Files_Sharing::TYPE_SHARED), |
||
0 ignored issues
–
show
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. ![]() |
|||
887 | $this->userSettings->getUserSetting($owner, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($owner, 'setting', 'batchtime') : false |
||
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
888 | ); |
||
889 | } |
||
890 | } |
||
891 | |||
892 | /** |
||
893 | * @param IUser[] $usersInGroup |
||
894 | * @param string $actionUser |
||
895 | * @param int $fileSource File ID that is being shared |
||
896 | * @param string $itemType File type that is being shared (file or folder) |
||
897 | * @param string $fileTarget File path |
||
898 | * @param int $shareId The Share ID of this share |
||
899 | */ |
||
900 | 4 | protected function addNotificationsForGroupUsers(array $usersInGroup, $actionUser, $fileSource, $itemType, $fileTarget, $shareId) { |
|
901 | 4 | $affectedUsers = []; |
|
902 | |||
903 | 4 | foreach ($usersInGroup as $user) { |
|
904 | 4 | $affectedUsers[$user->getUID()] = $fileTarget; |
|
905 | } |
||
906 | |||
907 | // Remove the triggering user, we already managed his notifications |
||
908 | 4 | unset($affectedUsers[$this->currentUser->getUID()]); |
|
909 | |||
910 | 4 | if (empty($affectedUsers)) { |
|
911 | 1 | return; |
|
912 | } |
||
913 | |||
914 | 3 | $userIds = array_keys($affectedUsers); |
|
915 | 3 | $filteredStreamUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'stream', Files_Sharing::TYPE_SHARED); |
|
916 | 3 | $filteredEmailUsersInGroup = $this->userSettings->filterUsersBySetting($userIds, 'email', Files_Sharing::TYPE_SHARED); |
|
917 | |||
918 | 3 | $affectedUsers = $this->fixPathsForShareExceptions($affectedUsers, $shareId); |
|
919 | 3 | foreach ($affectedUsers as $user => $path) { |
|
920 | 3 | if (empty($filteredStreamUsersInGroup[$user]) && empty($filteredEmailUsersInGroup[$user])) { |
|
921 | 2 | continue; |
|
922 | } |
||
923 | |||
924 | 1 | $this->addNotificationsForUser( |
|
925 | 1 | $user, $actionUser, [[$fileSource => $path], $this->currentUser->getUserIdentifier()], |
|
926 | 1 | $fileSource, $path, ($itemType === 'file'), |
|
927 | 1 | !empty($filteredStreamUsersInGroup[$user]), |
|
928 | 1 | $filteredEmailUsersInGroup[$user] ?? false |
|
929 | ); |
||
930 | } |
||
931 | 3 | } |
|
932 | |||
933 | /** |
||
934 | * Check when there was a naming conflict and the target is different |
||
935 | * for some of the users |
||
936 | * |
||
937 | * @param array $affectedUsers |
||
938 | * @param int $shareId |
||
939 | * @return mixed |
||
940 | */ |
||
941 | protected function fixPathsForShareExceptions(array $affectedUsers, $shareId) { |
||
942 | $queryBuilder = $this->connection->getQueryBuilder(); |
||
943 | $queryBuilder->select(['share_with', 'file_target']) |
||
944 | ->from('share') |
||
945 | ->where($queryBuilder->expr()->eq('parent', $queryBuilder->createParameter('parent'))) |
||
946 | ->setParameter('parent', (int) $shareId); |
||
947 | $query = $queryBuilder->execute(); |
||
948 | |||
949 | while ($row = $query->fetch()) { |
||
950 | $affectedUsers[$row['share_with']] = $row['file_target']; |
||
951 | } |
||
952 | |||
953 | return $affectedUsers; |
||
954 | } |
||
955 | |||
956 | /** |
||
957 | * Add notifications for the user that shares a file/folder |
||
958 | * |
||
959 | * @param string $subject |
||
960 | * @param string $shareWith |
||
961 | * @param int $fileSource |
||
962 | * @param string $itemType |
||
963 | */ |
||
964 | 2 | protected function shareNotificationForSharer($subject, $shareWith, $fileSource, $itemType) { |
|
965 | 2 | $sharer = $this->currentUser->getUID(); |
|
966 | 2 | if ($sharer === null) { |
|
967 | return; |
||
968 | } |
||
969 | |||
970 | 2 | $this->view->chroot('/' . $sharer . '/files'); |
|
971 | |||
972 | try { |
||
973 | 2 | $path = $this->view->getPath($fileSource); |
|
974 | 1 | } catch (NotFoundException $e) { |
|
0 ignored issues
–
show
The class
OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your 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. ![]() |
|||
975 | 1 | return; |
|
976 | } |
||
977 | |||
978 | 1 | $this->addNotificationsForUser( |
|
979 | 1 | $sharer, $subject, [[$fileSource => $path], $shareWith], |
|
980 | 1 | $fileSource, $path, ($itemType === 'file'), |
|
981 | 1 | $this->userSettings->getUserSetting($sharer, 'stream', Files_Sharing::TYPE_SHARED), |
|
0 ignored issues
–
show
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. ![]() |
|||
982 | 1 | $this->userSettings->getUserSetting($sharer, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($sharer, 'setting', 'batchtime') : false |
|
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
983 | ); |
||
984 | 1 | } |
|
985 | |||
986 | /** |
||
987 | * Add notifications for the user that shares a file/folder |
||
988 | * |
||
989 | * @param string $owner |
||
990 | * @param string $subject |
||
991 | * @param string $shareWith |
||
992 | * @param int $fileSource |
||
993 | * @param string $itemType |
||
994 | */ |
||
995 | 2 | protected function reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType) { |
|
996 | 2 | $this->view->chroot('/' . $owner . '/files'); |
|
997 | |||
998 | try { |
||
999 | 2 | $path = $this->view->getPath($fileSource); |
|
1000 | 1 | } catch (NotFoundException $e) { |
|
0 ignored issues
–
show
The class
OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your 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. ![]() |
|||
1001 | 1 | return; |
|
1002 | } |
||
1003 | |||
1004 | 1 | $this->addNotificationsForUser( |
|
1005 | 1 | $owner, $subject, [[$fileSource => $path], $this->currentUser->getUserIdentifier(), $shareWith], |
|
1006 | 1 | $fileSource, $path, ($itemType === 'file'), |
|
1007 | 1 | $this->userSettings->getUserSetting($owner, 'stream', Files_Sharing::TYPE_SHARED), |
|
0 ignored issues
–
show
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. ![]() |
|||
1008 | 1 | $this->userSettings->getUserSetting($owner, 'email', Files_Sharing::TYPE_SHARED) ? $this->userSettings->getUserSetting($owner, 'setting', 'batchtime') : false |
|
0 ignored issues
–
show
It seems like
$this->userSettings->get...', 'batchtime') : false 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. ![]() |
|||
1009 | ); |
||
1010 | 1 | } |
|
1011 | |||
1012 | /** |
||
1013 | * Add notifications for the owners whose files have been reshared |
||
1014 | * |
||
1015 | * @param string $currentOwner |
||
1016 | * @param string $subject |
||
1017 | * @param string $shareWith |
||
1018 | * @param int $fileSource |
||
1019 | * @param string $itemType |
||
1020 | */ |
||
1021 | 10 | protected function shareNotificationForOriginalOwners($currentOwner, $subject, $shareWith, $fileSource, $itemType) { |
|
1022 | // Get the full path of the current user |
||
1023 | 10 | $this->view->chroot('/' . $currentOwner . '/files'); |
|
1024 | |||
1025 | try { |
||
1026 | 10 | $path = $this->view->getPath($fileSource); |
|
1027 | 1 | } catch (NotFoundException $e) { |
|
0 ignored issues
–
show
The class
OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your 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. ![]() |
|||
1028 | 1 | return; |
|
1029 | } |
||
1030 | |||
1031 | /** |
||
1032 | * Get the original owner and his path |
||
1033 | */ |
||
1034 | 9 | $owner = $this->view->getOwner($path); |
|
1035 | 9 | if ($owner !== $currentOwner) { |
|
1036 | 7 | $this->reshareNotificationForSharer($owner, $subject, $shareWith, $fileSource, $itemType); |
|
1037 | } |
||
1038 | |||
1039 | /** |
||
1040 | * Get the sharee who shared the item with the currentUser |
||
1041 | */ |
||
1042 | 9 | $this->view->chroot('/' . $currentOwner . '/files'); |
|
1043 | 9 | $mount = $this->view->getMount($path); |
|
1044 | 9 | if (!($mount instanceof IMountPoint)) { |
|
0 ignored issues
–
show
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 dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. ![]() |
|||
1045 | 1 | return; |
|
1046 | } |
||
1047 | |||
1048 | 8 | $storage = $mount->getStorage(); |
|
1049 | 8 | if (!$storage->instanceOfStorage('OCA\Files_Sharing\SharedStorage')) { |
|
1050 | 1 | return; |
|
1051 | } |
||
1052 | |||
1053 | /** @var \OCA\Files_Sharing\SharedStorage $storage */ |
||
1054 | 7 | $shareOwner = $storage->getSharedFrom(); |
|
1055 | 7 | if ($shareOwner === '' || $shareOwner === null || $shareOwner === $owner || $shareOwner === $currentOwner) { |
|
1056 | 5 | return; |
|
1057 | } |
||
1058 | |||
1059 | 2 | $this->reshareNotificationForSharer($shareOwner, $subject, $shareWith, $fileSource, $itemType); |
|
1060 | 2 | } |
|
1061 | |||
1062 | /** |
||
1063 | * Adds the activity and email for a user when the settings require it |
||
1064 | * |
||
1065 | * @param string $user |
||
1066 | * @param string $subject |
||
1067 | * @param array $subjectParams |
||
1068 | * @param int $fileId |
||
1069 | * @param string $path |
||
1070 | * @param bool $isFile If the item is a file, we link to the parent directory |
||
1071 | * @param bool $streamSetting |
||
1072 | * @param int $emailSetting |
||
1073 | * @param string $type |
||
1074 | */ |
||
1075 | 11 | protected function addNotificationsForUser($user, $subject, $subjectParams, $fileId, $path, $isFile, $streamSetting, $emailSetting, $type = Files_Sharing::TYPE_SHARED) { |
|
1076 | 11 | if (!$streamSetting && !$emailSetting) { |
|
1077 | 1 | return; |
|
1078 | } |
||
1079 | |||
1080 | 10 | $user = (string)$user; |
|
1081 | 10 | $selfAction = $user === $this->currentUser->getUID(); |
|
1082 | 10 | $app = $type === Files_Sharing::TYPE_SHARED ? 'files_sharing' : 'files'; |
|
1083 | 10 | $link = $this->urlGenerator->linkToRouteAbsolute('files.view.index', array( |
|
1084 | 10 | 'dir' => ($isFile) ? dirname($path) : $path, |
|
1085 | )); |
||
1086 | |||
1087 | 10 | $objectType = ($fileId) ? 'files' : ''; |
|
1088 | |||
1089 | 10 | $event = $this->manager->generateEvent(); |
|
1090 | try { |
||
1091 | 10 | $event->setApp($app) |
|
1092 | 10 | ->setType($type) |
|
1093 | 10 | ->setAffectedUser($user) |
|
1094 | 10 | ->setTimestamp(time()) |
|
1095 | 10 | ->setSubject($subject, $subjectParams) |
|
1096 | 10 | ->setObject($objectType, $fileId, $path) |
|
1097 | 10 | ->setLink($link); |
|
1098 | |||
1099 | 10 | if ($this->currentUser->getUID() !== null) { |
|
1100 | // Allow this to be empty for guests |
||
1101 | 10 | $event->setAuthor($this->currentUser->getUID()); |
|
1102 | } |
||
1103 | } catch (\InvalidArgumentException $e) { |
||
1104 | $this->logger->logException($e); |
||
1105 | } |
||
1106 | |||
1107 | // Add activity to stream |
||
1108 | 10 | if ($streamSetting && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser->getUID(), 'setting', 'self'))) { |
|
1109 | 3 | $this->activityData->send($event); |
|
1110 | } |
||
1111 | |||
1112 | // Add activity to mail queue |
||
1113 | 10 | if ($emailSetting !== false && (!$selfAction || $this->userSettings->getUserSetting($this->currentUser->getUID(), 'setting', 'selfemail'))) { |
|
1114 | 5 | $latestSend = time() + $emailSetting; |
|
1115 | 5 | $this->activityData->storeMail($event, $latestSend); |
|
1116 | } |
||
1117 | 10 | } |
|
1118 | } |
||
1119 |
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.