Completed
Push — master ( 05cf55...c87bd0 )
by Roeland
13:25
created

Manager::registerConsumer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Thomas Müller <[email protected]>
6
 *
7
 * @copyright Copyright (c) 2016, ownCloud, Inc.
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
namespace OC\Activity;
24
25
26
use OCP\Activity\IConsumer;
27
use OCP\Activity\IEvent;
28
use OCP\Activity\IExtension;
29
use OCP\Activity\IManager;
30
use OCP\IConfig;
31
use OCP\IRequest;
32
use OCP\IUser;
33
use OCP\IUserSession;
34
35
class Manager implements IManager {
36
	/** @var IRequest */
37
	protected $request;
38
39
	/** @var IUserSession */
40
	protected $session;
41
42
	/** @var IConfig */
43
	protected $config;
44
45
	/** @var string */
46
	protected $formattingObjectType;
47
48
	/** @var int */
49
	protected $formattingObjectId;
50
51
	/** @var string */
52
	protected $currentUserId;
53
54
	/**
55
	 * constructor of the controller
56
	 *
57
	 * @param IRequest $request
58
	 * @param IUserSession $session
59
	 * @param IConfig $config
60
	 */
61
	public function __construct(IRequest $request,
62
								IUserSession $session,
63
								IConfig $config) {
64
		$this->request = $request;
65
		$this->session = $session;
66
		$this->config = $config;
67
	}
68
69
	/** @var \Closure[] */
70
	private $consumersClosures = array();
71
72
	/** @var IConsumer[] */
73
	private $consumers = array();
74
75
	/** @var \Closure[] */
76
	private $extensionsClosures = array();
77
78
	/** @var IExtension[] */
79
	private $extensions = array();
80
81
	/** @var array list of filters "name" => "is valid" */
82
	protected $validFilters = array(
83
		'all'	=> true,
84
		'by'	=> true,
85
		'self'	=> true,
86
	);
87
88
	/** @var array list of type icons "type" => "css class" */
89
	protected $typeIcons = array();
90
91
	/** @var array list of special parameters "app" => ["text" => ["parameter" => "type"]] */
92
	protected $specialParameters = array();
93
94
	/**
95
	 * @return \OCP\Activity\IConsumer[]
96
	 */
97 View Code Duplication
	protected function getConsumers() {
98
		if (!empty($this->consumers)) {
99
			return $this->consumers;
100
		}
101
102
		$this->consumers = [];
103
		foreach($this->consumersClosures as $consumer) {
104
			$c = $consumer();
105
			if ($c instanceof IConsumer) {
106
				$this->consumers[] = $c;
107
			} else {
108
				throw new \InvalidArgumentException('The given consumer does not implement the \OCP\Activity\IConsumer interface');
109
			}
110
		}
111
112
		return $this->consumers;
113
	}
114
115
	/**
116
	 * @return \OCP\Activity\IExtension[]
117
	 */
118 View Code Duplication
	protected function getExtensions() {
119
		if (!empty($this->extensions)) {
120
			return $this->extensions;
121
		}
122
123
		$this->extensions = [];
124
		foreach($this->extensionsClosures as $extension) {
125
			$e = $extension();
126
			if ($e instanceof IExtension) {
127
				$this->extensions[] = $e;
128
			} else {
129
				throw new \InvalidArgumentException('The given extension does not implement the \OCP\Activity\IExtension interface');
130
			}
131
		}
132
133
		return $this->extensions;
134
	}
135
136
	/**
137
	 * Generates a new IEvent object
138
	 *
139
	 * Make sure to call at least the following methods before sending it to the
140
	 * app with via the publish() method:
141
	 *  - setApp()
142
	 *  - setType()
143
	 *  - setAffectedUser()
144
	 *  - setSubject()
145
	 *
146
	 * @return IEvent
147
	 */
148
	public function generateEvent() {
149
		return new Event();
150
	}
151
152
	/**
153
	 * Publish an event to the activity consumers
154
	 *
155
	 * Make sure to call at least the following methods before sending an Event:
156
	 *  - setApp()
157
	 *  - setType()
158
	 *  - setAffectedUser()
159
	 *  - setSubject()
160
	 *
161
	 * @param IEvent $event
162
	 * @return null
163
	 * @throws \BadMethodCallException if required values have not been set
164
	 */
165
	public function publish(IEvent $event) {
166
		if (!$event->getApp()) {
167
			throw new \BadMethodCallException('App not set', 10);
168
		}
169
		if (!$event->getType()) {
170
			throw new \BadMethodCallException('Type not set', 11);
171
		}
172
		if ($event->getAffectedUser() === null) {
173
			throw new \BadMethodCallException('Affected user not set', 12);
174
		}
175
		if ($event->getSubject() === null || $event->getSubjectParameters() === null) {
176
			throw new \BadMethodCallException('Subject not set', 13);
177
		}
178
179
		if ($event->getAuthor() === null) {
180
			if ($this->session->getUser() instanceof IUser) {
181
				$event->setAuthor($this->session->getUser()->getUID());
182
			}
183
		}
184
185
		if (!$event->getTimestamp()) {
186
			$event->setTimestamp(time());
187
		}
188
189
		foreach ($this->getConsumers() as $c) {
190
			$c->receive($event);
191
		}
192
	}
193
194
	/**
195
	 * @param string $app           The app where this event is associated with
196
	 * @param string $subject       A short description of the event
197
	 * @param array  $subjectParams Array with parameters that are filled in the subject
198
	 * @param string $message       A longer description of the event
199
	 * @param array  $messageParams Array with parameters that are filled in the message
200
	 * @param string $file          The file including path where this event is associated with
201
	 * @param string $link          A link where this event is associated with
202
	 * @param string $affectedUser  Recipient of the activity
203
	 * @param string $type          Type of the notification
204
	 * @param int    $priority      Priority of the notification
205
	 * @return null
206
	 */
207
	public function publishActivity($app, $subject, $subjectParams, $message, $messageParams, $file, $link, $affectedUser, $type, $priority) {
208
		$event = $this->generateEvent();
209
		$event->setApp($app)
210
			->setType($type)
211
			->setAffectedUser($affectedUser)
212
			->setSubject($subject, $subjectParams)
213
			->setMessage($message, $messageParams)
214
			->setObject('', 0, $file)
215
			->setLink($link);
216
217
		$this->publish($event);
218
	}
219
220
	/**
221
	 * In order to improve lazy loading a closure can be registered which will be called in case
222
	 * activity consumers are actually requested
223
	 *
224
	 * $callable has to return an instance of OCA\Activity\IConsumer
225
	 *
226
	 * @param \Closure $callable
227
	 */
228
	public function registerConsumer(\Closure $callable) {
229
		array_push($this->consumersClosures, $callable);
230
		$this->consumers = [];
231
	}
232
233
	/**
234
	 * In order to improve lazy loading a closure can be registered which will be called in case
235
	 * activity consumers are actually requested
236
	 *
237
	 * $callable has to return an instance of OCA\Activity\IConsumer
238
	 *
239
	 * @param \Closure $callable
240
	 * @return void
241
	 */
242
	public function registerExtension(\Closure $callable) {
243
		array_push($this->extensionsClosures, $callable);
244
		$this->extensions = [];
245
	}
246
247
	/**
248
	 * Will return additional notification types as specified by other apps
249
	 *
250
	 * @param string $languageCode
251
	 * @return array
252
	 */
253
	public function getNotificationTypes($languageCode) {
254
		$filesNotificationTypes = [];
255
		$sharingNotificationTypes = [];
256
257
		$notificationTypes = array();
258
		foreach ($this->getExtensions() as $c) {
259
			$result = $c->getNotificationTypes($languageCode);
260
			if (is_array($result)) {
261
				if (class_exists('\OCA\Files\Activity', false) && $c instanceof \OCA\Files\Activity) {
262
					$filesNotificationTypes = $result;
263
					continue;
264
				}
265
				if (class_exists('\OCA\Files_Sharing\Activity', false) && $c instanceof \OCA\Files_Sharing\Activity) {
266
					$sharingNotificationTypes = $result;
267
					continue;
268
				}
269
270
				$notificationTypes = array_merge($notificationTypes, $result);
271
			}
272
		}
273
274
		return array_merge($filesNotificationTypes, $sharingNotificationTypes, $notificationTypes);
275
	}
276
277
	/**
278
	 * @param string $method
279
	 * @return array
280
	 */
281
	public function getDefaultTypes($method) {
282
		$defaultTypes = array();
283
		foreach ($this->getExtensions() as $c) {
284
			$types = $c->getDefaultTypes($method);
285
			if (is_array($types)) {
286
				$defaultTypes = array_merge($types, $defaultTypes);
287
			}
288
		}
289
		return $defaultTypes;
290
	}
291
292
	/**
293
	 * @param string $type
294
	 * @return string
295
	 */
296
	public function getTypeIcon($type) {
297
		if (isset($this->typeIcons[$type])) {
298
			return $this->typeIcons[$type];
299
		}
300
301
		foreach ($this->getExtensions() as $c) {
302
			$icon = $c->getTypeIcon($type);
303
			if (is_string($icon)) {
304
				$this->typeIcons[$type] = $icon;
305
				return $icon;
306
			}
307
		}
308
309
		$this->typeIcons[$type] = '';
310
		return '';
311
	}
312
313
	/**
314
	 * @param string $type
315
	 * @param string $id
316
	 */
317
	public function setFormattingObject($type, $id) {
318
		$this->formattingObjectType = $type;
319
		$this->formattingObjectId = (string) $id;
0 ignored issues
show
Documentation Bug introduced by
The property $formattingObjectId was declared of type integer, but (string) $id is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
320
	}
321
322
	/**
323
	 * @return bool
324
	 */
325
	public function isFormattingFilteredObject() {
326
		return $this->formattingObjectType !== null && $this->formattingObjectId !== null
327
			&& $this->formattingObjectType === $this->request->getParam('object_type')
328
			&& $this->formattingObjectId === $this->request->getParam('object_id');
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->formattingObjectId (integer) and $this->request->getParam('object_id') (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
329
	}
330
331
	/**
332
	 * @param string $app
333
	 * @param string $text
334
	 * @param array $params
335
	 * @param boolean $stripPath
336
	 * @param boolean $highlightParams
337
	 * @param string $languageCode
338
	 * @return string|false
339
	 */
340
	public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) {
341
		foreach ($this->getExtensions() as $c) {
342
			$translation = $c->translate($app, $text, $params, $stripPath, $highlightParams, $languageCode);
343
			if (is_string($translation)) {
344
				return $translation;
345
			}
346
		}
347
348
		return false;
349
	}
350
351
	/**
352
	 * @param string $app
353
	 * @param string $text
354
	 * @return array|false
355
	 */
356
	public function getSpecialParameterList($app, $text) {
357
		if (isset($this->specialParameters[$app][$text])) {
358
			return $this->specialParameters[$app][$text];
359
		}
360
361
		if (!isset($this->specialParameters[$app])) {
362
			$this->specialParameters[$app] = array();
363
		}
364
365
		foreach ($this->getExtensions() as $c) {
366
			$specialParameter = $c->getSpecialParameterList($app, $text);
367
			if (is_array($specialParameter)) {
368
				$this->specialParameters[$app][$text] = $specialParameter;
369
				return $specialParameter;
370
			}
371
		}
372
373
		$this->specialParameters[$app][$text] = false;
374
		return false;
375
	}
376
377
	/**
378
	 * @param array $activity
379
	 * @return integer|false
380
	 */
381
	public function getGroupParameter($activity) {
382
		foreach ($this->getExtensions() as $c) {
383
			$parameter = $c->getGroupParameter($activity);
384
			if ($parameter !== false) {
385
				return $parameter;
386
			}
387
		}
388
389
		return false;
390
	}
391
392
	/**
393
	 * @return array
394
	 */
395
	public function getNavigation() {
396
		$entries = array(
397
			'apps' => array(),
398
			'top' => array(),
399
		);
400
		foreach ($this->getExtensions() as $c) {
401
			$additionalEntries = $c->getNavigation();
402
			if (is_array($additionalEntries)) {
403
				$entries['apps'] = array_merge($entries['apps'], $additionalEntries['apps']);
404
				$entries['top'] = array_merge($entries['top'], $additionalEntries['top']);
405
			}
406
		}
407
408
		return $entries;
409
	}
410
411
	/**
412
	 * @param string $filterValue
413
	 * @return boolean
414
	 */
415
	public function isFilterValid($filterValue) {
416
		if (isset($this->validFilters[$filterValue])) {
417
			return $this->validFilters[$filterValue];
418
		}
419
420
		foreach ($this->getExtensions() as $c) {
421
			if ($c->isFilterValid($filterValue) === true) {
422
				$this->validFilters[$filterValue] = true;
423
				return true;
424
			}
425
		}
426
427
		$this->validFilters[$filterValue] = false;
428
		return false;
429
	}
430
431
	/**
432
	 * @param array $types
433
	 * @param string $filter
434
	 * @return array
435
	 */
436
	public function filterNotificationTypes($types, $filter) {
437
		if (!$this->isFilterValid($filter)) {
438
			return $types;
439
		}
440
441
		foreach ($this->getExtensions() as $c) {
442
			$result = $c->filterNotificationTypes($types, $filter);
443
			if (is_array($result)) {
444
				$types = $result;
445
			}
446
		}
447
		return $types;
448
	}
449
450
	/**
451
	 * @param string $filter
452
	 * @return array
453
	 */
454
	public function getQueryForFilter($filter) {
455
		if (!$this->isFilterValid($filter)) {
456
			return [null, null];
457
		}
458
459
		$conditions = array();
460
		$parameters = array();
461
462
		foreach ($this->getExtensions() as $c) {
463
			$result = $c->getQueryForFilter($filter);
464
			if (is_array($result)) {
465
				list($condition, $parameter) = $result;
466
				if ($condition && is_array($parameter)) {
467
					$conditions[] = $condition;
468
					$parameters = array_merge($parameters, $parameter);
469
				}
470
			}
471
		}
472
473
		if (empty($conditions)) {
474
			return array(null, null);
475
		}
476
477
		return array(' and ((' . implode(') or (', $conditions) . '))', $parameters);
478
	}
479
480
	/**
481
	 * Set the user we need to use
482
	 *
483
	 * @param string|null $currentUserId
484
	 * @throws \UnexpectedValueException If the user is invalid
485
	 */
486
	public function setCurrentUserId($currentUserId) {
487
		if (!is_string($currentUserId) && $currentUserId !== null) {
488
			throw new \UnexpectedValueException('The given current user is invalid');
489
		}
490
		$this->currentUserId = $currentUserId;
491
	}
492
493
	/**
494
	 * Get the user we need to use
495
	 *
496
	 * Either the user is logged in, or we try to get it from the token
497
	 *
498
	 * @return string
499
	 * @throws \UnexpectedValueException If the token is invalid, does not exist or is not unique
500
	 */
501
	public function getCurrentUserId() {
502
		if ($this->currentUserId !== null) {
503
			return $this->currentUserId;
504
		} else if (!$this->session->isLoggedIn()) {
505
			return $this->getUserFromToken();
506
		} else {
507
			return $this->session->getUser()->getUID();
508
		}
509
	}
510
511
	/**
512
	 * Get the user for the token
513
	 *
514
	 * @return string
515
	 * @throws \UnexpectedValueException If the token is invalid, does not exist or is not unique
516
	 */
517
	protected function getUserFromToken() {
518
		$token = (string) $this->request->getParam('token', '');
519
		if (strlen($token) !== 30) {
520
			throw new \UnexpectedValueException('The token is invalid');
521
		}
522
523
		$users = $this->config->getUsersForUserValue('activity', 'rsstoken', $token);
524
525
		if (sizeof($users) !== 1) {
526
			// No unique user found
527
			throw new \UnexpectedValueException('The token is invalid');
528
		}
529
530
		// Token found login as that user
531
		return array_shift($users);
532
	}
533
}
534