Completed
Pull Request — master (#8298)
by Joas
17:42
created
apps/files/lib/Activity/Provider.php 4 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -112,6 +112,9 @@  discard block
 block discarded – undo
112 112
 		return $this->parseLongVersion($event, $previousEvent);
113 113
 	}
114 114
 
115
+	/**
116
+	 * @param string $icon
117
+	 */
115 118
 	protected function setIcon(IEvent $event, $icon) {
116 119
 		if ($this->activityManager->getRequirePNG()) {
117 120
 			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon . '.png')));
@@ -252,6 +255,9 @@  discard block
 block discarded – undo
252 255
 		return $event;
253 256
 	}
254 257
 
258
+	/**
259
+	 * @param string $subject
260
+	 */
255 261
 	protected function setSubjects(IEvent $event, $subject, array $parameters) {
256 262
 		$placeholders = $replacements = [];
257 263
 		foreach ($parameters as $placeholder => $parameter) {
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -114,9 +114,9 @@  discard block
 block discarded – undo
114 114
 
115 115
 	protected function setIcon(IEvent $event, $icon) {
116 116
 		if ($this->activityManager->getRequirePNG()) {
117
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon . '.png')));
117
+			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon.'.png')));
118 118
 		} else {
119
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon . '.svg')));
119
+			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon.'.svg')));
120 120
 		}
121 121
 	}
122 122
 
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
 		}
233 233
 
234 234
 		if ($this->fileIsEncrypted) {
235
-			$event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
235
+			$event->setSubject($event->getSubject().'_enc', $event->getSubjectParameters());
236 236
 		}
237 237
 
