Completed
Pull Request — master (#347)
by Maxence
02:22
created

DavService::onDeleteCard()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
4
/**
5
 * Circles - Bring cloud-users closer together.
6
 *
7
 * This file is licensed under the Affero General Public License version 3 or
8
 * later. See the COPYING file.
9
 *
10
 * @author Maxence Lange <[email protected]>
11
 * @copyright 2017
12
 * @license GNU AGPL version 3 or any later version
13
 *
14
 * This program is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License as
16
 * published by the Free Software Foundation, either version 3 of the
17
 * License, or (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License
25
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
26
 *
27
 */
28
29
30
namespace OCA\Circles\Service;
31
32
33
use OCA\Circles\Db\CirclesRequest;
34
use OCA\Circles\Db\MembersRequest;
35
use OCA\Circles\Exceptions\CircleAlreadyExistsException;
36
use OCA\Circles\Exceptions\CircleDoesNotExistException;
37
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
38
use OCA\Circles\Exceptions\MemberDoesNotExistException;
39
use OCA\Circles\Exceptions\NotLocalMemberException;
40
use OCA\Circles\Model\Circle;
41
use OCA\Circles\Model\DavCard;
42
use OCA\Circles\Model\Member;
43
use OCP\IUserManager;
44
use Symfony\Component\EventDispatcher\GenericEvent;
45
46
47
/**
48
 * Class DavService
49
 *
50
 * @package OCA\Circles\Service
51
 */
52
class DavService {
53
54
55
	/** @var string */
56
	private $userId;
57
58
	/** @var IUserManager */
59
	private $userManager;
60
61
	/** @var CirclesRequest */
62
	private $circlesRequest;
63
64
	/** @var MembersRequest */
65
	private $membersRequest;
66
67
	/** @var ConfigService */
68
	private $configService;
69
70
	/** @var MiscService */
71
	private $miscService;
72
73
74
	/**
75
	 * TimezoneService constructor.
76
	 *
77
	 * @param string $userId
78
	 * @param IUserManager $userManager
79
	 * @param CirclesRequest $circlesRequest
80
	 * @param MembersRequest $membersRequest
81
	 * @param ConfigService $configService
82
	 * @param MiscService $miscService
83
	 */
84 View Code Duplication
	public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
85
		$userId, IUserManager $userManager, CirclesRequest $circlesRequest, MembersRequest $membersRequest,
86
		ConfigService $configService, MiscService $miscService
87
	) {
88
		$this->userId = $userId;
89
		$this->userManager = $userManager;
90
		$this->circlesRequest = $circlesRequest;
91
		$this->membersRequest = $membersRequest;
92
		$this->configService = $configService;
93
		$this->miscService = $miscService;
94
	}
95
96
97
	/**
98
	 * @param GenericEvent $event
99
	 */
100
	public function onCreateCard(GenericEvent $event) {
101
		$davCard = $this->generateDavCard($event);
102
		$this->updateDavCard($davCard);
103
	}
104
105
106
	/**
107
	 * @param GenericEvent $event
108
	 */
109
	public function onUpdateCard(GenericEvent $event) {
110
		$davCard = $this->generateDavCard($event);
111
		$this->updateDavCard($davCard);
112
	}
113
114
115
	/**
116
	 * @param GenericEvent $event
117
	 */
118
	public function onDeleteCard(GenericEvent $event) {
119
		$addressBookId = $event->getArgument('addressBookId');
0 ignored issues
show
Unused Code introduced by
$addressBookId is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
120
		$cardUri = $event->getArgument('cardUri');
0 ignored issues
show
Unused Code introduced by
$cardUri is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
121
	}
122
123
124
	/**
125
	 * @param GenericEvent $event
126
	 *
127
	 * @return DavCard
128
	 */
129
	private function generateDavCard(GenericEvent $event): DavCard {
130
		$addressBookId = $event->getArgument('addressBookId');
131
		$cardUri = $event->getArgument('cardUri');
132
		$cardData = $event->getArgument('cardData');
133
134
		$davCard = new DavCard();
135
		$davCard->importFromDav($cardData);
136
		$davCard->setAddressBookId($addressBookId);
137
		$davCard->setCardUri($cardUri);
138
139
		return $davCard;
140
	}
141
142
143
	/**
144
	 * @param DavCard $davCard
145
	 */
146
	private function updateDavCard(DavCard $davCard) {
147
		$this->miscService->log('Updating Card: ' . json_encode($davCard));
148
		$this->manageCircles($davCard);
149
		$this->manageContactMembers($davCard);
150
	}
151
152
153
	/**
154
	 * @param DavCard $davCard
155
	 *
156
	 * @return Member[]
157
	 */
158
	private function manageContactMembers(DavCard $davCard): array {
159
		$circles = array_map(
160
			function(Circle $circle) {
161
				return $circle->getUniqueId();
162
			}, $davCard->getCircles()
163
		);
164
165
		try {
166
			$userId = $this->isLocalMember($davCard);
167
168
			return $this->manageLocalMembers($circles, $davCard, $userId);
169
		} catch (NotLocalMemberException $e) {
170
			return $this->manageRemoteMembers($circles, $davCard);
171
		}
172
	}
173
174
175
	/**
176
	 * @param array $circles
177
	 * @param DavCard $davCard
178
	 * @param string $userId
179
	 *
180
	 * @return Member[]
181
	 */
182
	private function manageLocalMembers(array $circles, DavCard $davCard, string $userId): array {
183
		// remove all remote members
184
		$this->membersRequest->removeContactMembers($davCard->getContactId(), Member::TYPE_CONTACT);
185
		// remove local members with different userid and deprecated circles
186 View Code Duplication
		foreach ($this->membersRequest->getLocalContactMembers($davCard->getContactId()) as $member) {
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
			if ($member->getUserId() !== $userId || !in_array($member->getCircleId(), $circles)
188
			) {
189
				$this->membersRequest->removeMember($member);
190
			}
191
		}
192
193
		// generate members
194
		$members = [];
195
		foreach ($davCard->getCircles() as $circle) {
196
			$members[] = $this->manageMember($davCard->getContactId(), $circle, $userId, Member::TYPE_USER);
197
		}
198
199
		return $members;
200
	}
201
202
203
	/**
204
	 * @param array $circles
205
	 * @param DavCard $davCard
206
	 *
207
	 * @return Member[]
208
	 */
209
	private function manageRemoteMembers(array $circles, DavCard $davCard): array {
210
		// remove all local members
211
		$this->membersRequest->removeContactMembers($davCard->getContactId(), Member::TYPE_USER);
212
		// remove deprecated mail address & deprecated circles
213 View Code Duplication
		foreach ($this->membersRequest->getMembersByContactId($davCard->getContactId()) as $member) {
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...
214
215
			if (!in_array($member->getUserId(), $davCard->getEmails())
216
				|| !in_array($member->getCircleId(), $circles)
217
			) {
218
				$this->membersRequest->removeMember($member);
219
			}
220
		}
221
222
		$members = [];
223
		foreach ($davCard->getEmails() as $email) {
224
			foreach ($davCard->getCircles() as $circle) {
225
				$members[] =
226
					$this->manageMember($davCard->getContactId(), $circle, $email, Member::TYPE_CONTACT);
227
			}
228
		}
229
230
		return $members;
231
	}
232
233
234
	/**
235
	 * @param string $contactId
236
	 * @param Circle $circle
237
	 * @param string $userId
238
	 * @param int $type
239
	 *
240
	 * @return Member
241
	 */
242
	private function manageMember(string $contactId, Circle $circle, string $userId, int $type) {
243
		try {
244
			$member = $this->membersRequest->getContactMember(
245
				$circle->getUniqueId(), $contactId, $userId, $type
246
			);
247
		} catch (MemberDoesNotExistException $e) {
248
			$member = new Member();
249
			$member->setLevel(Member::LEVEL_MEMBER);
250
			$member->setStatus(Member::STATUS_MEMBER);
251
			$member->setContactId($contactId);
252
			$member->setType($type);
253
			$member->setCircleId($circle->getUniqueId());
254
			$member->setUserId($userId);
255
256
			try {
257
				$this->membersRequest->createMember($member);
258
			} catch (MemberAlreadyExistsException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
259
			}
260
		}
261
262
		return $member;
263
	}
264
265
266
	/**
267
	 * @param DavCard $davCard
268
	 *
269
	 * @return string
270
	 * @throws NotLocalMemberException
271
	 */
272
	private function isLocalMember(DavCard $davCard): string {
273
		foreach ($davCard->getEmails() as $email) {
274
			if (strpos($email, '@') === false) {
275
				continue;
276
			}
277
278
			list ($username, $domain) = explode('@', $email);
279
			if (in_array($domain, $this->configService->getAvailableHosts())) {
280
				$user = $this->userManager->get($username);
281
				if ($user !== null) {
282
					return $user->getUID();
283
				}
284
			}
285
		}
286
287
		throw new NotLocalMemberException();
288
	}
289
290
291
	/**
292
	 * @param DavCard $davCard
293
	 */
294
	private function manageCircles(DavCard $davCard) {
295
		$fromCard = $davCard->getGroups();
296
		$current = array_map(
297
			function(Circle $circle) {
298
				return $circle->getContactGroupName();
299
			}, $this->getCirclesFromBook($davCard->getAddressBookId())
300
		);
301
302
		$this->manageNewCircles($davCard->getAddressBookId(), $fromCard, $current);
303
		$this->manageDeprecatedCircles($fromCard, $current);
0 ignored issues
show
Unused Code introduced by
The call to the method OCA\Circles\Service\DavS...nageDeprecatedCircles() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
304
305
		$this->assignCirclesToCard($davCard);
306
	}
307
308
309
	/**
310
	 * @param int $bookId
311
	 * @param array $fromCard
312
	 * @param array $current
313
	 */
314
	private function manageNewCircles(int $bookId, array $fromCard, array $current) {
315
		foreach ($fromCard as $group) {
316
			if (in_array($group, $current)) {
317
				continue;
318
			}
319
			
320
			$circle = new Circle(Circle::CIRCLES_PUBLIC, $group . ' - ' . $this->uuid(5));
0 ignored issues
show
Deprecated Code introduced by
The method OCA\Circles\Service\DavService::uuid() has been deprecated.

This method has been deprecated.

Loading history...
321
			$circle->setContactAddressBook($bookId);
322
			$circle->setContactGroupName($group);
323
324
			try {
325
				$this->circlesRequest->createCircle($circle, $this->userId);
326
				$member = new Member($this->userId, Member::TYPE_USER, $circle->getUniqueId());
327
				$member->setLevel(Member::LEVEL_OWNER);
328
				$member->setStatus(Member::STATUS_MEMBER);
329
330
				try {
331
					$this->membersRequest->createMember($member);
332
				} catch (MemberAlreadyExistsException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
333
				}
334
			} catch (CircleAlreadyExistsException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
335
			}
336
337
		}
338
	}
339
340
341
	/**
342
	 * // TODO: Get all group from an addressbook
343
	 * // TODO: remove deprecated circles
344
	 *
345
	 * @param array $fromCard
346
	 * @param array $current
347
	 */
348
	private function manageDeprecatedCircles(array $fromCard, array $current) {
0 ignored issues
show
Unused Code introduced by
The parameter $fromCard is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $current is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
349
	}
350
351
352
	/**
353
	 * @param DavCard $davCard
354
	 */
355
	private function assignCirclesToCard(DavCard $davCard) {
356
		foreach ($davCard->getGroups() as $group) {
357
			try {
358
				$davCard->addCircle(
359
					$this->circlesRequest->getFromContactGroup($davCard->getAddressBookId(), $group)
360
				);
361
			} catch (CircleDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
362
			}
363
		}
364
	}
365
366
367
	/**
368
	 * @param int $addressBookId
369
	 *
370
	 * @return Circle[]
371
	 */
372
	private function getCirclesFromBook(int $addressBookId): array {
373
		return $this->circlesRequest->getFromBook($addressBookId);
374
	}
375
376
377
	/**
378
	 * @param int $length
379
	 *
380
	 * @return string
381
	 * @deprecated
382
	 */
383
	protected function uuid(int $length = 0): string {
384
		$uuid = sprintf(
385
			'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff),
386
			mt_rand(0, 0xffff), mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
387
			mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
388
		);
389
390
		if ($length > 0) {
391
			if ($length <= 16) {
392
				$uuid = str_replace('-', '', $uuid);
393
			}
394
395
			$uuid = substr($uuid, 0, $length);
396
		}
397
398
		return $uuid;
399
	}
400
401
402
}
403
404
405