Passed
Push — master ( 9b1b62...011405 )
by Julius
02:56 queued 10s
created

DeckProvider   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 320
Duplicated Lines 19.38 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
wmc 58
lcom 1
cbo 11
dl 62
loc 320
rs 4.5599
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
F parse() 6 80 16
A setSubjects() 0 16 4
B getIcon() 21 25 8
A parseParamForBoard() 0 11 2
A parseParamForStack() 0 10 2
A parseParamForAttachment() 0 11 2
A parseParamForAssignedUser() 0 11 3
A parseParamForLabel() 7 10 2
A parseParamForAcl() 7 19 4
A parseParamForComment() 0 16 3
A parseParamForDuedate() 0 15 3
B parseParamForChanges() 21 31 7
A deckUrl() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DeckProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DeckProvider, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2018 Julius Härtl <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2019 Alexandru Puiu <[email protected]>
6
 *
7
 * @author Julius Härtl <[email protected]>
8
 *
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
26
namespace OCA\Deck\Activity;
27
28
29
use cogpowered\FineDiff\Diff;
30
use OCA\Deck\Db\Acl;
31
use OCP\Activity\IEvent;
32
use OCP\Activity\IProvider;
33
use OCP\Comments\IComment;
34
use OCP\Comments\ICommentsManager;
35
use OCP\Comments\NotFoundException;
36
use OCP\IConfig;
37
use OCP\IURLGenerator;
38
use OCP\IUserManager;
39
use OCP\L10N\IFactory;
40
41
class DeckProvider implements IProvider {
42
43
	/** @var string */
44
	private $userId;
45
	/** @var IURLGenerator */
46
	private $urlGenerator;
47
	/** @var ActivityManager */
48
	private $activityManager;
49
	/** @var IUserManager */
50
	private $userManager;
51
	/** @var ICommentsManager */
52
	private $commentsManager;
53
	/** @var IFactory */
54
	private $l10nFactory;
55
	/** @var IConfig */
56
	private $config;
57
58
	public function __construct(IURLGenerator $urlGenerator, ActivityManager $activityManager, IUserManager $userManager, ICommentsManager $commentsManager, IFactory $l10n, IConfig $config, $userId) {
59
		$this->userId = $userId;
60
		$this->urlGenerator = $urlGenerator;
61
		$this->activityManager = $activityManager;
62
		$this->commentsManager = $commentsManager;
63
		$this->userManager = $userManager;
64
		$this->l10nFactory = $l10n;
65
		$this->config = $config;
66
	}
67
68
	/**
69
	 * @param string $language The language which should be used for translating, e.g. "en"
70
	 * @param IEvent $event The current event which should be parsed
71
	 * @param IEvent|null $previousEvent A potential previous event which you can combine with the current one.
72
	 *                                   To do so, simply use setChildEvent($previousEvent) after setting the
73
	 *                                   combined subject on the current event.
74
	 * @return IEvent
75
	 * @throws \InvalidArgumentException Should be thrown if your provider does not know this event
76
	 * @since 11.0.0
77
	 */
78
	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
79
		if ($event->getApp() !== 'deck') {
80
			throw new \InvalidArgumentException();
81
		}
82
83
		$event = $this->getIcon($event);
84
85
		$subjectIdentifier = $event->getSubject();
86
		$subjectParams = $event->getSubjectParameters();
87
		$ownActivity = ($event->getAuthor() === $this->userId);
88
89
		/**
90
		 * Map stored parameter objects to rich string types
91
		 */
92
93
		$author = $event->getAuthor();
94
		// get author if
95
		if (($author === '' || $author === ActivityManager::DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED) && array_key_exists('author', $subjectParams)) {
96
			$author = $subjectParams['author'];
97
			unset($subjectParams['author']);
98
		}
99
		$user = $this->userManager->get($author);
100
		if ($user !== null) {
101
			$params = [
102
				'user' => [
103
					'type' => 'user',
104
					'id' => $author,
105
					'name' => $user !== null ? $user->getDisplayName() : $author
106
				],
107
			];
108
			$event->setAuthor($author);
109
		}
110
		if ($event->getObjectType() === ActivityManager::DECK_OBJECT_BOARD) {
111 View Code Duplication
			if (isset($subjectParams['board']) && $event->getObjectName() === '') {
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...
112
				$event->setObject($event->getObjectType(), $event->getObjectId(), $subjectParams['board']['title']);
113
			}
114
			$board = [
115
				'type' => 'highlight',
116
				'id' => $event->getObjectId(),
117
				'name' => $event->getObjectName(),
118
				'link' => $this->deckUrl('/board/' . $event->getObjectId()),
119
			];
120
			$params['board'] = $board;
0 ignored issues
show
Bug introduced by
The variable $params does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
121
		}
122
123
		if (isset($subjectParams['card']) && $event->getObjectType() === ActivityManager::DECK_OBJECT_CARD) {
124 View Code Duplication
			if ($event->getObjectName() === '') {
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...
125
				$event->setObject($event->getObjectType(), $event->getObjectId(), $subjectParams['card']['title']);
126
			}
127
			$card = [
128
				'type' => 'highlight',
129
				'id' => $event->getObjectId(),
130
				'name' => $event->getObjectName(),
131
			];
132
133
			if (array_key_exists('board', $subjectParams)) {
134
				$archivedParam = $subjectParams['card']['archived'] ? 'archived' : '';
135
				$card['link'] = $this->deckUrl('/board/' . $subjectParams['board']['id'] . '/' . $archivedParam . '/card/' . $event->getObjectId());
136
			}
137
			$params['card'] = $card;
138
		}
139
140
		$params = $this->parseParamForBoard('board', $subjectParams, $params);
141
		$params = $this->parseParamForStack('stack', $subjectParams, $params);
142
		$params = $this->parseParamForStack('stackBefore', $subjectParams, $params);
143
		$params = $this->parseParamForAttachment('attachment', $subjectParams, $params);
144
		$params = $this->parseParamForLabel($subjectParams, $params);
145
		$params = $this->parseParamForAssignedUser($subjectParams, $params);
146
		$params = $this->parseParamForAcl($subjectParams, $params);
147
		$params = $this->parseParamForChanges($subjectParams, $params, $event);
148
		$params = $this->parseParamForComment($subjectParams, $params, $event);
149
		$params = $this->parseParamForDuedate($subjectParams, $params, $event);
150
151
		try {
152
			$subject = $this->activityManager->getActivityFormat($subjectIdentifier, $subjectParams, $ownActivity);
153
			$this->setSubjects($event, $subject, $params);
154
		} catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
155
		}
