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

Manager::publishActivity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 1
eloc 10
nc 1
nop 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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