Completed
Pull Request — master (#625)
by Maxence
02:28
created

MemberService::insertOrUpdate()   A

Complexity

Conditions 2
Paths 5

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 2
nc 5
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\Model\SimpleDataStore;
36
use daita\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger;
37
use daita\MySmallPhpTools\Traits\TArrayTools;
38
use daita\MySmallPhpTools\Traits\TStringTools;
39
use OCA\Circles\Db\CircleRequest;
40
use OCA\Circles\Db\MemberRequest;
41
use OCA\Circles\Exceptions\CircleNotFoundException;
42
use OCA\Circles\Exceptions\ContactAddressBookNotFoundException;
43
use OCA\Circles\Exceptions\ContactFormatException;
44
use OCA\Circles\Exceptions\ContactNotFoundException;
45
use OCA\Circles\Exceptions\FederatedEventException;
46
use OCA\Circles\Exceptions\FederatedItemException;
47
use OCA\Circles\Exceptions\FederatedUserException;
48
use OCA\Circles\Exceptions\InitiatorNotConfirmedException;
49
use OCA\Circles\Exceptions\InitiatorNotFoundException;
50
use OCA\Circles\Exceptions\InvalidIdException;
51
use OCA\Circles\Exceptions\MemberNotFoundException;
52
use OCA\Circles\Exceptions\OwnerNotFoundException;
53
use OCA\Circles\Exceptions\RemoteInstanceException;
54
use OCA\Circles\Exceptions\RemoteNotFoundException;
55
use OCA\Circles\Exceptions\RemoteResourceNotFoundException;
56
use OCA\Circles\Exceptions\RequestBuilderException;
57
use OCA\Circles\Exceptions\SingleCircleNotFoundException;
58
use OCA\Circles\Exceptions\UnknownRemoteException;
59
use OCA\Circles\FederatedItems\MassiveMemberAdd;
60
use OCA\Circles\FederatedItems\MemberLevel;
61
use OCA\Circles\FederatedItems\MemberRemove;
62
use OCA\Circles\FederatedItems\SingleMemberAdd;
63
use OCA\Circles\IFederatedUser;
64
use OCA\Circles\Model\Federated\FederatedEvent;
65
use OCA\Circles\Model\FederatedUser;
66
use OCA\Circles\Model\Member;
67
68
69
/**
70
 * Class MemberService
71
 *
72
 * @package OCA\Circles\Service
73
 */
74
class MemberService {
75
76
77
	use TArrayTools;
78
	use TStringTools;
79
	use TNC22Logger;
80
81
82
	/** @var CircleRequest */
83
	private $circleRequest;
84
85
	/** @var MemberRequest */
86
	private $memberRequest;
87
88
	/** @var FederatedUserService */
89
	private $federatedUserService;
90
91
	/** @var MembershipService */
92
	private $membershipService;
93
94
	/** @var FederatedEventService */
95
	private $federatedEventService;
96
97
	/** @var RemoteStreamService */
98
	private $remoteStreamService;
99
100
101
	/**
102
	 * MemberService constructor.
103
	 *
104
	 * @param CircleRequest $circleRequest
105
	 * @param MemberRequest $memberRequest
106
	 * @param FederatedUserService $federatedUserService
107
	 * @param FederatedEventService $federatedEventService
108
	 * @param RemoteStreamService $remoteStreamService
109
	 */
110 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...
111
		CircleRequest $circleRequest,
112
		MemberRequest $memberRequest,
113
		FederatedUserService $federatedUserService,
114
		MembershipService $membershipService,
115
		FederatedEventService $federatedEventService,
116
		RemoteStreamService $remoteStreamService
117
	) {
118
		$this->circleRequest = $circleRequest;
119
		$this->memberRequest = $memberRequest;
120
		$this->federatedUserService = $federatedUserService;
121
		$this->membershipService = $membershipService;
122
		$this->federatedEventService = $federatedEventService;
123
		$this->remoteStreamService = $remoteStreamService;
124
	}
125
126
//
127
//	/**
128
//	 * @param Member $member
129
//	 *
130
//	 * @throws MemberAlreadyExistsException
131
//	 */
132
//	public function saveMember(Member $member) {
133
//		$member->setId($this->token(Member::ID_LENGTH));
134
//		$this->memberRequest->save($member);
135
//	}
136
//
137
138
139
	/**
140
	 * @param string $memberId
141
	 * @param string $circleId
142
	 * @param bool $canBeVisitor
143
	 *
144
	 * @return Member
145
	 * @throws InitiatorNotFoundException
146
	 * @throws MemberNotFoundException
147
	 * @throws RequestBuilderException
148
	 */
149
	public function getMemberById(
150
		string $memberId,
151
		string $circleId = '',
152
		bool $canBeVisitor = false
153
	): Member {
154
		$this->federatedUserService->mustHaveCurrentUser();
155
156
		$member =
157
			$this->memberRequest->getMemberById(
158
				$memberId,
159
				$this->federatedUserService->getCurrentUser(),
160
				$canBeVisitor
161
			);
162
		if ($circleId !== '' && $member->getCircle()->getSingleId() !== $circleId) {
163
			throw new MemberNotFoundException();
164
		}
165
166
		return $member;
167
	}
168
169
170
	/**
171
	 * @param string $circleId
172
	 *
173
	 * @return Member[]
174
	 * @throws InitiatorNotFoundException
175
	 * @throws RequestBuilderException
176
	 */
177
	public function getMembers(string $circleId): array {
178
		$this->federatedUserService->mustHaveCurrentUser();
179
180
		return $this->memberRequest->getMembers(
181
			$circleId,
182
			$this->federatedUserService->getCurrentUser(),
183
			$this->federatedUserService->getRemoteInstance()
184
		);
185
	}
186
187
188
	/**
189
	 * @param string $circleId
190
	 * @param FederatedUser $federatedUser
191
	 *
192
	 * @return array
193
	 * @throws CircleNotFoundException
194
	 * @throws FederatedEventException
195
	 * @throws FederatedItemException
196
	 * @throws InitiatorNotConfirmedException
197
	 * @throws InitiatorNotFoundException
198
	 * @throws OwnerNotFoundException
199
	 * @throws RemoteInstanceException
200
	 * @throws RemoteNotFoundException
201
	 * @throws RemoteResourceNotFoundException
202
	 * @throws RequestBuilderException
203
	 * @throws UnknownRemoteException
204
	 * @throws ContactAddressBookNotFoundException
205
	 * @throws ContactFormatException
206
	 * @throws ContactNotFoundException
207
	 * @throws FederatedUserException
208
	 * @throws InvalidIdException
209
	 * @throws SingleCircleNotFoundException
210
	 */
211
	public function addMember(string $circleId, FederatedUser $federatedUser): array {
212
		$this->federatedUserService->mustHaveCurrentUser();
213
		$circle = $this->circleRequest->getCircle($circleId, $this->federatedUserService->getCurrentUser());
214
215
		$member = new Member();
216
		$member->importFromIFederatedUser($federatedUser);
217
218
		$this->federatedUserService->setMemberPatron($member);
219
220
		$event = new FederatedEvent(SingleMemberAdd::class);
221
		$event->setCircle($circle);
222
		$event->setMember($member);
223
224
		$this->federatedEventService->newEvent($event);
225
226
		return $event->getOutcome();
227
	}
228
229
230
	/**
231
	 * @param string $circleId
232
	 * @param IFederatedUser[] $members
0 ignored issues
show
Bug introduced by
There is no parameter named $members. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
233
	 *
234
	 * @return FederatedUser[]
235
	 * @throws CircleNotFoundException
236
	 * @throws FederatedEventException
237
	 * @throws FederatedItemException
238
	 * @throws InitiatorNotConfirmedException
239
	 * @throws InitiatorNotFoundException
240
	 * @throws OwnerNotFoundException
241
	 * @throws RemoteNotFoundException
242
	 * @throws RemoteResourceNotFoundException
243
	 * @throws UnknownRemoteException
244
	 * @throws RemoteInstanceException
245
	 * @throws RequestBuilderException
246
	 */
247
	public function addMembers(string $circleId, array $federatedUsers): array {
248
		$this->federatedUserService->mustHaveCurrentUser();
249
		$circle = $this->circleRequest->getCircle($circleId, $this->federatedUserService->getCurrentUser());
250
251
		if ($this->federatedUserService->isInitiatedByOcc()) {
252
			$patron = $this->federatedUserService->getAppInitiator('occ', Member::APP_OCC);
253
		} else {
254
			$patron = $this->federatedUserService->getCurrentUser();
255
		}
256
257
		$members = array_map(
258
			function(FederatedUser $federatedUser) use ($patron) {
259
				$member = new Member();
260
				$member->importFromIFederatedUser($federatedUser);
261
				$member->setInvitedBy($patron);
0 ignored issues
show
Bug introduced by
It seems like $patron defined by $this->federatedUserService->getCurrentUser() on line 254 can be null; however, OCA\Circles\Model\Member::setInvitedBy() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
262
263
				return $member;
264
			}, $federatedUsers
265
		);
266
267
		$event = new FederatedEvent(MassiveMemberAdd::class);
268
		$event->setCircle($circle);
269
		$event->setMembers($members);
270
		$event->setParams(new SimpleDataStore(['federatedUsers' => $members]));
271
272
		$this->federatedEventService->newEvent($event);
273
274
		return $event->getOutcome();
275
	}
276
277
278
	/**
279
	 * @param string $memberId
280
	 *
281
	 * @return array
282
	 * @throws FederatedEventException
283
	 * @throws FederatedItemException
284
	 * @throws InitiatorNotConfirmedException
285
	 * @throws InitiatorNotFoundException
286
	 * @throws MemberNotFoundException
287
	 * @throws OwnerNotFoundException
288
	 * @throws RemoteNotFoundException
289
	 * @throws RemoteResourceNotFoundException
290
	 * @throws UnknownRemoteException
291
	 * @throws RequestBuilderException
292
	 */
293
	public function removeMember(string $memberId): array {
294
		$this->federatedUserService->mustHaveCurrentUser();
295
		$member =
296
			$this->memberRequest->getMemberById($memberId, $this->federatedUserService->getCurrentUser());
297
298
		$event = new FederatedEvent(MemberRemove::class);
299
		$event->setCircle($member->getCircle());
300
		$event->setMember($member);
301
302
		$this->federatedEventService->newEvent($event);
303
304
		return $event->getOutcome();
305
	}
306
307
	/**
308
	 * @param string $memberId
309
	 * @param int $level
310
	 *
311
	 * @return array
312
	 * @throws FederatedEventException
313
	 * @throws InitiatorNotConfirmedException
314
	 * @throws InitiatorNotFoundException
315
	 * @throws MemberNotFoundException
316
	 * @throws OwnerNotFoundException
317
	 * @throws RemoteNotFoundException
318
	 * @throws RemoteResourceNotFoundException
319
	 * @throws UnknownRemoteException
320
	 * @throws FederatedItemException
321
	 * @throws RequestBuilderException
322
	 */
323
	public function memberLevel(string $memberId, int $level): array {
324
		$this->federatedUserService->mustHaveCurrentUser();
325
		$member =
326
			$this->memberRequest->getMemberById($memberId, $this->federatedUserService->getCurrentUser());
327
328
		$event = new FederatedEvent(MemberLevel::class);
329
		$event->setCircle($member->getCircle());
330
		$event->setMember($member);
331
		$event->setParams(new SimpleDataStore(['level' => $level]));
332
333
		$this->federatedEventService->newEvent($event);
334
335
		return $event->getOutcome();
336
	}
337
338
339
	/**
340
	 * @param Member $member
341
	 *
342
	 * @return bool
343
	 * @throws InvalidIdException
344
	 * @throws RemoteNotFoundException
345
	 * @throws RequestBuilderException
346
	 * @throws UnknownRemoteException
347
	 */
348
	public function insertOrUpdate(Member $member): bool {
349
		try {
350
			$this->federatedUserService->confirmSingleIdUniqueness($member);
351
352
			$member->setNoteObj('invitedBy', $member->getInvitedBy());
353
354
			$this->memberRequest->insertOrUpdate($member);
355
			$this->membershipService->onUpdate($member->getSingleId());
356
		} catch (FederatedUserException $e) {
357
			$this->e($e, ['member' => $member]);
358
359
			return false;
360
		}
361
362
		return true;
363
	}
364
365
}
366
367