156
		return $event;
157
	}
158
159
	/**
160
	 * @param IEvent $event
161
	 * @param string $subject
162
	 * @param array $parameters
163
	 */
164
	protected function setSubjects(IEvent $event, $subject, array $parameters) {
165
		$placeholders = $replacements = $richParameters = [];
166
		foreach ($parameters as $placeholder => $parameter) {
167
			$placeholders[] = '{' . $placeholder . '}';
168
			if (is_array($parameter) && array_key_exists('name', $parameter)) {
169
				$replacements[] = $parameter['name'];
170
				$richParameters[$placeholder] = $parameter;
171
			} else {
172
				$replacements[] = '';
173
			}
174
		}
175
176
		$event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
177
			->setRichSubject($subject, $richParameters);
178
		$event->setSubject($subject, $parameters);
179
	}
180
181
	private function getIcon(IEvent $event) {
182
		$event->setIcon($this->urlGenerator->imagePath('deck', 'deck-dark.svg'));
183 View Code Duplication
		if (strpos($event->getSubject(), '_update') !== false) {
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...
184
			$event->setIcon($this->urlGenerator->imagePath('files', 'change.svg'));
185
		}
186 View Code Duplication
		if (strpos($event->getSubject(), '_create') !== false) {
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...
187
			$event->setIcon($this->urlGenerator->imagePath('files', 'add-color.svg'));
188
		}
189 View Code Duplication
		if (strpos($event->getSubject(), '_delete') !== false) {
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...
190
			$event->setIcon($this->urlGenerator->imagePath('files', 'delete-color.svg'));
191
		}
192 View Code Duplication
		if (strpos($event->getSubject(), 'archive') !== false) {
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...
193
			$event->setIcon($this->urlGenerator->imagePath('deck', 'archive.svg'));
194
		}
195 View Code Duplication
		if (strpos($event->getSubject(), '_restore') !== false) {
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...
196
			$event->setIcon($this->urlGenerator->imagePath('core', 'actions/history.svg'));
197
		}
198 View Code Duplication
		if (strpos($event->getSubject(), 'attachment_') !== false) {
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...
199
			$event->setIcon($this->urlGenerator->imagePath('core', 'places/files.svg'));
200
		}
201 View Code Duplication
		if (strpos($event->getSubject(), 'comment_') !== false) {
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...
202
			$event->setIcon($this->urlGenerator->imagePath('core', 'actions/comment.svg'));
203
		}
204
		return $event;
205
	}
