Passed
Push — master ( acbe08...812f16 )
by Roeland
13:17 queued 12s
created
apps/files/lib/Activity/Provider.php 1 patch
Indentation   +462 added lines, -462 removed lines patch added patch discarded remove patch
@@ -41,466 +41,466 @@
 block discarded – undo
41 41
 
42 42
 class Provider implements IProvider {
43 43
 
44
-	/** @var IFactory */
45
-	protected $languageFactory;
46
-
47
-	/** @var IL10N */
48
-	protected $l;
49
-	/** @var IL10N */
50
-	protected $activityLang;
51
-
52
-	/** @var IURLGenerator */
53
-	protected $url;
54
-
55
-	/** @var IManager */
56
-	protected $activityManager;
57
-
58
-	/** @var IUserManager */
59
-	protected $userManager;
60
-
61
-	/** @var IRootFolder */
62
-	protected $rootFolder;
63
-
64
-	/** @var IEventMerger */
65
-	protected $eventMerger;
66
-
67
-	/** @var string[] cached displayNames - key is the UID and value the displayname */
68
-	protected $displayNames = [];
69
-
70
-	protected $fileIsEncrypted = false;
71
-
72
-	/**
73
-	 * @param IFactory $languageFactory
74
-	 * @param IURLGenerator $url
75
-	 * @param IManager $activityManager
76
-	 * @param IUserManager $userManager
77
-	 * @param IRootFolder $rootFolder
78
-	 * @param IEventMerger $eventMerger
79
-	 */
80
-	public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager, IRootFolder $rootFolder, IEventMerger $eventMerger) {
81
-		$this->languageFactory = $languageFactory;
82
-		$this->url = $url;
83
-		$this->activityManager = $activityManager;
84
-		$this->userManager = $userManager;
85
-		$this->rootFolder = $rootFolder;
86
-		$this->eventMerger = $eventMerger;
87
-	}
88
-
89
-	/**
90
-	 * @param string $language
91
-	 * @param IEvent $event
92
-	 * @param IEvent|null $previousEvent
93
-	 * @return IEvent
94
-	 * @throws \InvalidArgumentException
95
-	 * @since 11.0.0
96
-	 */
97
-	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
98
-		if ($event->getApp() !== 'files') {
99
-			throw new \InvalidArgumentException();
100
-		}
101
-
102
-		$this->l = $this->languageFactory->get('files', $language);
103
-		$this->activityLang = $this->languageFactory->get('activity', $language);
104
-
105
-		if ($this->activityManager->isFormattingFilteredObject()) {
106
-			try {
107
-				return $this->parseShortVersion($event, $previousEvent);
108
-			} catch (\InvalidArgumentException $e) {
109
-				// Ignore and simply use the long version...
110
-			}
111
-		}
112
-
113
-		return $this->parseLongVersion($event, $previousEvent);
114
-	}
115
-
116
-	protected function setIcon(IEvent $event, string $icon, string $app = 'files') {
117
-		if ($this->activityManager->getRequirePNG()) {
118
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.png')));
119
-		} else {
120
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.svg')));
121
-		}
122
-	}
123
-
124
-	/**
125
-	 * @param IEvent $event
126
-	 * @param IEvent|null $previousEvent
127
-	 * @return IEvent
128
-	 * @throws \InvalidArgumentException
129
-	 * @since 11.0.0
130
-	 */
131
-	public function parseShortVersion(IEvent $event, IEvent $previousEvent = null) {
132
-		$parsedParameters = $this->getParameters($event);
133
-
134
-		if ($event->getSubject() === 'created_by') {
135
-			$subject = $this->l->t('Created by {user}');
136
-			$this->setIcon($event, 'add-color');
137
-		} else if ($event->getSubject() === 'changed_by') {
138
-			$subject = $this->l->t('Changed by {user}');
139
-			$this->setIcon($event, 'change');
140
-		} else if ($event->getSubject() === 'deleted_by') {
141
-			$subject = $this->l->t('Deleted by {user}');
142
-			$this->setIcon($event, 'delete-color');
143
-		} else if ($event->getSubject() === 'restored_by') {
144
-			$subject = $this->l->t('Restored by {user}');
145
-			$this->setIcon($event, 'actions/history', 'core');
146
-		} else if ($event->getSubject() === 'renamed_by') {
147
-			$subject = $this->l->t('Renamed by {user}');
148
-			$this->setIcon($event, 'change');
149
-		} else if ($event->getSubject() === 'moved_by') {
150
-			$subject = $this->l->t('Moved by {user}');
151
-			$this->setIcon($event, 'change');
152
-		} else {
153
-			throw new \InvalidArgumentException();
154
-		}
155
-
156
-		if (!isset($parsedParameters['user'])) {
157
-			// External user via public link share
158
-			$subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
159
-		}
160
-
161
-		$this->setSubjects($event, $subject, $parsedParameters);
162
-
163
-		return $this->eventMerger->mergeEvents('user', $event, $previousEvent);
164
-	}
165
-
166
-	/**
167
-	 * @param IEvent $event
168
-	 * @param IEvent|null $previousEvent
169
-	 * @return IEvent
170
-	 * @throws \InvalidArgumentException
171
-	 * @since 11.0.0
172
-	 */
173
-	public function parseLongVersion(IEvent $event, IEvent $previousEvent = null) {
174
-		$this->fileIsEncrypted = false;
175
-		$parsedParameters = $this->getParameters($event);
176
-
177
-		if ($event->getSubject() === 'created_self') {
178
-			$subject = $this->l->t('You created {file}');
179
-			if ($this->fileIsEncrypted) {
180
-				$subject = $this->l->t('You created an encrypted file in {file}');
181
-			}
182
-			$this->setIcon($event, 'add-color');
183
-		} else if ($event->getSubject() === 'created_by') {
184
-			$subject = $this->l->t('{user} created {file}');
185
-			if ($this->fileIsEncrypted) {
186
-				$subject = $this->l->t('{user} created an encrypted file in {file}');
187
-			}
188
-			$this->setIcon($event, 'add-color');
189
-		} else if ($event->getSubject() === 'created_public') {
190
-			$subject = $this->l->t('{file} was created in a public folder');
191
-			$this->setIcon($event, 'add-color');
192
-		} else if ($event->getSubject() === 'changed_self') {
193
-			$subject = $this->l->t('You changed {file}');
194
-			if ($this->fileIsEncrypted) {
195
-				$subject = $this->l->t('You changed an encrypted file in {file}');
196
-			}
197
-			$this->setIcon($event, 'change');
198
-		} else if ($event->getSubject() === 'changed_by') {
199
-			$subject = $this->l->t('{user} changed {file}');
200
-			if ($this->fileIsEncrypted) {
201
-				$subject = $this->l->t('{user} changed an encrypted file in {file}');
202
-			}
203
-			$this->setIcon($event, 'change');
204
-		} else if ($event->getSubject() === 'deleted_self') {
205
-			$subject = $this->l->t('You deleted {file}');
206
-			if ($this->fileIsEncrypted) {
207
-				$subject = $this->l->t('You deleted an encrypted file in {file}');
208
-			}
209
-			$this->setIcon($event, 'delete-color');
210
-		} else if ($event->getSubject() === 'deleted_by') {
211
-			$subject = $this->l->t('{user} deleted {file}');
212
-			if ($this->fileIsEncrypted) {
213
-				$subject = $this->l->t('{user} deleted an encrypted file in {file}');
214
-			}
215
-			$this->setIcon($event, 'delete-color');
216
-		} else if ($event->getSubject() === 'restored_self') {
217
-			$subject = $this->l->t('You restored {file}');
218
-			$this->setIcon($event, 'actions/history', 'core');
219
-		} else if ($event->getSubject() === 'restored_by') {
220
-			$subject = $this->l->t('{user} restored {file}');
221
-			$this->setIcon($event, 'actions/history', 'core');
222
-		} else if ($event->getSubject() === 'renamed_self') {
223
-			$subject = $this->l->t('You renamed {oldfile} to {newfile}');
224
-			$this->setIcon($event, 'change');
225
-		} else if ($event->getSubject() === 'renamed_by') {
226
-			$subject = $this->l->t('{user} renamed {oldfile} to {newfile}');
227
-			$this->setIcon($event, 'change');
228
-		} else if ($event->getSubject() === 'moved_self') {
229
-			$subject = $this->l->t('You moved {oldfile} to {newfile}');
230
-			$this->setIcon($event, 'change');
231
-		} else if ($event->getSubject() === 'moved_by') {
232
-			$subject = $this->l->t('{user} moved {oldfile} to {newfile}');
233
-			$this->setIcon($event, 'change');
234
-		} else {
235
-			throw new \InvalidArgumentException();
236
-		}
237
-
238
-		if ($this->fileIsEncrypted) {
239
-			$event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
240
-		}
241
-
242
-		if (!isset($parsedParameters['user'])) {
243
-			// External user via public link share
244
-			$subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
245
-		}
246
-
247
-		$this->setSubjects($event, $subject, $parsedParameters);
248
-
249
-		if ($event->getSubject() === 'moved_self' || $event->getSubject() === 'moved_by') {
250
-			$event = $this->eventMerger->mergeEvents('oldfile', $event, $previousEvent);
251
-		} else {
252
-			$event = $this->eventMerger->mergeEvents('file', $event, $previousEvent);
253
-		}
254
-
255
-		if ($event->getChildEvent() === null) {
256
-			// Couldn't group by file, maybe we can group by user
257
-			$event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
258
-		}
259
-
260
-		return $event;
261
-	}
262
-
263
-	protected function setSubjects(IEvent $event, $subject, array $parameters) {
264
-		$placeholders = $replacements = [];
265
-		foreach ($parameters as $placeholder => $parameter) {
266
-			$placeholders[] = '{' . $placeholder . '}';
267
-			if ($parameter['type'] === 'file') {
268
-				$replacements[] = $parameter['path'];
269
-			} else {
270
-				$replacements[] = $parameter['name'];
271
-			}
272
-		}
273
-
274
-		$event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
275
-			->setRichSubject($subject, $parameters);
276
-	}
277
-
278
-	/**
279
-	 * @param IEvent $event
280
-	 * @return array
281
-	 * @throws \InvalidArgumentException
282
-	 */
283
-	protected function getParameters(IEvent $event) {
284
-		$parameters = $event->getSubjectParameters();
285
-		switch ($event->getSubject()) {
286
-			case 'created_self':
287
-			case 'created_public':
288
-			case 'changed_self':
289
-			case 'deleted_self':
290
-			case 'restored_self':
291
-				return [
292
-					'file' => $this->getFile($parameters[0], $event),
293
-				];
294
-			case 'created_by':
295
-			case 'changed_by':
296
-			case 'deleted_by':
297
-			case 'restored_by':
298
-				if ($parameters[1] === '') {
299
-					// External user via public link share
300
-					return [
301
-						'file' => $this->getFile($parameters[0], $event),
302
-					];
303
-				}
304
-				return [
305
-					'file' => $this->getFile($parameters[0], $event),
306
-					'user' => $this->getUser($parameters[1]),
307
-				];
308
-			case 'renamed_self':
309
-			case 'moved_self':
310
-				return [
311
-					'newfile' => $this->getFile($parameters[0]),
312
-					'oldfile' => $this->getFile($parameters[1]),
313
-				];
314
-			case 'renamed_by':
315
-			case 'moved_by':
316
-				if ($parameters[1] === '') {
317
-					// External user via public link share
318
-					return [
319
-						'newfile' => $this->getFile($parameters[0]),
320
-						'oldfile' => $this->getFile($parameters[2]),
321
-					];
322
-				}
323
-				return [
324
-					'newfile' => $this->getFile($parameters[0]),
325
-					'user' => $this->getUser($parameters[1]),
326
-					'oldfile' => $this->getFile($parameters[2]),
327
-				];
328
-		}
329
-		return [];
330
-	}
331
-
332
-	/**
333
-	 * @param array|string $parameter
334
-	 * @param IEvent|null $event
335
-	 * @return array
336
-	 * @throws \InvalidArgumentException
337
-	 */
338
-	protected function getFile($parameter, IEvent $event = null) {
339
-		if (is_array($parameter)) {
340
-			$path = reset($parameter);
341
-			$id = (string) key($parameter);
342
-		} else if ($event !== null) {
343
-			// Legacy from before ownCloud 8.2
344
-			$path = $parameter;
345
-			$id = $event->getObjectId();
346
-		} else {
347
-			throw new \InvalidArgumentException('Could not generate file parameter');
348
-		}
349
-
350
-		$encryptionContainer = $this->getEndToEndEncryptionContainer($id, $path);
351
-		if ($encryptionContainer instanceof Folder) {
352
-			$this->fileIsEncrypted = true;
353
-			try {
354
-				$fullPath = rtrim($encryptionContainer->getPath(), '/');
355
-				// Remove /user/files/...
356
-				list(,,, $path) = explode('/', $fullPath, 4);
357
-				if (!$path) {
358
-					throw new InvalidPathException('Path could not be split correctly');
359
-				}
360
-
361
-				return [
362
-					'type' => 'file',
363
-					'id' => $encryptionContainer->getId(),
364
-					'name' => $encryptionContainer->getName(),
365
-					'path' => $path,
366
-					'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $encryptionContainer->getId()]),
367
-				];
368
-			} catch (\Exception $e) {
369
-				// fall back to the normal one
370
-				$this->fileIsEncrypted = false;
371
-			}
372
-		}
373
-
374
-		return [
375
-			'type' => 'file',
376
-			'id' => $id,
377
-			'name' => basename($path),
378
-			'path' => trim($path, '/'),
379
-			'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $id]),
380
-		];
381
-	}
382
-
383
-	protected $fileEncrypted = [];
384
-
385
-	/**
386
-	 * Check if a file is end2end encrypted
387
-	 * @param int $fileId
388
-	 * @param string $path
389
-	 * @return Folder|null
390
-	 */
391
-	protected function getEndToEndEncryptionContainer($fileId, $path) {
392
-		if (isset($this->fileEncrypted[$fileId])) {
393
-			return $this->fileEncrypted[$fileId];
394
-		}
395
-
396
-		$fileName = basename($path);
397
-		if (!preg_match('/^[0-9a-fA-F]{32}$/', $fileName)) {
398
-			$this->fileEncrypted[$fileId] = false;
399
-			return $this->fileEncrypted[$fileId];
400
-		}
401
-
402
-		$userFolder = $this->rootFolder->getUserFolder($this->activityManager->getCurrentUserId());
403
-		$files = $userFolder->getById($fileId);
404
-		if (empty($files)) {
405
-			try {
406
-				// Deleted, try with parent
407
-				$file = $this->findExistingParent($userFolder, dirname($path));
408
-			} catch (NotFoundException $e) {
409
-				return null;
410
-			}
411
-
412
-			if (!$file instanceof Folder || !$file->isEncrypted()) {
413
-				return null;
414
-			}
415
-
416
-			$this->fileEncrypted[$fileId] = $file;
417
-			return $file;
418
-		}
419
-
420
-		$file = array_shift($files);
421
-
422
-		if ($file instanceof Folder && $file->isEncrypted()) {
423
-			// If the folder is encrypted, it is the Container,
424
-			// but can be the name is just fine.
425
-			$this->fileEncrypted[$fileId] = true;
426
-			return null;
427
-		}
428
-
429
-		$this->fileEncrypted[$fileId] = $this->getParentEndToEndEncryptionContainer($userFolder, $file);
430
-		return $this->fileEncrypted[$fileId];
431
-	}
432
-
433
-	/**
434
-	 * @param Folder $userFolder
435
-	 * @param string $path
436
-	 * @return Folder
437
-	 * @throws NotFoundException
438
-	 */
439
-	protected function findExistingParent(Folder $userFolder, $path) {
440
-		if ($path === '/') {
441
-			throw new NotFoundException('Reached the root');
442
-		}
443
-
444
-		try {
445
-			$folder = $userFolder->get(dirname($path));
446
-		} catch (NotFoundException $e) {
447
-			return $this->findExistingParent($userFolder, dirname($path));
448
-		}
449
-
450
-		return $folder;
451
-	}
452
-
453
-	/**
454
-	 * Check all parents until the user's root folder if one is encrypted
455
-	 *
456
-	 * @param Folder $userFolder
457
-	 * @param Node $file
458
-	 * @return Node|null
459
-	 */
460
-	protected function getParentEndToEndEncryptionContainer(Folder $userFolder, Node $file) {
461
-		try {
462
-			$parent = $file->getParent();
463
-
464
-			if ($userFolder->getId() === $parent->getId()) {
465
-				return null;
466
-			}
467
-		} catch (\Exception $e) {
468
-			return null;
469
-		}
470
-
471
-		if ($parent->isEncrypted()) {
472
-			return $parent;
473
-		}
474
-
475
-		return $this->getParentEndToEndEncryptionContainer($userFolder, $parent);
476
-	}
477
-
478
-	/**
479
-	 * @param string $uid
480
-	 * @return array
481
-	 */
482
-	protected function getUser($uid) {
483
-		if (!isset($this->displayNames[$uid])) {
484
-			$this->displayNames[$uid] = $this->getDisplayName($uid);
485
-		}
486
-
487
-		return [
488
-			'type' => 'user',
489
-			'id' => $uid,
490
-			'name' => $this->displayNames[$uid],
491
-		];
492
-	}
493
-
494
-	/**
495
-	 * @param string $uid
496
-	 * @return string
497
-	 */
498
-	protected function getDisplayName($uid) {
499
-		$user = $this->userManager->get($uid);
500
-		if ($user instanceof IUser) {
501
-			return $user->getDisplayName();
502
-		} else {
503
-			return $uid;
504
-		}
505
-	}
44
+    /** @var IFactory */
45
+    protected $languageFactory;
46
+
47
+    /** @var IL10N */
48
+    protected $l;
49
+    /** @var IL10N */
50
+    protected $activityLang;
51
+
52
+    /** @var IURLGenerator */
53
+    protected $url;
54
+
55
+    /** @var IManager */
56
+    protected $activityManager;
57
+
58
+    /** @var IUserManager */
59
+    protected $userManager;
60
+
61
+    /** @var IRootFolder */
62
+    protected $rootFolder;
63
+
64
+    /** @var IEventMerger */
65
+    protected $eventMerger;
66
+
67
+    /** @var string[] cached displayNames - key is the UID and value the displayname */
68
+    protected $displayNames = [];
69
+
70
+    protected $fileIsEncrypted = false;
71
+
72
+    /**
73
+     * @param IFactory $languageFactory
74
+     * @param IURLGenerator $url
75
+     * @param IManager $activityManager
76
+     * @param IUserManager $userManager
77
+     * @param IRootFolder $rootFolder
78
+     * @param IEventMerger $eventMerger
79
+     */
80
+    public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager, IRootFolder $rootFolder, IEventMerger $eventMerger) {
81
+        $this->languageFactory = $languageFactory;
82
+        $this->url = $url;
83
+        $this->activityManager = $activityManager;
84
+        $this->userManager = $userManager;
85
+        $this->rootFolder = $rootFolder;
86
+        $this->eventMerger = $eventMerger;
87
+    }
88
+
89
+    /**
90
+     * @param string $language
91
+     * @param IEvent $event
92
+     * @param IEvent|null $previousEvent
93
+     * @return IEvent
94
+     * @throws \InvalidArgumentException
95
+     * @since 11.0.0
96
+     */
97
+    public function parse($language, IEvent $event, IEvent $previousEvent = null) {
98
+        if ($event->getApp() !== 'files') {
99
+            throw new \InvalidArgumentException();
100
+        }
101
+
102
+        $this->l = $this->languageFactory->get('files', $language);
103
+        $this->activityLang = $this->languageFactory->get('activity', $language);
104
+
105
+        if ($this->activityManager->isFormattingFilteredObject()) {
106
+            try {
107
+                return $this->parseShortVersion($event, $previousEvent);
108
+            } catch (\InvalidArgumentException $e) {
109
+                // Ignore and simply use the long version...
110
+            }
111
+        }
112
+
113
+        return $this->parseLongVersion($event, $previousEvent);
114
+    }
115
+
116
+    protected function setIcon(IEvent $event, string $icon, string $app = 'files') {
117
+        if ($this->activityManager->getRequirePNG()) {
118
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.png')));
119
+        } else {
120
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.svg')));
121
+        }
122
+    }
123
+
124
+    /**
125
+     * @param IEvent $event
126
+     * @param IEvent|null $previousEvent
127
+     * @return IEvent
128
+     * @throws \InvalidArgumentException
129
+     * @since 11.0.0
130
+     */
131
+    public function parseShortVersion(IEvent $event, IEvent $previousEvent = null) {
132
+        $parsedParameters = $this->getParameters($event);
133
+
134
+        if ($event->getSubject() === 'created_by') {
135
+            $subject = $this->l->t('Created by {user}');
136
+            $this->setIcon($event, 'add-color');
137
+        } else if ($event->getSubject() === 'changed_by') {
138
+            $subject = $this->l->t('Changed by {user}');
139
+            $this->setIcon($event, 'change');
140
+        } else if ($event->getSubject() === 'deleted_by') {
141
+            $subject = $this->l->t('Deleted by {user}');
142
+            $this->setIcon($event, 'delete-color');
143
+        } else if ($event->getSubject() === 'restored_by') {
144
+            $subject = $this->l->t('Restored by {user}');
145
+            $this->setIcon($event, 'actions/history', 'core');
146
+        } else if ($event->getSubject() === 'renamed_by') {
147
+            $subject = $this->l->t('Renamed by {user}');
148
+            $this->setIcon($event, 'change');
149
+        } else if ($event->getSubject() === 'moved_by') {
150
+            $subject = $this->l->t('Moved by {user}');
151
+            $this->setIcon($event, 'change');
152
+        } else {
153
+            throw new \InvalidArgumentException();
154
+        }
155
+
156
+        if (!isset($parsedParameters['user'])) {
157
+            // External user via public link share
158
+            $subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
159
+        }
160
+
161
+        $this->setSubjects($event, $subject, $parsedParameters);
162
+
163
+        return $this->eventMerger->mergeEvents('user', $event, $previousEvent);
164
+    }
165
+
166
+    /**
167
+     * @param IEvent $event
168
+     * @param IEvent|null $previousEvent
169
+     * @return IEvent
170
+     * @throws \InvalidArgumentException
171
+     * @since 11.0.0
172
+     */
173
+    public function parseLongVersion(IEvent $event, IEvent $previousEvent = null) {
174
+        $this->fileIsEncrypted = false;
175
+        $parsedParameters = $this->getParameters($event);
176
+
177
+        if ($event->getSubject() === 'created_self') {
178
+            $subject = $this->l->t('You created {file}');
179
+            if ($this->fileIsEncrypted) {
180
+                $subject = $this->l->t('You created an encrypted file in {file}');
181
+            }
182
+            $this->setIcon($event, 'add-color');
183
+        } else if ($event->getSubject() === 'created_by') {
184
+            $subject = $this->l->t('{user} created {file}');
185
+            if ($this->fileIsEncrypted) {
186
+                $subject = $this->l->t('{user} created an encrypted file in {file}');
187
+            }
188
+            $this->setIcon($event, 'add-color');
189
+        } else if ($event->getSubject() === 'created_public') {
190
+            $subject = $this->l->t('{file} was created in a public folder');
191
+            $this->setIcon($event, 'add-color');
192
+        } else if ($event->getSubject() === 'changed_self') {
193
+            $subject = $this->l->t('You changed {file}');
194
+            if ($this->fileIsEncrypted) {
195
+                $subject = $this->l->t('You changed an encrypted file in {file}');
196
+            }
197
+            $this->setIcon($event, 'change');
198
+        } else if ($event->getSubject() === 'changed_by') {
199
+            $subject = $this->l->t('{user} changed {file}');
200
+            if ($this->fileIsEncrypted) {
201
+                $subject = $this->l->t('{user} changed an encrypted file in {file}');
202
+            }
203
+            $this->setIcon($event, 'change');
204
+        } else if ($event->getSubject() === 'deleted_self') {
205
+            $subject = $this->l->t('You deleted {file}');
206
+            if ($this->fileIsEncrypted) {
207
+                $subject = $this->l->t('You deleted an encrypted file in {file}');
208
+            }
209
+            $this->setIcon($event, 'delete-color');
210
+        } else if ($event->getSubject() === 'deleted_by') {
211
+            $subject = $this->l->t('{user} deleted {file}');
212
+            if ($this->fileIsEncrypted) {
213
+                $subject = $this->l->t('{user} deleted an encrypted file in {file}');
214
+            }
215
+            $this->setIcon($event, 'delete-color');
216
+        } else if ($event->getSubject() === 'restored_self') {
217
+            $subject = $this->l->t('You restored {file}');
218
+            $this->setIcon($event, 'actions/history', 'core');
219
+        } else if ($event->getSubject() === 'restored_by') {
220
+            $subject = $this->l->t('{user} restored {file}');
221
+            $this->setIcon($event, 'actions/history', 'core');
222
+        } else if ($event->getSubject() === 'renamed_self') {
223
+            $subject = $this->l->t('You renamed {oldfile} to {newfile}');
224
+            $this->setIcon($event, 'change');
225
+        } else if ($event->getSubject() === 'renamed_by') {
226
+            $subject = $this->l->t('{user} renamed {oldfile} to {newfile}');
227
+            $this->setIcon($event, 'change');
228
+        } else if ($event->getSubject() === 'moved_self') {
229
+            $subject = $this->l->t('You moved {oldfile} to {newfile}');
230
+            $this->setIcon($event, 'change');
231
+        } else if ($event->getSubject() === 'moved_by') {
232
+            $subject = $this->l->t('{user} moved {oldfile} to {newfile}');
233
+            $this->setIcon($event, 'change');
234
+        } else {
235
+            throw new \InvalidArgumentException();
236
+        }
237
+
238
+        if ($this->fileIsEncrypted) {
239
+            $event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
240
+        }
241
+
242
+        if (!isset($parsedParameters['user'])) {
243
+            // External user via public link share
244
+            $subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
245
+        }
246
+
247
+        $this->setSubjects($event, $subject, $parsedParameters);
248
+
249
+        if ($event->getSubject() === 'moved_self' || $event->getSubject() === 'moved_by') {
250
+            $event = $this->eventMerger->mergeEvents('oldfile', $event, $previousEvent);
251
+        } else {
252
+            $event = $this->eventMerger->mergeEvents('file', $event, $previousEvent);
253
+        }
254
+
255
+        if ($event->getChildEvent() === null) {
256
+            // Couldn't group by file, maybe we can group by user
257
+            $event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
258
+        }
259
+
260
+        return $event;
261
+    }
262
+
263
+    protected function setSubjects(IEvent $event, $subject, array $parameters) {
264
+        $placeholders = $replacements = [];
265
+        foreach ($parameters as $placeholder => $parameter) {
266
+            $placeholders[] = '{' . $placeholder . '}';
267
+            if ($parameter['type'] === 'file') {
268
+                $replacements[] = $parameter['path'];
269
+            } else {
270
+                $replacements[] = $parameter['name'];
271
+            }
272
+        }
273
+
274
+        $event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
275
+            ->setRichSubject($subject, $parameters);
276
+    }
277
+
278
+    /**
279
+     * @param IEvent $event
280
+     * @return array
281
+     * @throws \InvalidArgumentException
282
+     */
283
+    protected function getParameters(IEvent $event) {
284
+        $parameters = $event->getSubjectParameters();
285
+        switch ($event->getSubject()) {
286
+            case 'created_self':
287
+            case 'created_public':
288
+            case 'changed_self':
289
+            case 'deleted_self':
290
+            case 'restored_self':
291
+                return [
292
+                    'file' => $this->getFile($parameters[0], $event),
293
+                ];
294
+            case 'created_by':
295
+            case 'changed_by':
296
+            case 'deleted_by':
297
+            case 'restored_by':
298
+                if ($parameters[1] === '') {
299
+                    // External user via public link share
300
+                    return [
301
+                        'file' => $this->getFile($parameters[0], $event),
302
+                    ];
303
+                }
304
+                return [
305
+                    'file' => $this->getFile($parameters[0], $event),
306
+                    'user' => $this->getUser($parameters[1]),
307
+                ];
308
+            case 'renamed_self':
309
+            case 'moved_self':
310
+                return [
311
+                    'newfile' => $this->getFile($parameters[0]),
312
+                    'oldfile' => $this->getFile($parameters[1]),
313
+                ];
314
+            case 'renamed_by':
315
+            case 'moved_by':
316
+                if ($parameters[1] === '') {
317
+                    // External user via public link share
318
+                    return [
319
+                        'newfile' => $this->getFile($parameters[0]),
320
+                        'oldfile' => $this->getFile($parameters[2]),
321
+                    ];
322
+                }
323
+                return [
324
+                    'newfile' => $this->getFile($parameters[0]),
325
+                    'user' => $this->getUser($parameters[1]),
326
+                    'oldfile' => $this->getFile($parameters[2]),
327
+                ];
328
+        }
329
+        return [];
330
+    }
331
+
332
+    /**
333
+     * @param array|string $parameter
334
+     * @param IEvent|null $event
335
+     * @return array
336
+     * @throws \InvalidArgumentException
337
+     */
338
+    protected function getFile($parameter, IEvent $event = null) {
339
+        if (is_array($parameter)) {
340
+            $path = reset($parameter);
341
+            $id = (string) key($parameter);
342
+        } else if ($event !== null) {
343
+            // Legacy from before ownCloud 8.2
344
+            $path = $parameter;
345
+            $id = $event->getObjectId();
346
+        } else {
347
+            throw new \InvalidArgumentException('Could not generate file parameter');
348
+        }
349
+
350
+        $encryptionContainer = $this->getEndToEndEncryptionContainer($id, $path);
351
+        if ($encryptionContainer instanceof Folder) {
352
+            $this->fileIsEncrypted = true;
353
+            try {
354
+                $fullPath = rtrim($encryptionContainer->getPath(), '/');
355
+                // Remove /user/files/...
356
+                list(,,, $path) = explode('/', $fullPath, 4);
357
+                if (!$path) {
358
+                    throw new InvalidPathException('Path could not be split correctly');
359
+                }
360
+
361
+                return [
362
+                    'type' => 'file',
363
+                    'id' => $encryptionContainer->getId(),
364
+                    'name' => $encryptionContainer->getName(),
365
+                    'path' => $path,
366
+                    'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $encryptionContainer->getId()]),
367
+                ];
368
+            } catch (\Exception $e) {
369
+                // fall back to the normal one
370
+                $this->fileIsEncrypted = false;
371
+            }
372
+        }
373
+
374
+        return [
375
+            'type' => 'file',
376
+            'id' => $id,
377
+            'name' => basename($path),
378
+            'path' => trim($path, '/'),
379
+            'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $id]),
380
+        ];
381
+    }
382
+
383
+    protected $fileEncrypted = [];
384
+
385
+    /**
386
+     * Check if a file is end2end encrypted
387
+     * @param int $fileId
388
+     * @param string $path
389
+     * @return Folder|null
390
+     */
391
+    protected function getEndToEndEncryptionContainer($fileId, $path) {
392
+        if (isset($this->fileEncrypted[$fileId])) {
393
+            return $this->fileEncrypted[$fileId];
394
+        }
395
+
396
+        $fileName = basename($path);
397
+        if (!preg_match('/^[0-9a-fA-F]{32}$/', $fileName)) {
398
+            $this->fileEncrypted[$fileId] = false;
399
+            return $this->fileEncrypted[$fileId];
400
+        }
401
+
402
+        $userFolder = $this->rootFolder->getUserFolder($this->activityManager->getCurrentUserId());
403
+        $files = $userFolder->getById($fileId);
404
+        if (empty($files)) {
405
+            try {
406
+                // Deleted, try with parent
407
+                $file = $this->findExistingParent($userFolder, dirname($path));
408
+            } catch (NotFoundException $e) {
409
+                return null;
410
+            }
411
+
412
+            if (!$file instanceof Folder || !$file->isEncrypted()) {
413
+                return null;
414
+            }
415
+
416
+            $this->fileEncrypted[$fileId] = $file;
417
+            return $file;
418
+        }
419
+
420
+        $file = array_shift($files);
421
+
422
+        if ($file instanceof Folder && $file->isEncrypted()) {
423
+            // If the folder is encrypted, it is the Container,
424
+            // but can be the name is just fine.
425
+            $this->fileEncrypted[$fileId] = true;
426
+            return null;
427
+        }
428
+
429
+        $this->fileEncrypted[$fileId] = $this->getParentEndToEndEncryptionContainer($userFolder, $file);
430
+        return $this->fileEncrypted[$fileId];
431
+    }
432
+
433
+    /**
434
+     * @param Folder $userFolder
435
+     * @param string $path
436
+     * @return Folder
437
+     * @throws NotFoundException
438
+     */
439
+    protected function findExistingParent(Folder $userFolder, $path) {
440
+        if ($path === '/') {
441
+            throw new NotFoundException('Reached the root');
442
+        }
443
+
444
+        try {
445
+            $folder = $userFolder->get(dirname($path));
446
+        } catch (NotFoundException $e) {
447
+            return $this->findExistingParent($userFolder, dirname($path));
448
+        }
449
+
450
+        return $folder;
451
+    }
452
+
453
+    /**
454
+     * Check all parents until the user's root folder if one is encrypted
455
+     *
456
+     * @param Folder $userFolder
457
+     * @param Node $file
458
+     * @return Node|null
459
+     */
460
+    protected function getParentEndToEndEncryptionContainer(Folder $userFolder, Node $file) {
461
+        try {
462
+            $parent = $file->getParent();
463
+
464
+            if ($userFolder->getId() === $parent->getId()) {
465
+                return null;
466
+            }
467
+        } catch (\Exception $e) {
468
+            return null;
469
+        }
470
+
471
+        if ($parent->isEncrypted()) {
472
+            return $parent;
473
+        }
474
+
475
+        return $this->getParentEndToEndEncryptionContainer($userFolder, $parent);
476
+    }
477
+
478
+    /**
479
+     * @param string $uid
480
+     * @return array
481
+     */
482
+    protected function getUser($uid) {
483
+        if (!isset($this->displayNames[$uid])) {
484
+            $this->displayNames[$uid] = $this->getDisplayName($uid);
485
+        }
486
+
487
+        return [
488
+            'type' => 'user',
489
+            'id' => $uid,
490
+            'name' => $this->displayNames[$uid],
491
+        ];
492
+    }
493
+
494
+    /**
495
+     * @param string $uid
496
+     * @return string
497
+     */
498
+    protected function getDisplayName($uid) {
499
+        $user = $this->userManager->get($uid);
500
+        if ($user instanceof IUser) {
501
+            return $user->getDisplayName();
502
+        } else {
503
+            return $uid;
504
+        }
505
+    }
506 506
 }
Please login to merge, or discard this patch.