%PDF- %PDF-
Direktori : /www/varak.net/nextcloud.varak.net/apps_old/apps/circles/lib/FederatedItems/ |
Current File : //www/varak.net/nextcloud.varak.net/apps_old/apps/circles/lib/FederatedItems/SingleMemberAdd.php |
<?php declare(strict_types=1); /** * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Circles\FederatedItems; use OCA\Circles\Db\MemberRequest; use OCA\Circles\Exceptions\CircleNotFoundException; use OCA\Circles\Exceptions\FederatedItemBadRequestException; use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\FederatedItemNotFoundException; use OCA\Circles\Exceptions\FederatedItemRemoteException; use OCA\Circles\Exceptions\FederatedItemServerException; use OCA\Circles\Exceptions\FederatedUserException; use OCA\Circles\Exceptions\FederatedUserNotFoundException; use OCA\Circles\Exceptions\InvalidIdException; use OCA\Circles\Exceptions\MemberNotFoundException; use OCA\Circles\Exceptions\MembersLimitException; use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RemoteInstanceException; use OCA\Circles\Exceptions\RemoteNotFoundException; use OCA\Circles\Exceptions\RemoteResourceNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\SingleCircleNotFoundException; use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\Exceptions\UserTypeNotFoundException; use OCA\Circles\IFederatedItem; use OCA\Circles\IFederatedItemAsyncProcess; use OCA\Circles\IFederatedItemHighSeverity; use OCA\Circles\IFederatedItemMemberCheckNotRequired; use OCA\Circles\IFederatedItemMemberRequired; use OCA\Circles\Model\Circle; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\Helpers\MemberHelper; use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\EventService; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; use OCA\Circles\Service\MembershipService; use OCA\Circles\Service\RemoteStreamService; use OCA\Circles\StatusCode; use OCA\Circles\Tools\Traits\TDeserialize; use OCA\Circles\Tools\Traits\TNCLogger; use OCA\Circles\Tools\Traits\TStringTools; use OCP\IUserManager; /** * Class SingleMemberAdd * * @package OCA\Circles\FederatedItems */ class SingleMemberAdd implements IFederatedItem, IFederatedItemAsyncProcess, IFederatedItemHighSeverity, IFederatedItemMemberRequired, IFederatedItemMemberCheckNotRequired { use TDeserialize; use TStringTools; use TNCLogger; public function __construct( protected IUserManager $userManager, protected MemberRequest $memberRequest, protected FederatedUserService $federatedUserService, protected RemoteStreamService $remoteStreamService, protected CircleService $circleService, protected MemberService $memberService, protected MembershipService $membershipService, protected EventService $eventService, protected ConfigService $configService ) { } /** * @param FederatedEvent $event * * @throws FederatedItemBadRequestException * @throws FederatedItemNotFoundException * @throws FederatedItemServerException * @throws FederatedItemRemoteException * @throws FederatedItemException * @throws RequestBuilderException */ public function verify(FederatedEvent $event): void { $member = $event->getMember(); $circle = $event->getCircle(); $initiator = $circle->getInitiator(); $initiatorHelper = new MemberHelper($initiator); if (!$circle->isConfig(Circle::CFG_FRIEND)) { $initiatorHelper->mustBeModerator(); } $member = $this->generateMember($event, $circle, $member); $event->setMembers([$member]); $event->setOutcome($this->serialize($member)); $this->eventService->memberPreparing($event); } /** * @param FederatedEvent $event * * @throws InvalidIdException * @throws RemoteNotFoundException * @throws RequestBuilderException * @throws UnknownRemoteException */ public function manage(FederatedEvent $event): void { $member = $event->getMember(); if (!$this->memberService->insertOrUpdate($member)) { return; } if ($member->getStatus() === Member::STATUS_INVITED) { $this->eventService->memberInviting($event); } else { $this->eventService->memberAdding($event); } $this->membershipService->updatePopulation($event->getCircle()); } /** * @param FederatedEvent $event * @param array $results */ public function result(FederatedEvent $event, array $results): void { $member = $event->getMember(); if ($member->getStatus() === Member::STATUS_INVITED) { $this->eventService->memberInvited($event, $results); } else { $this->eventService->memberAdded($event, $results); } } /** * @param FederatedEvent $event * @param Circle $circle * @param Member $member * * @return Member * @throws CircleNotFoundException * @throws FederatedItemBadRequestException * @throws FederatedItemException * @throws FederatedUserException * @throws FederatedUserNotFoundException * @throws InvalidIdException * @throws MembersLimitException * @throws OwnerNotFoundException * @throws RemoteInstanceException * @throws RemoteNotFoundException * @throws RemoteResourceNotFoundException * @throws SingleCircleNotFoundException * @throws UnknownRemoteException * @throws UserTypeNotFoundException * @throws RequestBuilderException */ protected function generateMember(FederatedEvent $event, Circle $circle, Member $member): Member { try { if ($member->getSingleId() !== '') { $userId = $member->getSingleId() . '@' . $member->getInstance(); $federatedUser = $this->federatedUserService->getFederatedUser($userId, Member::TYPE_SINGLE); } else { $userId = $member->getUserId() . '@' . $member->getInstance(); $federatedUser = $this->federatedUserService->getFederatedUser( $userId, $member->getUserType() ); } } catch (MemberNotFoundException $e) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[120], 120); } $allowedTypes = $this->configService->getAppValueInt(ConfigService::ALLOWED_TYPES); if ($federatedUser->getUserType() < Member::TYPE_APP && ($allowedTypes & $federatedUser->getUserType()) === 0) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[132], 132); } if ($federatedUser->getBasedOn()->isConfig(Circle::CFG_ROOT)) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[125], 125); } if ($circle->isConfig(Circle::CFG_LOCAL) && $federatedUser->getUserType() === Member::TYPE_CIRCLE && !$federatedUser->getBasedOn()->isConfig(Circle::CFG_LOCAL)) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[131], 131); } if ($member->getSingleId() === $circle->getSingleId()) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[128], 128); } if (!$this->configService->isLocalInstance($member->getInstance())) { if ($circle->isConfig(Circle::CFG_LOCAL)) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[126], 126); } if (!$circle->isConfig(Circle::CFG_FEDERATED)) { $remoteInstance = $this->remoteStreamService->getCachedRemoteInstance($member->getInstance()); if ($remoteInstance->getType() !== RemoteInstance::TYPE_GLOBALSCALE) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[127], 127); } } } $member->importFromIFederatedUser($federatedUser); $member->setCircleId($circle->getSingleId()); $member->setCircle($circle); $this->confirmPatron($event, $member); $this->manageMemberStatus($circle, $member); $this->circleService->confirmCircleNotFull($circle); // The idea is that adding the member during the self::verify() will help during the broadcasting // of the event to Federated RemoteInstance for their first member. $this->memberRequest->insertOrUpdate($member); return $member; } /** * @param Circle $circle * @param Member $member * * @throws FederatedItemBadRequestException * @throws RequestBuilderException */ private function manageMemberStatus(Circle $circle, Member $member) { try { $knownMember = $this->memberRequest->searchMember($member); $member->setId($knownMember->getId()); if ($knownMember->getLevel() === Member::LEVEL_NONE) { switch ($knownMember->getStatus()) { case Member::STATUS_BLOCKED: if ($circle->isConfig(Circle::CFG_INVITE)) { $member->setStatus(Member::STATUS_INVITED); } return; case Member::STATUS_REQUEST: $member->setLevel(Member::LEVEL_MEMBER); $member->setStatus(Member::STATUS_MEMBER); return; case Member::STATUS_INVITED: throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[123], 123); } } throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[122], 122); } catch (MemberNotFoundException $e) { $member->setId($this->token(ManagedModel::ID_LENGTH)); if ($circle->isConfig(Circle::CFG_INVITE) && $member->getUserType() !== Member::TYPE_MAIL && $member->getUserType() !== Member::TYPE_CONTACT) { $member->setStatus(Member::STATUS_INVITED); } else { $member->setLevel(Member::LEVEL_MEMBER); $member->setStatus(Member::STATUS_MEMBER); } } } /** * @param FederatedEvent $event * @param Member $member * * @throws FederatedItemBadRequestException * @throws FederatedUserException * @throws RemoteNotFoundException * @throws RequestBuilderException * @throws UnknownRemoteException */ private function confirmPatron(FederatedEvent $event, Member $member): void { if (!$member->hasInvitedBy()) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[129], 129); } $patron = $member->getInvitedBy(); if ($patron->getInstance() !== $event->getSender()) { throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[130], 130); } $this->federatedUserService->confirmSingleIdUniqueness($patron); } }