206
207
	private function parseParamForBoard($paramName, $subjectParams, $params) {
208
		if (array_key_exists($paramName, $subjectParams)) {
209
			$params[$paramName] = [
210
				'type' => 'highlight',
211
				'id' => $subjectParams[$paramName]['id'],
212
				'name' => $subjectParams[$paramName]['title'],
213
				'link' => $this->deckUrl('/board/' . $subjectParams[$paramName]['id'] . '/'),
214
			];
215
		}
216
		return $params;
217
	}
218
	private function parseParamForStack($paramName, $subjectParams, $params) {
219
		if (array_key_exists($paramName, $subjectParams)) {
220
			$params[$paramName] = [
221
				'type' => 'highlight',
222
				'id' => $subjectParams[$paramName]['id'],
223
				'name' => $subjectParams[$paramName]['title'],
224
			];
225
		}
226
		return $params;
227
	}
228
229
	private function parseParamForAttachment($paramName, $subjectParams, $params) {
230
		if (array_key_exists($paramName, $subjectParams)) {
231
			$params[$paramName] = [
232
				'type' => 'highlight',
233
				'id' => $subjectParams[$paramName]['id'],
234
				'name' => $subjectParams[$paramName]['data'],
235
				'link' => $this->urlGenerator->linkToRoute('deck.attachment.display', ['cardId' => $subjectParams['card']['id'], 'attachmentId' => $subjectParams['attachment']['id']]),
236
			];
237
		}
238
		return $params;
239
	}
240
241
	private function parseParamForAssignedUser($subjectParams, $params) {
242
		if (array_key_exists('assigneduser', $subjectParams)) {
243
			$user = $this->userManager->get($subjectParams['assigneduser']);
244
			$params['assigneduser'] = [
245
				'type' => 'user',
246
				'id' => $subjectParams['assigneduser'],
247
				'name' => $user !== null ? $user->getDisplayName() : $subjectParams['assigneduser']
248
			];
249
		}
250
		return $params;
251
	}
252
253
	private function parseParamForLabel($subjectParams, $params) {
254 View Code Duplication
		if (array_key_exists('label', $subjectParams)) {
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...
255
			$params['label'] = [
256
				'type' => 'highlight',
257
				'id' => $subjectParams['label']['id'],
258
				'name' => $subjectParams['label']['title']
259
			];
260
		}
261
		return $params;
262
	}
