Completed
Push — master ( 3071ad...3723f6 )
by Maxence
03:35 queued 01:12
created

Provider::parseLinkEvent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 1
eloc 5
nc 1
nop 4
1
<?php
2
3
4
namespace OCA\Circles\Activity;
5
6
7
use Exception;
8
use InvalidArgumentException;
9
use OCA\Circles\Api\v1\Circles;
10
use OCA\Circles\Model\Circle;
11
use OCA\Circles\Model\FederatedLink;
12
use OCA\Circles\Model\Member;
13
use OCA\Circles\Service\CirclesService;
14
use OCA\Circles\Service\MiscService;
15
use OCP\Activity\IEvent;
16
use OCP\Activity\IManager;
17
use OCP\Activity\IProvider;
18
use OCP\IL10N;
19
use OCP\IURLGenerator;
20
use OpenCloud\Common\Exceptions\InvalidArgumentError;
21
22
23
class Provider implements IProvider {
24
25
	/** @var MiscService */
26
	protected $miscService;
27
28
	/** @var IL10N */
29
	protected $l10n;
30
31
	/** @var IURLGenerator */
32
	protected $url;
33
34
	/** @var IManager */
35
	protected $activityManager;
36
37
	public function __construct(
38
		IURLGenerator $url, IManager $activityManager, IL10N $l10n, MiscService $miscService
39
	) {
40
		$this->url = $url;
41
		$this->activityManager = $activityManager;
42
		$this->l10n = $l10n;
43
		$this->miscService = $miscService;
44
	}
45
46
47
	/**
48
	 * @param string $lang
49
	 * @param IEvent $event
50
	 * @param IEvent|null $previousEvent
51
	 *
52
	 * @return IEvent
53
	 */
54
	public function parse($lang, IEvent $event, IEvent $previousEvent = null) {
55
56
		if ($event->getApp() !== 'circles') {
57
			throw new \InvalidArgumentException();
58
		}
59
60
		try {
61
			$params = $event->getSubjectParameters();
62
			$circle = Circle::fromJSON($this->l10n, $params['circle']);
63
64
			$this->verifyCircleIntegrity($circle);
65
			$this->setIcon($event, $circle);
66
			$this->parseAsMember($event, $circle, $params);
67
			$this->parseAsModerator($event, $circle, $params);
68
69
			$this->generateParsedSubject($event);
70
71
			return $event;
72
		} catch (\Exception $e) {
73
			throw new \InvalidArgumentException();
74
		}
75
	}
76
77
78
	private function verifyCircleIntegrity(Circle $circle) {
79
		if ($circle->getViewer() === null) {
80
			throw new \InvalidArgumentException();
81
		}
82
	}
83
84
85
	private function setIcon(IEvent &$event, Circle $circle) {
86
		$event->setIcon(
87
			CirclesService::getCircleIcon(
88
				$circle->getType(),
89
				(method_exists($this->activityManager, 'getRequirePNG')
90
				 && $this->activityManager->getRequirePNG())
91
			)
92
		);
93
	}
94
95
	/**
96
	 * @param Circle $circle
97
	 * @param IEvent $event
98
	 * @param array $params
99
	 *
100
	 * @return IEvent
101
	 */
102
	private function parseAsMember(IEvent &$event, Circle $circle, $params) {
103
		if ($event->getType() !== 'circles_as_member') {
104
			return $event;
105
		}
106
107
		switch ($event->getSubject()) {
108
			case 'circle_create':
109
				return $this->parseCircleEvent(
110
					$event, $circle, null,
111
					$this->l10n->t('You created the circle {circle}'),
112
					$this->l10n->t('{author} created the circle {circle}')
113
				);
114
115
			case 'circle_delete':
116
				return $this->parseCircleEvent(
117
					$event, $circle, null,
118
					$this->l10n->t('You deleted {circle}'),
119
					$this->l10n->t('{author} deleted {circle}')
120
				);
121
		}
122
123
		if (key_exists('member', $params)) {
124
			$this->parseMemberAsMember($event, $circle);
125
		}
126
127
		return $event;
128
	}
129
130
131
	/**
132
	 * @param Circle $circle
133
	 * @param IEvent $event
134
	 *
135
	 * @return IEvent
136
	 */
137
	private function parseMemberAsMember(IEvent &$event, Circle $circle) {
138
		$params = $event->getSubjectParameters();
139
		$member = Member::fromJSON($this->l10n, $params['member']);
140
141
		switch ($event->getSubject()) {
142 View Code Duplication
			case 'member_join':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
				return $this->parseCircleMemberEvent(
144
					$event, $circle, $member,
145
					$this->l10n->t('You joined {circle}'),
146
					$this->l10n->t('{member} joined {circle}')
147
				);
148
149 View Code Duplication
			case 'member_add':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
				return $this->parseCircleMemberAdvancedEvent(
151
					$event, $circle, $member,
152
					$this->l10n->t('You added {member} as member to {circle}'),
153
					$this->l10n->t('You were added as member to {circle} by {author}'),
154
					$this->l10n->t('{member} was added as member to {circle} by {author}')
155
				);
156
157 View Code Duplication
			case 'member_left':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
158
				return $this->parseCircleMemberEvent(
159
					$event, $circle, $member,
160
					$this->l10n->t('You left {circle}'),
161
					$this->l10n->t('{member} left {circle}')
162
				);
163
164 View Code Duplication
			case 'member_remove':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
				return $this->parseCircleMemberAdvancedEvent(
166
					$event, $circle, $member,
167
					$this->l10n->t('You removed {member} from {circle}'),
168
					$this->l10n->t('You were removed from {circle} by {author}'),
169
					$this->l10n->t('{member} was removed from {circle} by {author}')
170
				);
171
		}
172
173
		return $event;
174
	}
175
176
177
	/**
178
	 * @param Circle $circle
179
	 * @param IEvent $event
180
	 * @param array $params
181
	 *
182
	 * @return IEvent
183
	 * @throws Exception
184
	 */
185
	private function parseAsModerator(IEvent &$event, Circle $circle, $params) {
186
		if ($event->getType() !== 'circles_as_moderator') {
187
			return $event;
188
		}
189
190
		try {
191
			if (key_exists('member', $params)) {
192
				return $this->parseMemberAsModerator($event, $circle);
193
			}
194
195
			if (key_exists('link', $params)) {
196
				return $this->parseLinkAsModerator($event, $circle);
197
			}
198
199
			throw new InvalidArgumentError();
200
		} catch (Exception $e) {
201
			throw $e;
202
		}
203
204
	}
205
206
207
	/**
208
	 * @param Circle $circle
209
	 * @param IEvent $event
210
	 *
211
	 * @return IEvent
212
	 */
213
	private function parseMemberAsModerator(IEvent &$event, Circle $circle) {
214
215
		$params = $event->getSubjectParameters();
216
		$member = Member::fromJSON($this->l10n, $params['member']);
217
218
		switch ($event->getSubject()) {
219 View Code Duplication
			case 'member_invited':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
220
				return $this->parseCircleMemberAdvancedEvent(
221
					$event, $circle, $member,
222
					$this->l10n->t('You invited {member} into {circle}'),
223
					$this->l10n->t('You have been invited into {circle} by {author}'),
224
					$this->l10n->t('{member} have been invited into {circle} by {author}')
225
				);
226
227
			case 'member_level':
228
				$level = [$this->l10n->t($member->getLevelString())];
229
230
				return $this->parseCircleMemberAdvancedEvent(
231
					$event, $circle, $member,
232
					$this->l10n->t('You changed {member}\'s level in {circle} to %1$s', $level),
233
					$this->l10n->t('{author} changed your level in {circle} to %1$s', $level),
234
					$this->l10n->t('{author} changed {member}\'s level in {circle} to %1$s', $level)
235
				);
236
237 View Code Duplication
			case 'member_request_invitation':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
238
				return $this->parseMemberEvent(
239
					$event, $circle, $member,
240
					$this->l10n->t('You requested an invitation to {circle}'),
241
					$this->l10n->t(
242
						'{member} has requested an invitation into {circle}'
243
					)
244
				);
245
246 View Code Duplication
			case 'member_owner':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
247
				return $this->parseMemberEvent(
248
					$event, $circle, $member,
249
					$this->l10n->t('You are the new owner of {circle}'),
250
					$this->l10n->t('{member} is the new owner of {circle}')
251
				);
252
		}
253
254
		throw new InvalidArgumentException();
255
	}
256
257
258
	/**
259
	 * @param Circle $circle
260
	 * @param IEvent $event
261
	 *
262
	 * @return IEvent
263
	 */
264
	private function parseLinkAsModerator(IEvent &$event, Circle $circle) {
265
266
		$params = $event->getSubjectParameters();
267
		$link = FederatedLink::fromJSON($params['link']);
268
269
		switch ($event->getSubject()) {
270
			case 'link_request_sent':
271
				return $this->parseCircleEvent(
272
					$event, $circle, $link,
273
					$this->l10n->t('You sent a request to link {circle} with {link}'),
274
					$this->l10n->t('{author} sent a request to link {circle} with {link}')
275
				);
276
277
			case 'link_request_received';
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
278
				return $this->parseLinkEvent(
279
					$event, $circle, $link,
280
					$this->l10n->t('{link} requested a link with {circle}')
281
				);
282
283
			case 'link_request_rejected';
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
284
				return $this->parseLinkEvent(
285
					$event, $circle, $link, $this->l10n->t(
286
					'The request to link {circle} with {link} has been rejected'
287
				)
288
				);
289
290
			case 'link_request_canceled':
291
				return $this->parseLinkEvent(
292
					$event, $circle, $link,
293
					$this->l10n->t(
294
						'The request to link {link} with {circle} has been canceled remotely'
295
					)
296
				);
297
298
			case 'link_request_accepted':
299
				return $this->parseLinkEvent(
300
					$event, $circle, $link,
301
					$this->l10n->t('The request to link {circle} with {link} has been accepted')
302
				);
303
304
			case 'link_request_removed':
305
				return $this->parseCircleEvent(
306
					$event, $circle, $link,
307
					$this->l10n->t('You dismissed the request to link {link} with {circle}'),
308
					$this->l10n->t('{author} dismissed the request to link {link} with {circle}')
309
				);
310
311
			case 'link_request_canceling':
312
				return $this->parseCircleEvent(
313
					$event, $circle, $link,
314
					$this->l10n->t('You canceled the request to link {circle} with {link}'),
315
					$this->l10n->t('{author} canceled the request to link {circle} with {link}')
316
				);
317
318
			case 'link_request_accepting':
319
				return $this->parseCircleEvent(
320
					$event, $circle, $link,
321
					$this->l10n->t('You accepted the request to link {link} with {circle}'),
322
					$this->l10n->t('{author} accepted the request to link {link} with {circle}')
323
				);
324
325
			case 'link_up':
326
				return $this->parseLinkEvent(
327
					$event, $circle, $link,
328
					$this->l10n->t('A link between {circle} and {link} is now up and running')
329
				);
330
331
			case 'link_down':
332
				return $this->parseLinkEvent(
333
					$event, $circle, $link,
334
					$this->l10n->t(
335
						'The link between {circle} and {link} has been shutdown remotely'
336
					)
337
				);
338
339
			case 'link_remove':
340
				return $this->parseCircleEvent(
341
					$event, $circle, $link,
342
					$this->l10n->t('You closed the link between {circle} and {link}'),
343
					$this->l10n->t('{author} closed the link between {circle} and {link}')
344
				);
345
		}
346
347
		throw new InvalidArgumentException();
348
	}
349
350
351
	/**
352
	 * general function to generate Circle event.
353
	 *
354
	 * @param Circle $circle
355
	 * @param FederatedLink $link
356
	 * @param IEvent $event
357
	 * @param $ownEvent
358
	 * @param $othersEvent
359
	 *
360
	 * @return IEvent
361
	 */
362
	private function parseCircleEvent(IEvent &$event, Circle $circle, $link, $ownEvent, $othersEvent
363
	) {
364
		$data = [
365
			'author' => $author = $this->generateUserParameter(
366
				$circle->getViewer()
367
					   ->getUserId()
368
			),
369
			'circle' => $this->generateCircleParameter($circle),
370
			'link'   => ($link === null) ? '' : $this->generateLinkParameter($link)
371
		];
372
373
		if ($circle->getViewer()
374
				   ->getUserId() === $this->activityManager->getCurrentUserId()
375
		) {
376
			return $event->setRichSubject($ownEvent, $data);
377
		}
378
379
		return $event->setRichSubject($othersEvent, $data);
380
	}
381
382
383
	/**
384
	 * general function to generate Member event.
385
	 *
386
	 * @param Circle $circle
387
	 * @param $member
388
	 * @param IEvent $event
389
	 * @param $ownEvent
390
	 * @param $othersEvent
391
	 *
392
	 * @return IEvent
393
	 */
394
	private function parseMemberEvent(
395
		IEvent &$event, Circle $circle, Member $member, $ownEvent, $othersEvent
396
	) {
397
		$data = [
398
			'circle' => $this->generateCircleParameter($circle),
399
			'member' => $this->generateMemberParameter($member)
400
		];
401
402
		if ($member->getUserId() === $this->activityManager->getCurrentUserId()
403
		) {
404
			return $event->setRichSubject($ownEvent, $data);
405
		}
406
407
		return $event->setRichSubject($othersEvent, $data);
408
	}
409
410
411
	/**
412
	 * general function to generate Link event.
413
	 *
414
	 * @param Circle $circle
415
	 * @param FederatedLink $link
416
	 * @param IEvent $event
417
	 * @param $line
418
	 *
419
	 * @return IEvent
420
	 */
421
	private function parseLinkEvent(IEvent &$event, Circle $circle, FederatedLink $link, $line) {
422
		$data = [
423
			'circle' => $this->generateCircleParameter($circle),
424
			'link'   => $this->generateLinkParameter($link)
425
		];
426
427
		return $event->setRichSubject($line, $data);
428
	}
429
430
431
	/**
432
	 * general function to generate Circle+Member event.
433
	 *
434
	 * @param Circle $circle
435
	 * @param Member $member
436
	 * @param IEvent $event
437
	 * @param $ownEvent
438
	 * @param $othersEvent
439
	 *
440
	 * @return IEvent
441
	 */
442
	private function parseCircleMemberEvent(
443
		IEvent &$event, Circle $circle, Member $member, $ownEvent, $othersEvent
444
	) {
445
		$data = [
446
			'circle' => $this->generateCircleParameter($circle),
447
			'member' => $this->generateMemberParameter($member)
448
		];
449
450
		if ($circle->getViewer()
451
				   ->getUserId() === $this->activityManager->getCurrentUserId()
452
		) {
453
			return $event->setRichSubject($ownEvent, $data);
454
		}
455
456
		return $event->setRichSubject($othersEvent, $data);
457
	}
458
459
460
	/**
461
	 * general function to generate Circle+Member advanced event.
462
	 *
463
	 * @param Circle $circle
464
	 * @param Member $member
465
	 * @param IEvent $event
466
	 *\
467
	 * @param $ownEvent
468
	 * @param $targetEvent
469
	 * @param $othersEvent
470
	 *
471
	 * @return IEvent
472
	 */
473
	private function parseCircleMemberAdvancedEvent(
474
		IEvent &$event, Circle $circle, Member $member, $ownEvent, $targetEvent, $othersEvent
475
	) {
476
477
		$data = [
478
			'author' => $this->generateUserParameter(
479
				$circle->getViewer()
480
					   ->getUserId()
481
			),
482
			'circle' => $this->generateCircleParameter($circle),
483
			'member' => $this->generateMemberParameter($member)
484
		];
485
486
		if ($circle->getViewer()
487
				   ->getUserId() === $this->activityManager->getCurrentUserId()
488
		) {
489
			return $event->setRichSubject($ownEvent, $data);
490
		}
491
492
		if ($member->getUserId() === $this->activityManager->getCurrentUserId()) {
493
			return $event->setRichSubject($targetEvent, $data);
494
		}
495
496
		return $event->setRichSubject($othersEvent, $data);
497
	}
498
499
500
	/**
501
	 * @param IEvent $event
502
	 */
503
	private function generateParsedSubject(IEvent &$event) {
504
		$subject = $event->getRichSubject();
505
		$params = $event->getRichSubjectParameters();
506
		$ak = array_keys($params);
507
		foreach ($ak as $k) {
508
			if (is_array($params[$k])) {
509
				$subject = str_replace('{' . $k . '}', $params[$k]['parsed'], $subject);
510
			}
511
		}
512
513
		$event->setParsedSubject($subject);
514
	}
515
516
	/**
517
	 * @param Member $member
518
	 *
519
	 * @return array<string,string|integer>
520
	 */
521
	private function generateMemberParameter(Member $member) {
522
		return $this->generateUserParameter($member->getUserId());
523
	}
524
525
526
	/**
527
	 * @param Circle $circle
528
	 *
529
	 * @return array<string,string|integer>
530
	 */
531
	private function generateCircleParameter(Circle $circle) {
532
		return [
533
			'type'   => 'circle',
534
			'id'     => $circle->getId(),
535
			'name'   => $circle->getName(),
536
			'parsed' => $circle->getName(),
537
			'link'   => Circles::generateLink($circle->getId())
538
		];
539
	}
540
541
542
	/**
543
	 * @param FederatedLink $link
544
	 *
545
	 * @return array<string,string|integer>
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
546
	 */
547
	private function generateLinkParameter(FederatedLink $link) {
548
		return [
549
			'type'   => 'circle',
550
			'id'     => $link->getUniqueId(),
551
			'name'   => $link->getToken() . '@' . $link->getAddress(),
552
			'parsed' => $link->getToken() . '@' . $link->getAddress()
553
		];
554
//			'link' => Circles::generateRemoteLink($link)
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
555
	}
556
557
558
	/**
559
	 * @param $userId
560
	 *
561
	 * @return array<string,string|integer>
562
	 */
563
	private function generateUserParameter($userId) {
564
		return [
565
			'type'   => 'user',
566
			'id'     => $userId,
567
			'name'   => \OC::$server->getUserManager()
568
									->get($userId)
569
									->getDisplayName(),
570
			'parsed' => \OC::$server->getUserManager()
571
									->get($userId)
572
									->getDisplayName()
573
		];
574
	}
575
}
576