Completed
Push — master ( 041121...2f1837 )
by Maxence
02:46
created

CirclesService::onUserRemoved()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\Circles\Service;
28
29
30
use OCA\Circles\AppInfo\Application;
31
use OCA\Circles\Db\CirclesRequest;
32
use OCA\Circles\Db\FederatedLinksRequest;
33
use OCA\Circles\Db\MembersRequest;
34
use OCA\Circles\Exceptions\CircleAlreadyExistsException;
35
use OCA\Circles\Exceptions\CircleTypeDisabledException;
36
use OCA\Circles\Exceptions\FederatedCircleNotAllowedException;
37
use OCA\Circles\Exceptions\MemberDoesNotExistException;
38
use OCA\Circles\Exceptions\MemberIsNotOwnerException;
39
use OCA\Circles\Model\Circle;
40
use OCA\Circles\Model\Member;
41
use OCP\IL10N;
42
43
class CirclesService {
44
45
	/** @var string */
46
	private $userId;
47
48
	/** @var IL10N */
49
	private $l10n;
50
51
	/** @var ConfigService */
52
	private $configService;
53
54
	/** @var CirclesRequest */
55
	private $circlesRequest;
56
57
	/** @var MembersRequest */
58
	private $membersRequest;
59
60
	/** @var FederatedLinksRequest */
61
	private $federatedLinksRequest;
62
63
	/** @var EventsService */
64
	private $eventsService;
65
66
	/** @var MiscService */
67
	private $miscService;
68
69
70
	/**
71
	 * CirclesService constructor.
72
	 *
73
	 * @param string $userId
74
	 * @param IL10N $l10n
75
	 * @param ConfigService $configService
76
	 * @param CirclesRequest $circlesRequest
77
	 * @param MembersRequest $membersRequest
78
	 * @param FederatedLinksRequest $federatedLinksRequest
79
	 * @param EventsService $eventsService
80
	 * @param MiscService $miscService
81
	 */
82 View Code Duplication
	public function __construct(
83
		$userId,
84
		IL10N $l10n,
85
		ConfigService $configService,
86
		CirclesRequest $circlesRequest,
87
		MembersRequest $membersRequest,
88
		FederatedLinksRequest $federatedLinksRequest,
89
		EventsService $eventsService,
90
		MiscService $miscService
91
	) {
92
		$this->userId = $userId;
93
		$this->l10n = $l10n;
94
		$this->configService = $configService;
95
		$this->circlesRequest = $circlesRequest;
96
		$this->membersRequest = $membersRequest;
97
		$this->federatedLinksRequest = $federatedLinksRequest;
98
		$this->eventsService = $eventsService;
99
		$this->miscService = $miscService;
100
	}
101
102
103
	/**
104
	 * Create circle using this->userId as owner
105
	 *
106
	 * @param int|string $type
107
	 * @param string $name
108
	 *
109
	 * @return Circle
110
	 * @throws CircleTypeDisabledException
111
	 * @throws \Exception
112
	 */
113
	public function createCircle($type, $name) {
114
		self::convertTypeStringToBitValue($type);
115
		$type = (int)$type;
116
117
		if ($type === '') {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $type (integer) and '' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
118
			throw new CircleTypeDisabledException(
119
				$this->l10n->t('You need a specify a type of circle')
120
			);
121
		}
122
123
		if (!$this->configService->isCircleAllowed($type)) {
124
			throw new CircleTypeDisabledException(
125
				$this->l10n->t('You cannot create this type of circle')
126
			);
127
		}
128
129
		$circle = new Circle($type, $name);
130
131
		try {
132
			$this->circlesRequest->createCircle($circle, $this->userId);
133
			$this->membersRequest->createMember($circle->getOwner());
134
		} catch (CircleAlreadyExistsException $e) {
135
			throw $e;
136
		}
137
138
		$this->eventsService->onCircleCreation($circle);
139
140
		return $circle;
141
	}
142
143
144
	/**
145
	 * list Circles depends on type (or all) and name (parts) and minimum level.
146
	 *
147
	 * @param mixed $type
148
	 * @param string $name
149
	 * @param int $level
150
	 *
151
	 * @return Circle[]
152
	 * @throws CircleTypeDisabledException
153
	 */
154
	public function listCircles($type, $name = '', $level = 0) {
155
		self::convertTypeStringToBitValue($type);
156
157
		if (!$this->configService->isCircleAllowed((int)$type)) {
158
			throw new CircleTypeDisabledException(
159
				$this->l10n->t('You cannot display this type of circle')
160
			);
161
		}
162
163
		$data = [];
164
		$result = $this->circlesRequest->getCircles($this->userId, $type, $name, $level);
165
		foreach ($result as $item) {
166
			$data[] = $item;
167
		}
168
169
		return $data;
170
	}
171
172
173
	/**
174
	 * returns details on circle and its members if this->userId is a member itself.
175
	 *
176
	 * @param string $circleUniqueId
177
	 *
178
	 * @return Circle
179
	 * @throws \Exception
180
	]	 */
181
	public function detailsCircle($circleUniqueId) {
182
183
		try {
184
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
185
			if ($circle->getHigherViewer()
186
					   ->isLevel(Member::LEVEL_MEMBER)
187
			) {
188
				$this->detailsCircleMembers($circle);
189
				$this->detailsCircleLinkedGroups($circle);
190
				$this->detailsCircleFederatedCircles($circle);
191
			}
192
		} catch (\Exception $e) {
193
			throw $e;
194
		}
195
196
		return $circle;
197
	}
198
199
200
	/**
201
	 * get the Members list and add the result to the Circle.
202
	 *
203
	 * @param Circle $circle
204
	 */
205
	private function detailsCircleMembers(Circle &$circle) {
206
		$members =
207
			$this->membersRequest->getMembers($circle->getUniqueId(), $circle->getHigherViewer());
208
209
		$circle->setMembers($members);
210
	}
211
212
213
	/**
214
	 * get the Linked Group list and add the result to the Circle.
215
	 *
216
	 * @param Circle $circle
217
	 */
218
	private function detailsCircleLinkedGroups(Circle &$circle) {
219
		$groups = [];
220
		if ($this->configService->isLinkedGroupsAllowed()) {
221
			$groups =
222
				$this->membersRequest->getGroupsFromCircle(
223
					$circle->getUniqueId(), $circle->getHigherViewer()
224
				);
225
		}
226
227
		$circle->setGroups($groups);
228
	}
229
230
231
	/**
232
	 * get the Federated Circles list and add the result to the Circle.
233
	 *
234
	 * @param Circle $circle
235
	 */
236
	private function detailsCircleFederatedCircles(Circle &$circle) {
237
		$links = [];
238
239
		try {
240
			if ($this->configService->isFederatedCirclesAllowed()) {
241
				$circle->hasToBeFederated();
242
				$links = $this->federatedLinksRequest->getLinksFromCircle($circle->getUniqueId());
243
			}
244
		} catch (FederatedCircleNotAllowedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
245
		}
246
247
		$circle->setLinks($links);
248
	}
249
250
251
	/**
252
	 * save new settings if current user is admin.
253
	 *
254
	 * @param string $circleUniqueId
255
	 * @param array $settings
256
	 *
257
	 * @return Circle
258
	 * @throws \Exception
259
	 */
260
	public function settingsCircle($circleUniqueId, $settings) {
261
262
		try {
263
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
264
			$circle->getHigherViewer()
265
				   ->hasToBeOwner();
266
267
			$ak = array_keys($settings);
268
			foreach ($ak AS $k) {
269
				$circle->setSetting($k, $settings[$k]);
270
			}
271
272
			$this->circlesRequest->updateCircle($circle);
273
274
			$this->eventsService->onSettingsChange($circle);
275
		} catch (\Exception $e) {
276
			throw $e;
277
		}
278
279
		return $circle;
280
	}
281
282
283
	/**
284
	 * Join a circle.
285
	 *
286
	 * @param string $circleUniqueId
287
	 *
288
	 * @return null|Member
289
	 * @throws \Exception
290
	 */
291 View Code Duplication
	public function joinCircle($circleUniqueId) {
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...
292
293
		try {
294
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
295
296
			$member = $this->membersRequest->getFreshNewMember(
297
				$circleUniqueId, $this->userId, Member::TYPE_USER
298
			);
299
			$member->hasToBeAbleToJoinTheCircle();
300
			$member->joinCircle($circle->getType());
301
			$this->membersRequest->updateMember($member);
302
303
			$this->eventsService->onMemberNew($circle, $member);
304
		} catch (\Exception $e) {
305
			throw $e;
306
		}
307
308
		return $member;
309
	}
310
311
312
	/**
313
	 * Leave a circle.
314
	 *
315
	 * @param string $circleUniqueId
316
	 *
317
	 * @return null|Member
318
	 * @throws \Exception
319
	 */
320 View Code Duplication
	public function leaveCircle($circleUniqueId) {
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...
321
322
		try {
323
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
324
			$member = $circle->getViewer();
325
326
			$member->hasToBeMemberOrAlmost();
327
			$member->cantBeOwner();
328
329
			$this->eventsService->onMemberLeaving($circle, $member);
330
331
			$member->setStatus(Member::STATUS_NONMEMBER);
332
			$member->setLevel(Member::LEVEL_NONE);
333
			$this->membersRequest->updateMember($member);
334
		} catch (\Exception $e) {
335
			throw $e;
336
		}
337
338
		return $member;
339
	}
340
341
342
	/**
343
	 * destroy a circle.
344
	 *
345
	 * @param string $circleUniqueId
346
	 *
347
	 * @throws MemberIsNotOwnerException
348
	 */
349
	public function removeCircle($circleUniqueId) {
350
351
		try {
352
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
353
			$circle->getHigherViewer()
354
				   ->hasToBeOwner();
355
356
			$this->eventsService->onCircleDestruction($circle);
357
358
			$this->membersRequest->removeAllFromCircle($circleUniqueId);
359
			$this->circlesRequest->destroyCircle($circleUniqueId);
360
361
		} catch (MemberIsNotOwnerException $e) {
362
			throw $e;
363
		}
364
	}
365
366
367
	/**
368
	 * @param $circleName
369
	 *
370
	 * @return Circle|null
371
	 */
372
	public function infoCircleByName($circleName) {
373
		return $this->circlesRequest->forceGetCircleByName($circleName);
374
	}
375
376
377
	/**
378
	 * When a user is removed.
379
	 *
380
	 * @param $userId
381
	 */
382
	public function onUserRemoved($userId) {
383
		$this->switchOlderAdminToOwnerInCirclesOwnedByUser($userId);
384
	}
385
386
387
	/**
388
	 * switchOlderAdminToOwnerInCirclesOwnedByUser();
389
	 *
390
	 * Before deleting a user from the cloud, we assign a new owner to his Circles.
391
	 * Remove the Circle if it has no admin.
392
	 *
393
	 * @param string $userId
394
	 */
395
	private function switchOlderAdminToOwnerInCirclesOwnedByUser($userId) {
396
		$circles = $this->circlesRequest->getCircles($userId, 0, '', Member::LEVEL_OWNER);
397
398
		foreach ($circles as $circle) {
399
400
			$members =
401
				$this->membersRequest->forceGetMembers($circle->getUniqueId(), Member::LEVEL_ADMIN);
402
403
			if (sizeof($members) === 1) {
404
				$this->circlesRequest->destroyCircle($circle->getUniqueId());
405
				continue;
406
			}
407
408
			foreach ($members as $member) {
409
				if ($member->getLevel() === Member::LEVEL_ADMIN) {
410
					$member->setLevel(Member::LEVEL_OWNER);
411
					$this->membersRequest->updateMember($member);
412
					continue;
413
				}
414
			}
415
		}
416
	}
417
418
419
	/**
420
	 * Convert a Type in String to its Bit Value
421
	 *
422
	 * @param string $type
423
	 */
424
	public static function convertTypeStringToBitValue(&$type) {
425
		if (strtolower($type) === 'personal') {
426
			$type = Circle::CIRCLES_PERSONAL;
427
		}
428
		if (strtolower($type) === 'secret') {
429
			$type = Circle::CIRCLES_SECRET;
430
		}
431
		if (strtolower($type) === 'closed') {
432
			$type = Circle::CIRCLES_CLOSED;
433
		}
434
		if (strtolower($type) === 'public') {
435
			$type = Circle::CIRCLES_PUBLIC;
436
		}
437
		if (strtolower($type) === 'all') {
438
			$type = Circle::CIRCLES_ALL;
439
		}
440
	}
441
442
443
	/**
444
	 * getCircleIcon()
445
	 *
446
	 * Return the right imagePath for a type of circle.
447
	 *
448
	 * @param string $type
449
	 * @param bool $png
450
	 *
451
	 * @return string
452
	 */
453
	public static function getCircleIcon($type, $png = false) {
454
455
		$ext = '.svg';
456
		if ($png === true) {
457
			$ext = '.png';
458
		}
459
460
		$urlGen = \OC::$server->getURLGenerator();
461
		switch ($type) {
462
			case Circle::CIRCLES_PERSONAL:
463
				return $urlGen->getAbsoluteURL(
464
					$urlGen->imagePath(Application::APP_NAME, 'personal' . $ext)
465
				);
466
			case Circle::CIRCLES_CLOSED:
467
				return $urlGen->getAbsoluteURL(
468
					$urlGen->imagePath(Application::APP_NAME, 'closed' . $ext)
469
				);
470
			case Circle::CIRCLES_SECRET:
471
				return $urlGen->getAbsoluteURL(
472
					$urlGen->imagePath(Application::APP_NAME, 'secret' . $ext)
473
				);
474
			case Circle::CIRCLES_PUBLIC:
475
				return $urlGen->getAbsoluteURL(
476
					$urlGen->imagePath(Application::APP_NAME, 'public' . $ext)
477
				);
478
		}
479
480
		return $urlGen->getAbsoluteURL($urlGen->imagePath(Application::APP_NAME, 'black_circle' . $ext));
481
	}
482
483
}