263
264
	private function parseParamForAcl($subjectParams, $params) {
265
		if (array_key_exists('acl', $subjectParams)) {
266
			if ($subjectParams['acl']['type'] === Acl::PERMISSION_TYPE_USER) {
267
				$user = $this->userManager->get($subjectParams['acl']['participant']);
268
				$params['acl'] = [
269
					'type' => 'user',
270
					'id' => $subjectParams['acl']['participant'],
271
					'name' => $user !== null ? $user->getDisplayName() : $subjectParams['acl']['participant']
272
				];
273 View Code Duplication
			} else {
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...
274
				$params['acl'] = [
275
					'type' => 'highlight',
276
					'id' => $subjectParams['acl']['participant'],
277
					'name' => $subjectParams['acl']['participant']
278
				];
279
			}
280
		}
281
		return $params;
282
	}
283
284
	private function parseParamForComment($subjectParams, $params, IEvent $event) {
285
		if (array_key_exists('comment', $subjectParams)) {
286
			/** @var IComment $comment */
287
			try {
288
				$comment = $this->commentsManager->get((int)$subjectParams['comment']);
289
				$event->setParsedMessage($comment->getMessage());
290
				$params['comment'] =[
291
					'type' => 'highlight',
292
					'id' => $subjectParams['comment'],
293
					'name' => $comment->getMessage()
294
				];
295
			} catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
296
			}
297
		}
298
		return $params;
299
	}
300
301
	private function parseParamForDuedate($subjectParams, $params, IEvent $event) {
302
		if (array_key_exists('after', $subjectParams) && $event->getSubject() === ActivityManager::SUBJECT_CARD_UPDATE_DUEDATE) {
303
			$userLanguage = $this->config->getUserValue($event->getAuthor(), 'core', 'lang', $this->l10nFactory->findLanguage());
304
			$userLocale = $this->config->getUserValue($event->getAuthor(), 'core', 'locale', $this->l10nFactory->findLocale());
305
			$l10n = $this->l10nFactory->get('deck', $userLanguage, $userLocale);
306
			$date = new \DateTime($subjectParams['after']);
307
			$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
308
			$params['after'] = [
309
				'type' => 'highlight',
310
				'id' => 'dt:' . $subjectParams['after'],
311
				'name' => $l10n->l('datetime', $date)
312
			];
313
		}
314
		return $params;
315
	}
316
317
	/**
318
	 * Add diff to message if the subject parameter 'diff' is set, otherwise
319
	 * the changed values are added to before/after
320
	 *
321
	 * @param $subjectParams
322
	 * @param $params
323
	 * @return mixed
324
	 */
325
	private function parseParamForChanges($subjectParams, $params, $event) {
326
		if (array_key_exists('diff', $subjectParams) && $subjectParams['diff']) {
327
			$diff = new Diff();
328
			// Don't add diff as message since we are limited to 255 chars here
329
			//$event->setMessage($subjectParams['after']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
90% 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...
330
			$event->setParsedMessage('<pre class="visualdiff">' . $diff->render($subjectParams['before'], $subjectParams['after']) . '</pre>');
331
			return $params;
332
		}
333 View Code Duplication
		if (array_key_exists('before', $subjectParams)) {
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...
334
			$params['before'] = [
335
				'type' => 'highlight',
336
				'id' => $subjectParams['before'],
337
				'name' => $subjectParams['before']
338
			];
339
		}
340 View Code Duplication
		if (array_key_exists('after', $subjectParams)) {
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...
341
			$params['after'] = [
342
				'type' => 'highlight',
343
				'id' => $subjectParams['after'],
344
				'name' => $subjectParams['after']
345
			];
346
		}
347 View Code Duplication
		if (array_key_exists('card', $subjectParams) && $event->getSubject() === ActivityManager::SUBJECT_CARD_UPDATE_TITLE) {
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...
348
			$params['card'] = [
349
				'type' => 'highlight',
350
				'id' => $subjectParams['after'],
351
				'name' => $subjectParams['after']
352
			];
353
		}
354
		return $params;
355
	}
356
357
	public function deckUrl($endpoint) {
358
		return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#!' . $endpoint;
359
	}
360
}
361