Completed
Pull Request — master (#551)
by Maxence
02:27
created

FederatedUserService::createFederatedUser()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 2
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\InitiatorNotFoundException;
44
use OCA\Circles\Exceptions\OwnerNotFoundException;
45
use OCA\Circles\Exceptions\UserTypeNotFoundException;
46
use OCA\Circles\IFederatedUser;
47
use OCA\Circles\Model\Circle;
48
use OCA\Circles\Model\FederatedUser;
49
use OCA\Circles\Model\Member;
50
use OCA\Circles\Model\Membership;
51
use OCP\IUserManager;
52
53
54
/**
55
 * Class FederatedUserService
56
 *
57
 * @package OCA\Circles\Service
58
 */
59
class FederatedUserService {
60
61
62
	use TArrayTools;
63
	use TStringTools;
64
	use TNC21Logger;
65
66
67
	/** @var IUserManager */
68
	private $userManager;
69
70
	/** @var MembershipRequest */
71
	private $membershipRequest;
72
73
	/** @var CircleRequest */
74
	private $circleRequest;
75
76
	/** @var MemberRequest */
77
	private $memberRequest;
78
79
	/** @var ConfigService */
80
	private $configService;
81
82
83
	/** @var FederatedUser */
84
	private $currentUser = null;
85
86
	/** @var bool */
87
	private $bypass = false;
88
89
90
	/**
91
	 * FederatedUserService constructor.
92
	 *
93
	 * @param IUserManager $userManager
94
	 * @param MembershipRequest $membershipRequest
95
	 * @param CircleRequest $circleRequest
96
	 * @param MemberRequest $memberRequest
97
	 * @param ConfigService $configService
98
	 */
99
	public function __construct(
100
		IUserManager $userManager, MembershipRequest $membershipRequest, CircleRequest $circleRequest,
101
		MemberRequest $memberRequest, ConfigService $configService
102
	) {
103
		$this->userManager = $userManager;
104
		$this->membershipRequest = $membershipRequest;
105
		$this->circleRequest = $circleRequest;
106
		$this->memberRequest = $memberRequest;
107
		$this->configService = $configService;
108
	}
109
110
111
	/**
112
	 * @param string $userId
113
	 *
114
	 * @throws CircleNotFoundException
115
	 * @throws NoUserException
116
	 */
117
	public function setLocalInitiator(string $userId): void {
118
		$this->currentUser = $this->createLocalFederatedUser($userId);
119
	}
120
121
	/**
122
	 * @param IFederatedUser $federatedUser
123
	 *
124
	 * @throws CircleNotFoundException
125
	 */
126
	public function setCurrentUser(IFederatedUser $federatedUser): void {
127
		if (!($federatedUser instanceof FederatedUser)) {
128
			$tmp = new FederatedUser();
129
			$tmp->importFromIFederatedUser($federatedUser);
130
			$federatedUser = $tmp;
131
		}
132
133
		$this->fillSingleCircleId($federatedUser);
134
		$this->currentUser = $federatedUser;
135
	}
136
137
	/**
138
	 * @return FederatedUser|null
139
	 */
140
	public function getCurrentUser(): ?FederatedUser {
141
		return $this->currentUser;
142
	}
143
144
	/**
145
	 * @return bool
146
	 */
147
	public function hasCurrentUser(): bool {
148
		return ($this->currentUser !== null);
149
	}
150
151
	/**
152
	 * @throws InitiatorNotFoundException
153
	 */
154
	public function mustHaveCurrentUser(): void {
155
		if ($this->bypass) {
156
			return;
157
		}
158
		if (!$this->hasCurrentUser()) {
159
			throw new InitiatorNotFoundException();
160
		}
161
	}
162
163
	/**
164
	 * @param bool $bypass
165
	 */
166
	public function bypassCurrentUserCondition(bool $bypass): void {
167
		$this->bypass = $bypass;
168
	}
169
170
171
	/**
172
	 * @param string $userId
173
	 *
174
	 * @return FederatedUser
175
	 * @throws CircleNotFoundException
176
	 * @throws NoUserException
177
	 */
178
	public function createLocalFederatedUser(string $userId): FederatedUser {
179
		$user = $this->userManager->get($userId);
180
		if ($user === null) {
181
			throw new NoUserException('user ' . $userId . ' not found');
182
		}
183
184
		$federatedUser = new FederatedUser();
185
		$federatedUser->set($user->getUID());
186
		$this->fillSingleCircleId($federatedUser);
187
188
		return $federatedUser;
189
	}
190
191
192
	/**
193
	 * @param string $federatedId
194
	 * @param int $userType
195
	 *
196
	 * @return FederatedUser
197
	 * @throws CircleNotFoundException
198
	 * @throws NoUserException
199
	 * @throws UserTypeNotFoundException
200
	 */
201
	public function createFederatedUser(string $federatedId, int $userType = Member::TYPE_USER
202
	): FederatedUser {
203
		switch ($userType) {
204
			case Member::TYPE_USER:
205
				return $this->createFederatedUserTypeUser($federatedId);
206
		}
207
208
		throw new UserTypeNotFoundException();
209
	}
210
211
	/**
212
	 * @param string $userId
213
	 *
214
	 * @return FederatedUser
215
	 * @throws CircleNotFoundException
216
	 * @throws NoUserException
217
	 */
218
	public function createFederatedUserTypeUser(string $userId): FederatedUser {
219
		$userId = trim($userId, '@');
220
		if (strpos($userId, '@') === false) {
221
			$instance = $this->configService->getLocalInstance();
222
		} else {
223
			list($userId, $instance) = explode('@', $userId);
224
		}
225
226
		if ($this->configService->isLocalInstance($instance)) {
227
			return $this->createLocalFederatedUser($userId);
228
		} else {
229
			$federatedUser = new FederatedUser();
230
			$federatedUser->set($userId, $instance, Member::TYPE_USER);
231
232
			return $federatedUser;
233
		}
234
	}
235
236
237
	/**
238
	 * some ./occ commands allows to add an Initiator
239
	 * TODO: manage non-user type
240
	 *
241
	 * @param string $userId
242
	 * @param string $circleId
243
	 * @param bool $bypass
244
	 *
245
	 * @throws CircleNotFoundException
246
	 * @throws NoUserException
247
	 * @throws OwnerNotFoundException
248
	 */
249
	public function commandLineInitiator(string $userId, string $circleId = '', bool $bypass = false) {
250
		if ($userId !== '') {
251
			$this->setCurrentUser($this->createFederatedUserTypeUser($userId));
252
253
			return;
254
		}
255
256
		if ($circleId !== '') {
257
			$localCircle = $this->circleRequest->getCircle($circleId);
258
			if ($this->configService->isLocalInstance($localCircle->getInstance())) {
259
				// TODO: manage NO_OWNER circles
260
				$this->setCurrentUser($localCircle->getOwner());
261
262
				return;
263
			}
264
		}
265
266
		if (!$bypass) {
267
			throw new CircleNotFoundException(
268
				'This Circle is not managed from this instance, please use --initiator'
269
			);
270
		}
271
272
		$this->bypassCurrentUserCondition($bypass);
273
	}
274
275
276
	/**
277
	 * TODO: Is it needed outside of CirclesList ?
278
	 *
279
	 * @param string $userId
280
	 * @param int $level
281
	 *
282
	 * @return Member
283
	 * @throws CircleNotFoundException
284
	 * @throws NoUserException
285
	 */
286
	public function createFilterMember(string $userId, int $level = Member::LEVEL_MEMBER): Member {
287
		$userId = trim($userId, ',');
288
		if (strpos($userId, ',') !== false) {
289
			list($userId, $level) = explode(',', $userId);
290
		}
291
292
		$federatedUser = $this->createFederatedUserTypeUser($userId);
293
		$member = new Member();
294
		$member->importFromIFederatedUser($federatedUser);
295
		$member->setLevel((int)$level);
296
297
		return $member;
298
	}
299
300
301
	/**
302
	 * @param FederatedUser $federatedUser
303
	 *
304
	 * @throws CircleNotFoundException
305
	 */
306
	private function fillSingleCircleId(FederatedUser $federatedUser): void {
307
		if ($federatedUser->getSingleId() !== '') {
308
			return;
309
		}
310
311
		// only if currentUser is from LocalInstance
312
		if ($this->configService->isLocalInstance($federatedUser->getInstance())) {
313
			$circle = $this->getSingleCircle($federatedUser);
314
			$federatedUser->setSingleId($circle->getId());
315
		}
316
	}
317
318
319
	/**
320
	 * @param FederatedUser $federatedUser
321
	 *
322
	 * @return Circle
323
	 * @throws CircleNotFoundException
324
	 */
325
	public function getSingleCircle(FederatedUser $federatedUser): Circle {
326
		try {
327
			return $this->circleRequest->getInitiatorCircle($federatedUser);
328
		} catch (CircleNotFoundException $e) {
329
			$circle = new Circle();
330
			$id = $this->token(Circle::ID_LENGTH);
331
332
			$circle->setName('single:' . $federatedUser->getUserId() . ':' . $id)
333
				   ->setId($id)
334
				   ->setConfig(Circle::CFG_SINGLE);
335
			$this->circleRequest->save($circle);
336
337
			$owner = new Member();
338
			$owner->importFromIFederatedUser($federatedUser);
339
			$owner->setLevel(Member::LEVEL_OWNER)
340
				  ->setCircleId($id)
341
				  ->setId($id)
342
				  ->setCachedName($owner->getUserId())
343
				  ->setStatus('Member');
344
			$this->memberRequest->save($owner);
345
		}
346
347
		return $this->circleRequest->getInitiatorCircle($federatedUser);
348
	}
349
350
351
	/**
352
	 * @param FederatedUser $federatedUser
353
	 *
354
	 * @return Membership[]
355
	 */
356
	public function generateMemberships(FederatedUser $federatedUser): array {
357
		$circles = $this->circleRequest->getCircles(null, $federatedUser);
358
		$memberships = [];
359
		foreach ($circles as $circle) {
360
			$initiator = $circle->getInitiator();
361
			if (!$initiator->isMember()) {
362
				continue;
363
			}
364
365
			$memberships[] = new Membership(
366
				$initiator->getId(), $circle->getId(), $federatedUser->getSingleId(), $initiator->getLevel()
367
			);
368
369
//			$newUser = new CurrentUser($circle->getId(), Member::TYPE_CIRCLE, '');
370
//			$circles = $this->circleRequest->getCircles(null, $currentUser);
371
		}
372
373
		return $memberships;
374
	}
375
376
377
	/**
378
	 * @param FederatedUser|null $federatedUser
379
	 */
380
	public function updateMemberships(?FederatedUser $federatedUser = null) {
381
		if (is_null($federatedUser)) {
382
			$federatedUser = $this->getCurrentUser();
383
		} else {
384
			$federatedUser->setMemberships($this->membershipRequest->getMemberships($federatedUser));
0 ignored issues
show
Documentation introduced by
$federatedUser is of type object<OCA\Circles\Model\FederatedUser>, 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...
385
		}
386
387
		if (is_null($federatedUser)) {
388
			return;
389
		}
390
391
		$last = $this->generateMemberships($federatedUser);
392
393
		echo 'known: ' . json_encode($federatedUser->getMemberships()) . "\n";
394
		echo 'last: ' . json_encode($last) . "\n";
395
396
//
397
//		$circles = $this->circleRequest->getCircles(null, $viewer);
398
//		foreach ($circles as $circle) {
399
//			$viewer = $circle->getViewer();
400
//			if (!$viewer->isMember()) {
401
//				continue;
402
//			}
403
//
404
//			echo 'new member: ' . json_encode($viewer) . "\n";
405
////			$this->federatedUserService->updateMembership($circle);
406
//		}
407
408
409
	}
410
411
}
412
413