238 238
 		if (!isset($parsedParameters['user'])) {
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
 	protected function setSubjects(IEvent $event, $subject, array $parameters) {
256 256
 		$placeholders = $replacements = [];
257 257
 		foreach ($parameters as $placeholder => $parameter) {
258
-			$placeholders[] = '{' . $placeholder . '}';
258
+			$placeholders[] = '{'.$placeholder.'}';
259 259
 			if ($parameter['type'] === 'file') {
260 260
 				$replacements[] = $parameter['path'];
261 261
 			} else {
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -32,7 +32,6 @@
 block discarded – undo
32 32
 use OCP\Files\InvalidPathException;
33 33
 use OCP\Files\IRootFolder;
34 34
 use OCP\Files\Node;
35
-use OCP\Files\NotFoundException;
36 35
 use OCP\IL10N;
37 36
 use OCP\IURLGenerator;
38 37
 use OCP\IUser;
Please login to merge, or discard this patch.
Indentation   +430 added lines, -430 removed lines patch added patch discarded remove patch
@@ -41,434 +41,434 @@
 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, $icon) {
117
-		if ($this->activityManager->getRequirePNG()) {
118
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon . '.png')));
119
-		} else {
120
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $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
-		} else if ($event->getSubject() === 'renamed_by') {
146
-			$subject = $this->l->t('Renamed by {user}');
147
-			$this->setIcon($event, 'change');
148
-		} else if ($event->getSubject() === 'moved_by') {
149
-			$subject = $this->l->t('Moved by {user}');
150
-			$this->setIcon($event, 'change');
151
-		} else {
152
-			throw new \InvalidArgumentException();
153
-		}
154
-
155
-		if (!isset($parsedParameters['user'])) {
156
-			// External user via public link share
157
-			$subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
158
-		}
159
-
160
-		$this->setSubjects($event, $subject, $parsedParameters);
161
-
162
-		return $this->eventMerger->mergeEvents('user', $event, $previousEvent);
163
-	}
164
-
165
-	/**
166
-	 * @param IEvent $event
167
-	 * @param IEvent|null $previousEvent
168
-	 * @return IEvent
169
-	 * @throws \InvalidArgumentException
170
-	 * @since 11.0.0
171
-	 */
172
-	public function parseLongVersion(IEvent $event, IEvent $previousEvent = null) {
173
-		$this->fileIsEncrypted = false;
174
-		$parsedParameters = $this->getParameters($event);
175
-
176
-		if ($event->getSubject() === 'created_self') {
177
-			$subject = $this->l->t('You created {file}');
178
-			if ($this->fileIsEncrypted) {
179
-				$subject = $this->l->t('You created an encrypted file in {file}');
180
-			}
181
-			$this->setIcon($event, 'add-color');
182
-		} else if ($event->getSubject() === 'created_by') {
183
-			$subject = $this->l->t('{user} created {file}');
184
-			if ($this->fileIsEncrypted) {
185
-				$subject = $this->l->t('{user} created an encrypted file in {file}');
186
-			}
187
-			$this->setIcon($event, 'add-color');
188
-		} else if ($event->getSubject() === 'created_public') {
189
-			$subject = $this->l->t('{file} was created in a public folder');
190
-			$this->setIcon($event, 'add-color');
191
-		} else if ($event->getSubject() === 'changed_self') {
192
-			$subject = $this->l->t('You changed {file}');
193
-			if ($this->fileIsEncrypted) {
194
-				$subject = $this->l->t('You changed an encrypted file in {file}');
195
-			}
196
-			$this->setIcon($event, 'change');
197
-		} else if ($event->getSubject() === 'changed_by') {
198
-			$subject = $this->l->t('{user} changed {file}');
199
-			if ($this->fileIsEncrypted) {
200
-				$subject = $this->l->t('{user} changed an encrypted file in {file}');
201
-			}
202
-			$this->setIcon($event, 'change');
203
-		} else if ($event->getSubject() === 'deleted_self') {
204
-			$subject = $this->l->t('You deleted {file}');
205
-			if ($this->fileIsEncrypted) {
206
-				$subject = $this->l->t('You deleted an encrypted file in {file}');
207
-			}
208
-			$this->setIcon($event, 'delete-color');
209
-		} else if ($event->getSubject() === 'deleted_by') {
210
-			$subject = $this->l->t('{user} deleted {file}');
211
-			if ($this->fileIsEncrypted) {
212
-				$subject = $this->l->t('{user} deleted an encrypted file in {file}');
213
-			}
214
-			$this->setIcon($event, 'delete-color');
215
-		} else if ($event->getSubject() === 'restored_self') {
216
-			$subject = $this->l->t('You restored {file}');
217
-		} else if ($event->getSubject() === 'restored_by') {
218
-			$subject = $this->l->t('{user} restored {file}');
219
-		} else if ($event->getSubject() === 'renamed_self') {
220
-			$subject = $this->l->t('You renamed {oldfile} to {newfile}');
221
-			$this->setIcon($event, 'change');
222
-		} else if ($event->getSubject() === 'renamed_by') {
223
-			$subject = $this->l->t('{user} renamed {oldfile} to {newfile}');
224
-			$this->setIcon($event, 'change');
225
-		} else if ($event->getSubject() === 'moved_self') {
226
-			$subject = $this->l->t('You moved {oldfile} to {newfile}');
227
-			$this->setIcon($event, 'change');
228
-		} else if ($event->getSubject() === 'moved_by') {
229
-			$subject = $this->l->t('{user} moved {oldfile} to {newfile}');
230
-			$this->setIcon($event, 'change');
231
-		} else {
232
-			throw new \InvalidArgumentException();
233
-		}
234
-
235
-		if ($this->fileIsEncrypted) {
236
-			$event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
237
-		}
238
-
239
-		if (!isset($parsedParameters['user'])) {
240
-			// External user via public link share
241
-			$subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
242
-		}
243
-
244
-		$this->setSubjects($event, $subject, $parsedParameters);
245
-
246
-		$event = $this->eventMerger->mergeEvents('file', $event, $previousEvent);
247
-
248
-		if ($event->getChildEvent() === null) {
249
-			// Couldn't group by file, maybe we can group by user
250
-			$event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
251
-		}
252
-
253
-		return $event;
254
-	}
255
-
256
-	protected function setSubjects(IEvent $event, $subject, array $parameters) {
257
-		$placeholders = $replacements = [];
258
-		foreach ($parameters as $placeholder => $parameter) {
259
-			$placeholders[] = '{' . $placeholder . '}';
260
-			if ($parameter['type'] === 'file') {
261
-				$replacements[] = $parameter['path'];
262
-			} else {
263
-				$replacements[] = $parameter['name'];
264
-			}
265
-		}
266
-
267
-		$event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
268
-			->setRichSubject($subject, $parameters);
269
-	}
270
-
271
-	/**
272
-	 * @param IEvent $event
273
-	 * @return array
274
-	 * @throws \InvalidArgumentException
275
-	 */
276
-	protected function getParameters(IEvent $event) {
277
-		$parameters = $event->getSubjectParameters();
278
-		switch ($event->getSubject()) {
279
-			case 'created_self':
280
-			case 'created_public':
281
-			case 'changed_self':
282
-			case 'deleted_self':
283
-			case 'restored_self':
284
-				return [
285
-					'file' => $this->getFile($parameters[0], $event),
286
-				];
287
-			case 'created_by':
288
-			case 'changed_by':
289
-			case 'deleted_by':
290
-			case 'restored_by':
291
-				if ($parameters[1] === '') {
292
-					// External user via public link share
293
-					return [
294
-						'file' => $this->getFile($parameters[0], $event),
295
-					];
296
-				}
297
-				return [
298
-					'file' => $this->getFile($parameters[0], $event),
299
-					'user' => $this->getUser($parameters[1]),
300
-				];
301
-			case 'renamed_self':
302
-			case 'moved_self':
303
-				return [
304
-					'newfile' => $this->getFile($parameters[0]),
305
-					'oldfile' => $this->getFile($parameters[1]),
306
-				];
307
-			case 'renamed_by':
308
-			case 'moved_by':
309
-				if ($parameters[1] === '') {
310
-					// External user via public link share
311
-					return [
312
-						'newfile' => $this->getFile($parameters[0]),
313
-						'oldfile' => $this->getFile($parameters[2]),
314
-					];
315
-				}
316
-				return [
317
-					'newfile' => $this->getFile($parameters[0]),
318
-					'user' => $this->getUser($parameters[1]),
319
-					'oldfile' => $this->getFile($parameters[2]),
320
-				];
321
-		}
322
-		return [];
323
-	}
324
-
325
-	/**
326
-	 * @param array|string $parameter
327
-	 * @param IEvent|null $event
328
-	 * @return array
329
-	 * @throws \InvalidArgumentException
330
-	 */
331
-	protected function getFile($parameter, IEvent $event = null) {
332
-		if (is_array($parameter)) {
333
-			$path = reset($parameter);
334
-			$id = (string) key($parameter);
335
-		} else if ($event !== null) {
336
-			// Legacy from before ownCloud 8.2
337
-			$path = $parameter;
338
-			$id = $event->getObjectId();
339
-		} else {
340
-			throw new \InvalidArgumentException('Could not generate file parameter');
341
-		}
342
-
343
-		$encryptionContainer = $this->getEndToEndEncryptionContainer($id, $path);
344
-		if ($encryptionContainer instanceof Folder) {
345
-			$this->fileIsEncrypted = true;
346
-			try {
347
-				$fullPath = rtrim($encryptionContainer->getPath(), '/');
348
-				// Remove /user/files/...
349
-				list(,,, $path) = explode('/', $fullPath, 4);
350
-				if (!$path) {
351
-					throw new InvalidPathException('Path could not be split correctly');
352
-				}
353
-
354
-				return [
355
-					'type' => 'file',
356
-					'id' => $encryptionContainer->getId(),
357
-					'name' => $encryptionContainer->getName(),
358
-					'path' => $path,
359
-					'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $encryptionContainer->getId()]),
360
-				];
361
-			} catch (\Exception $e) {
362
-				// fall back to the normal one
363
-				$this->fileIsEncrypted = false;
364
-			}
365
-		}
366
-
367
-		return [
368
-			'type' => 'file',
369
-			'id' => $id,
370
-			'name' => basename($path),
371
-			'path' => trim($path, '/'),
372
-			'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $id]),
373
-		];
374
-	}
375
-
376
-	protected $fileEncrypted = [];
377
-
378
-	/**
379
-	 * Check if a file is end2end encrypted
380
-	 * @param int $fileId
381
-	 * @param string $path
382
-	 * @return Folder|null
383
-	 */
384
-	protected function getEndToEndEncryptionContainer($fileId, $path) {
385
-		if (isset($this->fileEncrypted[$fileId])) {
386
-			return $this->fileEncrypted[$fileId];
387
-		}
388
-
389
-		$fileName = basename($path);
390
-		if (!preg_match('/^[0-9a-fA-F]{32}$/', $fileName)) {
391
-			$this->fileEncrypted[$fileId] = false;
392
-			return $this->fileEncrypted[$fileId];
393
-		}
394
-
395
-		$userFolder = $this->rootFolder->getUserFolder($this->activityManager->getCurrentUserId());
396
-		$files = $userFolder->getById($fileId);
397
-		if (empty($files)) {
398
-			// Deleted, try with parent
399
-			$file = $userFolder->get(dirname($path));
400
-			if (!$file instanceof Folder || !$file->isEncrypted()) {
401
-				return null;
402
-			}
403
-
404
-			$this->fileEncrypted[$fileId] = $file;
405
-			return $file;
406
-		}
407
-
408
-		$file = array_shift($files);
409
-
410
-		if ($file instanceof Folder && $file->isEncrypted()) {
411
-			// If the folder is encrypted, it is the Container,
412
-			// but can be the name is just fine.
413
-			$this->fileEncrypted[$fileId] = true;
414
-			return null;
415
-		}
416
-
417
-		$this->fileEncrypted[$fileId] = $this->getParentEndToEndEncryptionContainer($userFolder, $file);
418
-		return $this->fileEncrypted[$fileId];
419
-	}
420
-
421
-	/**
422
-	 * Check all parents until the user's root folder if one is encrypted
423
-	 *
424
-	 * @param Folder $userFolder
425
-	 * @param Node $file
426
-	 * @return Node|null
427
-	 */
428
-	protected function getParentEndToEndEncryptionContainer(Folder $userFolder, Node $file) {
429
-		try {
430
-			$parent = $file->getParent();
431
-
432
-			if ($userFolder->getId() === $parent->getId()) {
433
-				return null;
434
-			}
435
-		} catch (\Exception $e) {
436
-			return null;
437
-		}
438
-
439
-		if ($parent->isEncrypted()) {
440
-			return $parent;
441
-		}
442
-
443
-		return $this->getParentEndToEndEncryptionContainer($userFolder, $file);
444
-	}
445
-
446
-	/**
447
-	 * @param string $uid
448
-	 * @return array
449
-	 */
450
-	protected function getUser($uid) {
451
-		if (!isset($this->displayNames[$uid])) {
452
-			$this->displayNames[$uid] = $this->getDisplayName($uid);
453
-		}
454
-
455
-		return [
456
-			'type' => 'user',
457
-			'id' => $uid,
458
-			'name' => $this->displayNames[$uid],
459
-		];
460
-	}
461
-
462
-	/**
463
-	 * @param string $uid
464
-	 * @return string
465
-	 */
466
-	protected function getDisplayName($uid) {
467
-		$user = $this->userManager->get($uid);
468
-		if ($user instanceof IUser) {
469
-			return $user->getDisplayName();
470
-		} else {
471
-			return $uid;
472
-		}
473
-	}
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, $icon) {
117
+        if ($this->activityManager->getRequirePNG()) {
118
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $icon . '.png')));
119
+        } else {
120
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('files', $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
+        } else if ($event->getSubject() === 'renamed_by') {
146
+            $subject = $this->l->t('Renamed by {user}');
147
+            $this->setIcon($event, 'change');
148
+        } else if ($event->getSubject() === 'moved_by') {
149
+            $subject = $this->l->t('Moved by {user}');
150
+            $this->setIcon($event, 'change');
151
+        } else {
152
+            throw new \InvalidArgumentException();
153
+        }
154
+
155
+        if (!isset($parsedParameters['user'])) {
156
+            // External user via public link share
157
+            $subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
158
+        }
159
+
160
+        $this->setSubjects($event, $subject, $parsedParameters);
161
+
162
+        return $this->eventMerger->mergeEvents('user', $event, $previousEvent);
163
+    }
164
+
165
+    /**
166
+     * @param IEvent $event
167
+     * @param IEvent|null $previousEvent
168
+     * @return IEvent
169
+     * @throws \InvalidArgumentException
170
+     * @since 11.0.0
171
+     */
172
+    public function parseLongVersion(IEvent $event, IEvent $previousEvent = null) {
173
+        $this->fileIsEncrypted = false;
174
+        $parsedParameters = $this->getParameters($event);
175
+
176
+        if ($event->getSubject() === 'created_self') {
177
+            $subject = $this->l->t('You created {file}');
178
+            if ($this->fileIsEncrypted) {
179
+                $subject = $this->l->t('You created an encrypted file in {file}');
180
+            }
181
+            $this->setIcon($event, 'add-color');
182
+        } else if ($event->getSubject() === 'created_by') {
183
+            $subject = $this->l->t('{user} created {file}');
184
+            if ($this->fileIsEncrypted) {
185
+                $subject = $this->l->t('{user} created an encrypted file in {file}');
186
+            }
187
+            $this->setIcon($event, 'add-color');
188
+        } else if ($event->getSubject() === 'created_public') {
189
+            $subject = $this->l->t('{file} was created in a public folder');
190
+            $this->setIcon($event, 'add-color');
191
+        } else if ($event->getSubject() === 'changed_self') {
192
+            $subject = $this->l->t('You changed {file}');
193
+            if ($this->fileIsEncrypted) {
194
+                $subject = $this->l->t('You changed an encrypted file in {file}');
195
+            }
196
+            $this->setIcon($event, 'change');
197
+        } else if ($event->getSubject() === 'changed_by') {
198
+            $subject = $this->l->t('{user} changed {file}');
199
+            if ($this->fileIsEncrypted) {
200
+                $subject = $this->l->t('{user} changed an encrypted file in {file}');
201
+            }
202
+            $this->setIcon($event, 'change');
203
+        } else if ($event->getSubject() === 'deleted_self') {
204
+            $subject = $this->l->t('You deleted {file}');
205
+            if ($this->fileIsEncrypted) {
206
+                $subject = $this->l->t('You deleted an encrypted file in {file}');
207
+            }
208
+            $this->setIcon($event, 'delete-color');
209
+        } else if ($event->getSubject() === 'deleted_by') {
210
+            $subject = $this->l->t('{user} deleted {file}');
211
+            if ($this->fileIsEncrypted) {
212
+                $subject = $this->l->t('{user} deleted an encrypted file in {file}');
213
+            }
214
+            $this->setIcon($event, 'delete-color');
215
+        } else if ($event->getSubject() === 'restored_self') {
216
+            $subject = $this->l->t('You restored {file}');
217
+        } else if ($event->getSubject() === 'restored_by') {
218
+            $subject = $this->l->t('{user} restored {file}');
219
+        } else if ($event->getSubject() === 'renamed_self') {
220
+            $subject = $this->l->t('You renamed {oldfile} to {newfile}');
221
+            $this->setIcon($event, 'change');
222
+        } else if ($event->getSubject() === 'renamed_by') {
223
+            $subject = $this->l->t('{user} renamed {oldfile} to {newfile}');
224
+            $this->setIcon($event, 'change');
225
+        } else if ($event->getSubject() === 'moved_self') {
226
+            $subject = $this->l->t('You moved {oldfile} to {newfile}');
227
+            $this->setIcon($event, 'change');
228
+        } else if ($event->getSubject() === 'moved_by') {
229
+            $subject = $this->l->t('{user} moved {oldfile} to {newfile}');
230
+            $this->setIcon($event, 'change');
231
+        } else {
232
+            throw new \InvalidArgumentException();
233
+        }
234
+
235
+        if ($this->fileIsEncrypted) {
236
+            $event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
237
+        }
238
+
239
+        if (!isset($parsedParameters['user'])) {
240
+            // External user via public link share
241
+            $subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
242
+        }
243
+
244
+        $this->setSubjects($event, $subject, $parsedParameters);
245
+
246
+        $event = $this->eventMerger->mergeEvents('file', $event, $previousEvent);
247
+
248
+        if ($event->getChildEvent() === null) {
249
+            // Couldn't group by file, maybe we can group by user
250
+            $event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
251
+        }
252
+
253
+        return $event;
254
+    }
255
+
256
+    protected function setSubjects(IEvent $event, $subject, array $parameters) {
257
+        $placeholders = $replacements = [];
258
+        foreach ($parameters as $placeholder => $parameter) {
259
+            $placeholders[] = '{' . $placeholder . '}';
260
+            if ($parameter['type'] === 'file') {
261
+                $replacements[] = $parameter['path'];
262
+            } else {
263
+                $replacements[] = $parameter['name'];
264
+            }
265
+        }
266
+
267
+        $event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
268
+            ->setRichSubject($subject, $parameters);
269
+    }
270
+
271
+    /**
272
+     * @param IEvent $event
273
+     * @return array
274
+     * @throws \InvalidArgumentException
275
+     */
276
+    protected function getParameters(IEvent $event) {
277
+        $parameters = $event->getSubjectParameters();
278
+        switch ($event->getSubject()) {
279
+            case 'created_self':
280
+            case 'created_public':
281
+            case 'changed_self':
282
+            case 'deleted_self':
283
+            case 'restored_self':
284
+                return [
285
+                    'file' => $this->getFile($parameters[0], $event),
286
+                ];
287
+            case 'created_by':
288
+            case 'changed_by':
289
+            case 'deleted_by':
290
+            case 'restored_by':
291
+                if ($parameters[1] === '') {
292
+                    // External user via public link share
293
+                    return [
294
+                        'file' => $this->getFile($parameters[0], $event),
295
+                    ];
296
+                }
297
+                return [
298
+                    'file' => $this->getFile($parameters[0], $event),
299
+                    'user' => $this->getUser($parameters[1]),
300
+                ];
301
+            case 'renamed_self':
302
+            case 'moved_self':
303
+                return [
304
+                    'newfile' => $this->getFile($parameters[0]),
305
+                    'oldfile' => $this->getFile($parameters[1]),
306
+                ];
307
+            case 'renamed_by':
308
+            case 'moved_by':
309
+                if ($parameters[1] === '') {
310
+                    // External user via public link share
311
+                    return [
312
+                        'newfile' => $this->getFile($parameters[0]),
313
+                        'oldfile' => $this->getFile($parameters[2]),
314
+                    ];
315
+                }
316
+                return [
317
+                    'newfile' => $this->getFile($parameters[0]),
318
+                    'user' => $this->getUser($parameters[1]),
319
+                    'oldfile' => $this->getFile($parameters[2]),
320
+                ];
321
+        }
322
+        return [];
323
+    }
324
+
325
+    /**
326
+     * @param array|string $parameter
327
+     * @param IEvent|null $event
328
+     * @return array
329
+     * @throws \InvalidArgumentException
330
+     */
331
+    protected function getFile($parameter, IEvent $event = null) {
332
+        if (is_array($parameter)) {
333
+            $path = reset($parameter);
334
+            $id = (string) key($parameter);
335
+        } else if ($event !== null) {
336
+            // Legacy from before ownCloud 8.2
337
+            $path = $parameter;
338
+            $id = $event->getObjectId();
339
+        } else {
340
+            throw new \InvalidArgumentException('Could not generate file parameter');
341
+        }
342
+
343
+        $encryptionContainer = $this->getEndToEndEncryptionContainer($id, $path);
344
+        if ($encryptionContainer instanceof Folder) {
345
+            $this->fileIsEncrypted = true;
346
+            try {
347
+                $fullPath = rtrim($encryptionContainer->getPath(), '/');
348
+                // Remove /user/files/...
349
+                list(,,, $path) = explode('/', $fullPath, 4);
350
+                if (!$path) {
351
+                    throw new InvalidPathException('Path could not be split correctly');
352
+                }
353
+
354
+                return [
355
+                    'type' => 'file',
356
+                    'id' => $encryptionContainer->getId(),
357
+                    'name' => $encryptionContainer->getName(),
358
+                    'path' => $path,
359
+                    'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $encryptionContainer->getId()]),
360
+                ];
361
+            } catch (\Exception $e) {
362
+                // fall back to the normal one
363
+                $this->fileIsEncrypted = false;
364
+            }
365
+        }
366
+
367
+        return [
368
+            'type' => 'file',
369
+            'id' => $id,
370
+            'name' => basename($path),
371
+            'path' => trim($path, '/'),
372
+            'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $id]),
373
+        ];
374
+    }
375
+
376
+    protected $fileEncrypted = [];
377
+
378
+    /**
379
+     * Check if a file is end2end encrypted
380
+     * @param int $fileId
381
+     * @param string $path
382
+     * @return Folder|null
383
+     */
384
+    protected function getEndToEndEncryptionContainer($fileId, $path) {
385
+        if (isset($this->fileEncrypted[$fileId])) {
386
+            return $this->fileEncrypted[$fileId];
387
+        }
388
+
389
+        $fileName = basename($path);
390
+        if (!preg_match('/^[0-9a-fA-F]{32}$/', $fileName)) {
391
+            $this->fileEncrypted[$fileId] = false;
392
+            return $this->fileEncrypted[$fileId];
393
+        }
394
+
395
+        $userFolder = $this->rootFolder->getUserFolder($this->activityManager->getCurrentUserId());
396
+        $files = $userFolder->getById($fileId);
397
+        if (empty($files)) {
398
+            // Deleted, try with parent
399
+            $file = $userFolder->get(dirname($path));
400
+            if (!$file instanceof Folder || !$file->isEncrypted()) {
401
+                return null;
402
+            }
403
+
404
+            $this->fileEncrypted[$fileId] = $file;
405
+            return $file;
406
+        }
407
+
408
+        $file = array_shift($files);
409
+
410
+        if ($file instanceof Folder && $file->isEncrypted()) {
411
+            // If the folder is encrypted, it is the Container,
412
+            // but can be the name is just fine.
413
+            $this->fileEncrypted[$fileId] = true;
414
+            return null;
415
+        }
416
+
417
+        $this->fileEncrypted[$fileId] = $this->getParentEndToEndEncryptionContainer($userFolder, $file);
418
+        return $this->fileEncrypted[$fileId];
419
+    }
420
+
421
+    /**
422
+     * Check all parents until the user's root folder if one is encrypted
423
+     *
424
+     * @param Folder $userFolder
425
+     * @param Node $file
426
+     * @return Node|null
427
+     */
428
+    protected function getParentEndToEndEncryptionContainer(Folder $userFolder, Node $file) {
429
+        try {
430
+            $parent = $file->getParent();
431
+
432
+            if ($userFolder->getId() === $parent->getId()) {
433
+                return null;
434
+            }
435
+        } catch (\Exception $e) {
436
+            return null;
437
+        }
438
+
439
+        if ($parent->isEncrypted()) {
440
+            return $parent;
441
+        }
442
+
443
+        return $this->getParentEndToEndEncryptionContainer($userFolder, $file);
444
+    }
445
+
446
+    /**
447
+     * @param string $uid
448
+     * @return array
449
+     */
450
+    protected function getUser($uid) {
451
+        if (!isset($this->displayNames[$uid])) {
452
+            $this->displayNames[$uid] = $this->getDisplayName($uid);
453
+        }
454
+
455
+        return [
456
+            'type' => 'user',
457
+            'id' => $uid,
458
+            'name' => $this->displayNames[$uid],
459
+        ];
460
+    }
461
+
462
+    /**
463
+     * @param string $uid
464
+     * @return string
465
+     */
466
+    protected function getDisplayName($uid) {
467
+        $user = $this->userManager->get($uid);
468
+        if ($user instanceof IUser) {
469
+            return $user->getDisplayName();
470
+        } else {
471
+            return $uid;
472
+        }
473
+    }
474 474
 }
Please login to merge, or discard this patch.