Completed
Pull Request — master (#551)
by Maxence
01:54
created

CurrentUserService::getSingleCircle()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 9.536
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Service;
33
34
35
use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Logger;
36
use daita\MySmallPhpTools\Traits\TArrayTools;
37
use daita\MySmallPhpTools\Traits\TStringTools;
38
use OC\User\NoUserException;
39
use OCA\Circles\Db\CircleRequest;
40
use OCA\Circles\Db\MemberRequest;
41
use OCA\Circles\Db\MembershipRequest;
42
use OCA\Circles\Exceptions\CircleNotFoundException;
43
use OCA\Circles\Exceptions\UserTypeNotFoundException;
44
use OCA\Circles\Exceptions\ViewerNotFoundException;
45
use OCA\Circles\IMember;
46
use OCA\Circles\Model\Circle;
47
use OCA\Circles\Model\CurrentUser;
48
use OCA\Circles\Model\Member;
49
use OCA\Circles\Model\Membership;
50
use OCP\IUserManager;
51
52
53
/**
54
 * Class ViewerService
55
 *
56
 * @package OCA\Circles\Service
57
 */
58
class CurrentUserService {
59
60
61
	use TArrayTools;
62
	use TStringTools;
63
	use TNC21Logger;
64
65
66
	/** @var IUserManager */
67
	private $userManager;
68
69
	/** @var MembershipRequest */
70
	private $membershipRequest;
71
72
	/** @var CircleRequest */
73
	private $circleRequest;
74
75
	/** @var MemberRequest */
76
	private $memberRequest;
77
78
	/** @var ConfigService */
79
	private $configService;
80
81
82
	/** @var CurrentUser */
83
	private $currentUser = null;
84
85
	/** @var bool */
86
	private $bypass = false;
87
88
89
	/**
90
	 * ViewerService constructor.
91
	 *
92
	 * @param IUserManager $userManager
93
	 * @param MembershipRequest $membershipRequest
94
	 * @param CircleRequest $circleRequest
95
	 * @param MemberRequest $memberRequest
96
	 * @param ConfigService $configService
97
	 */
98
	public function __construct(
99
		IUserManager $userManager, MembershipRequest $membershipRequest, CircleRequest $circleRequest,
100
		MemberRequest $memberRequest, ConfigService $configService
101
	) {
102
		$this->userManager = $userManager;
103
		$this->membershipRequest = $membershipRequest;
104
		$this->circleRequest = $circleRequest;
105
		$this->memberRequest = $memberRequest;
106
		$this->configService = $configService;
107
	}
108
109
110
	/**
111
	 * @param string $userId
112
	 *
113
	 * @throws CircleNotFoundException
114
	 * @throws NoUserException
115
	 */
116
	public function setLocalViewer(string $userId): void {
117
		$this->currentUser = $this->createLocalCurrentUser($userId);
118
	}
119
120
	/**
121
	 * @param IMember $currentUser
122
	 *
123
	 * @throws CircleNotFoundException
124
	 */
125
	public function setCurrentUser(IMember $currentUser): void {
126
		if ($currentUser instanceof Member) {
127
			$tmp = new CurrentUser();
128
			$tmp->importFromIMember($currentUser);
129
			$currentUser = $tmp;
130
		}
131
132
//		if ($currentUser->getInstance() === '') {
133
//			$currentUser->setInstance($this->configService->getLocalInstance());
134
//		}
135
136
		$this->currentUser = $currentUser;
0 ignored issues
show
Documentation Bug introduced by
$currentUser is of type object<OCA\Circles\IMember>, but the property $currentUser was declared to be of type object<OCA\Circles\Model\CurrentUser>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
137
		$this->fillSingleCircleId($this->currentUser);
0 ignored issues
show
Compatibility introduced by
$this->currentUser of type object<OCA\Circles\IMember> is not a sub-type of object<OCA\Circles\Model\CurrentUser>. It seems like you assume a concrete implementation of the interface OCA\Circles\IMember to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
138
	}
139
140
	/**
141
	 * @return CurrentUser|null
142
	 */
143
	public function getCurrentUser(): ?CurrentUser {
144
		return $this->currentUser;
145
	}
146
147
	/**
148
	 * @return bool
149
	 */
150
	public function hasCurrentUser(): bool {
151
		return ($this->currentUser !== null);
152
	}
153
154
	/**
155
	 * @throws ViewerNotFoundException
156
	 */
157
	public function mustHaveCurrentUser(): void {
158
		if ($this->bypass) {
159
			return;
160
		}
161
		if (!$this->hasCurrentUser()) {
162
			throw new ViewerNotFoundException();
163
		}
164
	}
165
166
	/**
167
	 * @param bool $bypass
168
	 */
169
	public function bypassCurrentUserCondition(bool $bypass): void {
170
		$this->bypass = $bypass;
171
	}
172
173
174
	/**
175
	 * @param string $userId
176
	 *
177
	 * @return CurrentUser
178
	 * @throws CircleNotFoundException
179
	 * @throws NoUserException
180
	 */
181
	public function createLocalCurrentUser(string $userId): CurrentUser {
182
		$user = $this->userManager->get($userId);
183
		if ($user === null) {
184
			throw new NoUserException('user ' . $userId . ' not found');
185
		}
186
187
		$currentUser = new CurrentUser($user->getUID());
188
		$this->fillSingleCircleId($currentUser);
189
190
		return $currentUser;
191
	}
192
193
194
	/**
195
	 * @param string $userId
196
	 * @param int $userType
197
	 *
198
	 * @return CurrentUser
199
	 * @throws CircleNotFoundException
200
	 * @throws NoUserException
201
	 * @throws UserTypeNotFoundException
202
	 */
203
	public function createCurrentUser(string $userId, int $userType = Member::TYPE_USER): CurrentUser {
204
		switch ($userType) {
205
			case Member::TYPE_USER:
206
				return $this->createCurrentUserTypeUser($userId);
207
		}
208
209
		throw new UserTypeNotFoundException();
210
	}
211
212
	/**
213
	 * @param string $userId
214
	 *
215
	 * @return CurrentUser
216
	 * @throws CircleNotFoundException
217
	 * @throws NoUserException
218
	 */
219
	public function createCurrentUserTypeUser(string $userId): CurrentUser {
220
		$userId = trim($userId, '@');
221
		if (strpos($userId, '@') === false) {
222
			$instance = $this->configService->getLocalInstance();
223
		} else {
224
			list($userId, $instance) = explode('@', $userId);
225
		}
226
227
		if ($this->configService->isLocalInstance($instance)) {
228
			return $this->createLocalCurrentUser($userId);
229
		} else {
230
			return new CurrentUser($userId, $instance, Member::TYPE_USER);
231
		}
232
	}
233
234
235
236
237
	/**
238
	 * some ./occ commands allows to add a Viewer
239
	 *
240
	 * @param string $userId
241
	 * @param bool $bypass
242
	 *
243
	 * @throws CircleNotFoundException
244
	 * @throws NoUserException
245
	 */
246
	public function commandLineViewer(string $userId, bool $bypass = false) {
247
		if ($userId !== '') {
248
			$currentUser = $this->createCurrentUserTypeUser($userId);
249
			$this->setCurrentUser($currentUser);
250
		} elseif ($bypass) {
251
			$this->bypassCurrentUserCondition(true);
252
		}
253
	}
254
255
256
	/**
257
	 * TODO: Is it needed outside of CirclesList ?
258
	 *
259
	 * @param string $userId
260
	 * @param int $level
261
	 *
262
	 * @return Member
263
	 * @throws CircleNotFoundException
264
	 * @throws NoUserException
265
	 */
266
	public function createFilterMember(string $userId, int $level = Member::LEVEL_MEMBER): Member {
267
		$userId = trim($userId, ',');
268
		if (strpos($userId, ',') !== false) {
269
			list($userId, $level) = explode(',', $userId);
270
		}
271
272
		$currentUser = $this->createCurrentUserTypeUser($userId);
273
		$member = new Member();
274
		$member->importFromIMember($currentUser)
275
			   ->setLevel((int)$level);
276
277
		return $member;
278
	}
279
280
281
	/**
282
	 * @param CurrentUser $currentUser
283
	 *
284
	 * @throws CircleNotFoundException
285
	 */
286
	private function fillSingleCircleId(CurrentUser $currentUser): void {
287
		if ($currentUser->getId() !== '') {
288
			return;
289
		}
290
291
		// only if currentUser is from LocalInstance
292
		if ($this->configService->isLocalInstance($currentUser->getInstance())) {
293
			$circle = $this->getSingleCircle($currentUser);
294
			$currentUser->setId($circle->getId());
295
		}
296
	}
297
298
299
	/**
300
	 * @param CurrentUser $currentUser
301
	 *
302
	 * @return Circle
303
	 * @throws CircleNotFoundException
304
	 */
305
	public function getSingleCircle(CurrentUser $currentUser): Circle {
306
		try {
307
			return $this->circleRequest->getViewerCircle($currentUser);
308
		} catch (CircleNotFoundException $e) {
309
			$circle = new Circle();
310
			$id = $this->token(Circle::ID_LENGTH);
311
312
			$circle->setName('single:' . $currentUser->getUserId() . ':' . $id)
313
				   ->setId($id)
314
				   ->setConfig(Circle::CFG_SINGLE);
315
			$this->circleRequest->save($circle);
316
317
			$owner = new Member();
318
			$owner->importFromIMember($currentUser)
319
				  ->setLevel(Member::LEVEL_OWNER)
320
				  ->setCircleId($id)
321
				  ->setId($id)
322
				  ->setCachedName($owner->getUserId())
323
				  ->setStatus('Member');
324
			$this->memberRequest->save($owner);
325
		}
326
327
		return $this->circleRequest->getViewerCircle($currentUser);
328
	}
329
330
331
	/**
332
	 * @param CurrentUser $currentUser
333
	 *
334
	 * @return Membership[]
335
	 */
336
	public function generateMemberships(CurrentUser $currentUser): array {
337
		$circles = $this->circleRequest->getCircles(null, $currentUser);
338
		$memberships = [];
339
		foreach ($circles as $circle) {
340
			$viewer = $circle->getViewer();
341
			if (!$viewer->isMember()) {
342
				continue;
343
			}
344
345
			$viewer = $circle->getViewer();
346
			$memberships[] = new Membership(
347
				$viewer->getId(), $circle->getId(), $currentUser->getId(), $viewer->getLevel()
348
			);
349
350
//			$newUser = new CurrentUser($circle->getId(), Member::TYPE_CIRCLE, '');
351
//			$circles = $this->circleRequest->getCircles(null, $currentUser);
352
		}
353
354
		return $memberships;
355
	}
356
357
358
	/**
359
	 * @param CurrentUser|null $currentUser
360
	 */
361
	public function updateMemberships(?CurrentUser $currentUser = null) {
362
		if (is_null($currentUser)) {
363
			$currentUser = $this->getCurrentUser();
364
		} else {
365
			$currentUser->setMemberships($this->membershipRequest->getMemberships($currentUser));
0 ignored issues
show
Documentation introduced by
$currentUser is of type object<OCA\Circles\Model\CurrentUser>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
366
		}
367
368
		if (is_null($currentUser)) {
369
			return;
370
		}
371
372
		$last = $this->generateMemberships($currentUser);
373
374
		echo 'known: ' . json_encode($currentUser->getMemberships()) . "\n";
375
		echo 'last: ' . json_encode($last) . "\n";
376
377
//
378
//		$circles = $this->circleRequest->getCircles(null, $viewer);
379
//		foreach ($circles as $circle) {
380
//			$viewer = $circle->getViewer();
381
//			if (!$viewer->isMember()) {
382
//				continue;
383
//			}
384
//
385
//			echo 'new member: ' . json_encode($viewer) . "\n";
386
////			$this->currentUserService->updateMembership($circle);
387
//		}
388
389
390
	}
391
392
}
393
394