From ce45b71c5b59e17cc9883d925004cfd00fa91c9e Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Sun, 7 Feb 2021 11:46:22 -0100 Subject: [PATCH] async and more Signed-off-by: Maxence Lange --- lib/Command/MembersLevel.php | 10 +- lib/Command/MembersRemove.php | 45 +++-- lib/Controller/RemoteController.php | 10 +- lib/Db/CoreQueryBuilder.php | 8 + lib/Db/MemberRequest.php | 60 ++++++- .../MemberAlreadyExistsException.php | 13 +- lib/Exceptions/MemberHelperException.php | 43 +++++ lib/Exceptions/MemberLevelException.php | 8 +- lib/FederatedItems/CircleCreate.php | 2 + lib/FederatedItems/MemberAdd.php | 28 ++- lib/FederatedItems/MemberLevel.php | 135 +++++++------- lib/FederatedItems/MemberRemove.php | 106 +++++++++++ lib/IFederatedItemAsync.php | 43 +++++ lib/Model/Circle.php | 8 +- lib/Model/Federated/FederatedEvent.php | 12 +- lib/Model/Helpers/MemberHelper.php | 168 ++++++++++++++++++ lib/Model/ManagedModel.php | 3 + lib/Model/Member.php | 52 +++++- lib/Service/CircleService.php | 6 +- lib/Service/FederatedEventService.php | 21 ++- lib/Service/FederatedUserService.php | 3 +- lib/Service/MemberService.php | 51 ++++-- lib/Service/RemoteDownstreamService.php | 45 +++-- lib/Service/RemoteUpstreamService.php | 24 +-- toto.json | 107 ++++------- 25 files changed, 756 insertions(+), 255 deletions(-) create mode 100644 lib/Exceptions/MemberHelperException.php create mode 100644 lib/FederatedItems/MemberRemove.php create mode 100644 lib/IFederatedItemAsync.php create mode 100644 lib/Model/Helpers/MemberHelper.php diff --git a/lib/Command/MembersLevel.php b/lib/Command/MembersLevel.php index bcd7e46e5..b3b6f7e51 100644 --- a/lib/Command/MembersLevel.php +++ b/lib/Command/MembersLevel.php @@ -35,6 +35,7 @@ use OC\Core\Command\Base; use OC\User\NoUserException; use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Model\Member; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; use Symfony\Component\Console\Input\InputArgument; @@ -104,13 +105,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $input->getOption('initiator'), $member->getCircleId() ); - $level = $this->memberService->parseLevelString($input->getArgument('level')); - $this->memberService->memberLevel($memberId, $level); + $level = Member::parseLevelString($input->getArgument('level')); + $outcome = $this->memberService->memberLevel($memberId, $level); -// $member = $this->membersRequest->forceGetMember( -// $member->getCircleId(), $member->getUserId(), DeprecatedMember::TYPE_USER, $member->getInstance() -// ); - echo json_encode($member, JSON_PRETTY_PRINT) . "\n"; + echo json_encode($outcome, JSON_PRETTY_PRINT) . "\n"; return 0; } diff --git a/lib/Command/MembersRemove.php b/lib/Command/MembersRemove.php index 9cf979444..aa9762199 100644 --- a/lib/Command/MembersRemove.php +++ b/lib/Command/MembersRemove.php @@ -1,4 +1,6 @@ -l10n = $l10n; - $this->membersService = $membersService; + $this->memberRequest = $memberRequest; + $this->federatedUserService = $federatedUserService; + $this->memberService = $memberService; } @@ -71,7 +83,8 @@ protected function configure() { parent::configure(); $this->setName('circles:members:remove') ->setDescription('remove a member from a circle') - ->addArgument('member_id', InputArgument::REQUIRED, 'ID of the member to be expel'); + ->addArgument('member_id', InputArgument::REQUIRED, 'ID of the member from the Circle') + ->addOption('initiator', '', InputOption::VALUE_REQUIRED, 'set an initiator to the request', ''); } @@ -86,8 +99,14 @@ protected function configure() { protected function execute(InputInterface $input, OutputInterface $output): int { $memberId = $input->getArgument('member_id'); - $member = $this->membersService->getMemberById($memberId); - $this->membersService->removeMember($member->getCircleId(), $member->getUserId(), $member->getType(), $member->getInstance(), true); + $member = $this->memberRequest->getMember($memberId); + $this->federatedUserService->commandLineInitiator( + $input->getOption('initiator'), $member->getCircleId() + ); + + $outcome = $this->memberService->removeMember($memberId); + + echo json_encode($outcome, JSON_PRETTY_PRINT) . "\n"; return 0; } diff --git a/lib/Controller/RemoteController.php b/lib/Controller/RemoteController.php index fb07a6312..660af8f49 100644 --- a/lib/Controller/RemoteController.php +++ b/lib/Controller/RemoteController.php @@ -31,6 +31,7 @@ namespace OCA\Circles\Controller; +use daita\MySmallPhpTools\Exceptions\InvalidItemException; use daita\MySmallPhpTools\Exceptions\InvalidOriginException; use daita\MySmallPhpTools\Exceptions\MalformedArrayException; use daita\MySmallPhpTools\Exceptions\SignatoryException; @@ -39,6 +40,7 @@ use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Controller; use Exception; use OCA\Circles\Db\CircleRequest; +use OCA\Circles\Exceptions\FederatedEventDSyncException; use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Federated\RemoteInstance; @@ -116,7 +118,9 @@ public function event(): DataResponse { $this->remoteDownstreamService->requestedEvent($event); } catch (FederatedItemException $e) { $this->e($e, ['event' => $event]); - $event->setReadingOutcome($e->getMessage(), $e->getParams(), false); + $event->setReadingOutcome($e->getMessage(), $e->getParams(), true); + } catch (FederatedEventDSyncException $e) { + return $this->fail($e, [], Http::STATUS_CONFLICT); } catch (Exception $e) { $this->e($e); @@ -183,7 +187,8 @@ public function circles(): DataResponse { private function confirmRemoteInstance(NC21SignedRequest $signedRequest) { $signatory = $signedRequest->getSignatory(); if (!$signatory instanceof RemoteInstance - || $signatory->getType() === RemoteInstance::TYPE_UNKNOWN) { + || ((!$this->configService->isLocalInstance($signedRequest->getOrigin()) + && $signatory->getType() === RemoteInstance::TYPE_UNKNOWN))) { $this->debug('Could not confirm identity', ['signedRequest' => $signedRequest]); throw new SignatoryException('could not confirm identity'); } @@ -195,6 +200,7 @@ private function confirmRemoteInstance(NC21SignedRequest $signedRequest) { * @throws MalformedArrayException * @throws SignatoryException * @throws SignatureException + * @throws InvalidItemException */ private function extractEventFromRequest(): FederatedEvent { $signed = $this->remoteService->incomingSignedRequest($this->configService->getLocalInstance()); diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index 3dbcedd73..d9b6af594 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -110,6 +110,14 @@ public function limitToInstance(string $host): void { } + /** + * @param int $userType + */ + public function limitToUserType(int $userType): void { + $this->limitToDBFieldInt('user_type', $userType); + } + + /** * @param IFederatedUser $initiator * @param string $alias diff --git a/lib/Db/MemberRequest.php b/lib/Db/MemberRequest.php index cc6fb8bf3..cc2a7cbce 100644 --- a/lib/Db/MemberRequest.php +++ b/lib/Db/MemberRequest.php @@ -53,7 +53,9 @@ class MemberRequest extends MemberRequestBuilder { * @throws InvalidIdException */ public function save(Member $member): void { - $this->confirmValidIds([$member->getCircleId(), $member->getSingleId(), $member->getId()]); + // TODO: check singleId is not empty +// $this->confirmValidIds([$member->getCircleId(), $member->getSingleId(), $member->getId()]); + $this->confirmValidIds([$member->getCircleId(), $member->getId()]); $qb = $this->getMemberInsertSql(); $qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId())) @@ -73,6 +75,39 @@ public function save(Member $member): void { } + /** + * @param Member $member + */ + public function delete(Member $member) { + $qb = $this->getMemberDeleteSql(); + $qb->limitToCircleId($member->getCircleId()); + $qb->limitToUserId($member->getUserId()); + $qb->limitToUserType($member->getUserType()); + $qb->limitToInstance($qb->getInstance($member)); +// $qb->limitToSingleId($federatedUser->getSingleId()); + + $qb->execute(); + } + + + /** + * @param Member $member + */ + public function updateLevel(Member $member): void { + $qb = $this->getMemberUpdateSql(); + $qb->set('level', $qb->createNamedParameter($member->getLevel())); + + $qb->limitToMemberId($member->getId()); + $qb->limitToCircleId($member->getCircleId()); + $qb->limitToUserId($member->getUserId()); + $qb->limitToUserType($member->getUserType()); + $qb->limitToInstance($qb->getInstance($member)); + // $qb->limitToSingleId($member->getSingleId()); + + $qb->execute(); + } + + /** * @param string $circleId * @@ -105,5 +140,28 @@ public function getMember(string $memberId, ?FederatedUser $initiator = null): M return $this->getItemFromRequest($qb); } + + /** + * @param Member $member + * @param FederatedUser|null $initiator + * + * @return Member + * @throws MemberNotFoundException + */ + public function searchMember(Member $member, ?FederatedUser $initiator = null): Member { + $qb = $this->getMemberSelectSql(); + $qb->limitToCircleId($member->getCircleId()); + $qb->limitToUserId($member->getUserId()); + $qb->limitToUserType($member->getUserType()); + $qb->limitToInstance($qb->getInstance($member)); +// $qb->limitToSingleId($federatedUser->getSingleId()); + + if (!is_null($initiator)) { + $qb->leftJoinCircle($initiator); + } + + return $this->getItemFromRequest($qb); + } + } diff --git a/lib/Exceptions/MemberAlreadyExistsException.php b/lib/Exceptions/MemberAlreadyExistsException.php index af0784fb6..ea6cfeb4b 100644 --- a/lib/Exceptions/MemberAlreadyExistsException.php +++ b/lib/Exceptions/MemberAlreadyExistsException.php @@ -1,4 +1,8 @@ + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Exceptions; + + +/** + * Class MemberLevelException + * + * @package OCA\Circles\Exceptions + */ +class MemberHelperException extends FederatedItemException { + +} + diff --git a/lib/Exceptions/MemberLevelException.php b/lib/Exceptions/MemberLevelException.php index 56766b961..692492622 100644 --- a/lib/Exceptions/MemberLevelException.php +++ b/lib/Exceptions/MemberLevelException.php @@ -28,11 +28,15 @@ * */ -namespace OCA\Circles\Exceptions; -use Exception; +namespace OCA\Circles\Exceptions; +/** + * Class MemberLevelException + * + * @package OCA\Circles\Exceptions + */ class MemberLevelException extends FederatedItemException { } diff --git a/lib/FederatedItems/CircleCreate.php b/lib/FederatedItems/CircleCreate.php index 350703c2e..3c7b7484a 100644 --- a/lib/FederatedItems/CircleCreate.php +++ b/lib/FederatedItems/CircleCreate.php @@ -98,6 +98,8 @@ public function manage(FederatedEvent $event): void { $circle = $event->getCircle(); $owner = $circle->getOwner(); + // TODO: confirm CircleId is unique + // TODO: confirm MemberId is unique $this->circleRequest->save($circle); $this->memberRequest->save($owner); diff --git a/lib/FederatedItems/MemberAdd.php b/lib/FederatedItems/MemberAdd.php index 3f2d65070..a62b56700 100644 --- a/lib/FederatedItems/MemberAdd.php +++ b/lib/FederatedItems/MemberAdd.php @@ -36,18 +36,23 @@ use Exception; use OC\User\NoUserException; use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Exceptions\MemberAlreadyExistsException; use OCA\Circles\Exceptions\MemberLevelException; +use OCA\Circles\Exceptions\MemberNotFoundException; use OCA\Circles\Exceptions\MembersLimitException; use OCA\Circles\Exceptions\MemberTypeNotFoundException; use OCA\Circles\Exceptions\TokenDoesNotExistException; use OCA\Circles\Exceptions\UserTypeNotFoundException; use OCA\Circles\IFederatedItem; +use OCA\Circles\IFederatedItemAsync; use OCA\Circles\IFederatedItemMemberCheckNotRequired; use OCA\Circles\IFederatedItemMemberRequired; use OCA\Circles\IFederatedUser; use OCA\Circles\Model\DeprecatedCircle; use OCA\Circles\Model\DeprecatedMember; use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\Helpers\MemberHelper; +use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; use OCA\Circles\Model\SharesToken; use OCA\Circles\Service\CircleService; @@ -65,6 +70,7 @@ */ class MemberAdd implements IFederatedItem, + IFederatedItemAsync, IFederatedItemMemberRequired, IFederatedItemMemberCheckNotRequired { @@ -111,30 +117,35 @@ public function __construct( * @throws NoUserException * @throws UserTypeNotFoundException * @throws MembersLimitException + * @throws MemberAlreadyExistsException */ public function verify(FederatedEvent $event): void { $member = $event->getMember(); $circle = $event->getCircle(); $initiator = $circle->getInitiator(); - if ($initiator->getLevel() < Member::LEVEL_MODERATOR) { - throw new MemberLevelException('Insufficient rights to add members to this Circle'); + $member->setCircleId($circle->getId()); + + $initiatorHelper = new MemberHelper($initiator); + $initiatorHelper->mustBeModerator(); + + try { + $this->memberRequest->searchMember($member); + // TODO: maybe member is requesting access + throw new MemberAlreadyExistsException('Member already exists'); + } catch (MemberNotFoundException $e) { } $this->confirmMemberFormat($member); - $member->setId($this->uuid(Member::ID_LENGTH)); - $member->setCircleId($circle->getId()); - + $member->setId($this->uuid(ManagedModel::ID_LENGTH)); // TODO: check Config on Circle to know if we set Level to 1 or just send an invitation $member->setLevel(Member::LEVEL_MEMBER); $member->setStatus(Member::STATUS_MEMBER); - $event->setDataOutcome(['member' => $member]); // TODO: Managing cached name // $member->setCachedName($eventMember->getCachedName()); -// check Circle is 'verified' $this->circleService->confirmCircleNotFull($circle); $event->setReadingOutcome('Member %s have been added to Circle', ['userId' => $member->getUserId()]); @@ -185,6 +196,7 @@ public function manage(FederatedEvent $event): void { // } // + // TODO: confirm MemberId is unique $this->memberRequest->save($member); // @@ -276,7 +288,7 @@ private function confirmMemberFormat(IFederatedUser $member): void { $this->confirmMemberTypeUser($member); break; - // TODO #M003: confirm other UserType + // TODO: confirm other UserType default: throw new UserTypeNotFoundException(); } diff --git a/lib/FederatedItems/MemberLevel.php b/lib/FederatedItems/MemberLevel.php index ccb3d9063..cdb8cf53f 100644 --- a/lib/FederatedItems/MemberLevel.php +++ b/lib/FederatedItems/MemberLevel.php @@ -32,19 +32,13 @@ namespace OCA\Circles\FederatedItems; -use OCA\Circles\Exceptions\FederatedEventException; +use OCA\Circles\Db\MemberRequest; use OCA\Circles\Exceptions\FederatedItemException; -use OCA\Circles\Exceptions\MemberDoesNotExistException; -use OCA\Circles\Exceptions\MemberIsNotModeratorException; -use OCA\Circles\Exceptions\MemberIsNotOwnerException; -use OCA\Circles\Exceptions\MemberIsOwnerException; -use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException; +use OCA\Circles\Exceptions\MemberLevelException; use OCA\Circles\IFederatedItem; use OCA\Circles\IFederatedItemMemberRequired; -use OCA\Circles\Model\DeprecatedCircle; -use OCA\Circles\Model\DeprecatedMember; use OCA\Circles\Model\Federated\FederatedEvent; -use OCA\Circles\Model\GlobalScale\GSEvent; +use OCA\Circles\Model\Helpers\MemberHelper; use OCA\Circles\Model\Member; @@ -58,32 +52,52 @@ class MemberLevel implements IFederatedItemMemberRequired { + /** @var MemberRequest */ + private $memberRequest; + + + /** + * MemberAdd constructor. + * + * @param MemberRequest $memberRequest + */ + public function __construct(MemberRequest $memberRequest) { + $this->memberRequest = $memberRequest; + } + + /** * @param FederatedEvent $event * - * @throws FederatedEventException - * @throws MemberDoesNotExistException - * @throws MemberIsNotModeratorException - * @throws MemberIsOwnerException - * @throws ModeratorIsNotHighEnoughException + * @throws FederatedItemException */ public function verify(FederatedEvent $event): void { $circle = $event->getCircle(); $member = $event->getMember(); - $level = $event->getData() - ->gInt('level'); + $initiator = $circle->getInitiator(); + $level = $event->getData()->gInt('level'); + + if ($level === 0) { + throw new FederatedItemException('invalid level'); + } if ($member->getLevel() === $level) { throw new FederatedItemException('This member already have the selected level'); } + $initiatorHelper = new MemberHelper($initiator); + $initiatorHelper->mustBeModerator(); if ($level === Member::LEVEL_OWNER) { -// $this->verifySwitchOwner($event, $circle, $member); + $this->verifySwitchOwner($member, $initiator); } else { -// $this->verifyMemberLevel($event, $circle, $member, $level); + $this->verifyMemberLevel($member, $initiator, $level); } + $outcomeMember = clone $member; + $outcomeMember->setLevel($level); + $event->setDataOutcome(['member' => $outcomeMember]); + $event->setReadingOutcome('new level !'); } @@ -91,25 +105,15 @@ public function verify(FederatedEvent $event): void { * @param FederatedEvent $event */ public function manage(FederatedEvent $event): void { - $level = $event->getData() - ->gInt('level'); -// -// $member = $event->getMember(); -// $this->cleanMember($member); -// -// $member->setLevel($level); -// $this->membersRequest->updateMemberLevel($member); -// -// if ($level === DeprecatedMember::LEVEL_OWNER) { -// $circle = $event->getDeprecatedCircle(); -// $isMod = $circle->getOwner(); -// if ($isMod->getInstance() === '') { -// $isMod->setInstance($event->getSource()); -// } -// -// $isMod->setLevel(DeprecatedMember::LEVEL_ADMIN); -// $this->membersRequest->updateMemberLevel($isMod); -// } + $member = clone $event->getMember(); + $member->setLevel($event->getData()->gInt('level')); + $this->memberRequest->updateLevel($member); + + if ($member->getLevel() === Member::LEVEL_OWNER) { + $oldOwner = clone $event->getCircle()->getOwner(); + $oldOwner->setLevel(Member::LEVEL_ADMIN); + $this->memberRequest->updateLevel($oldOwner); + } } @@ -121,47 +125,36 @@ public function result(array $events): void { /** - * @param GSEvent $event - * @param DeprecatedCircle $circle - * @param DeprecatedMember $member + * @param Member $member + * @param Member $initiator * @param int $level * - * @throws MemberDoesNotExistException - * @throws MemberIsOwnerException - * @throws MemberIsNotModeratorException - * @throws ModeratorIsNotHighEnoughException + * @throws MemberLevelException */ - private function verifyMemberLevel( - GSEvent $event, DeprecatedCircle $circle, DeprecatedMember $member, int $level - ) { - $member->hasToBeMember(); - $member->cantBeOwner(); - - if (!$event->isForced()) { - $isMod = $circle->getHigherViewer(); - $isMod->hasToBeModerator(); - $isMod->hasToBeHigherLevel($level); - $isMod->hasToBeHigherLevel($member->getLevel()); - } + private function verifyMemberLevel(Member $member, Member $initiator, int $level) { + $initiatorHelper = new MemberHelper($initiator); + $memberHelper = new MemberHelper($member); + + $memberHelper->mustBeMember(); + $memberHelper->cannotBeOwner(); + + $initiatorHelper->mustBeModerator(); + $initiatorHelper->mustHaveLevelAbove($level); + $initiatorHelper->mustBeHigherLevelThan($member); } /** - * @param GSEvent $event - * @param DeprecatedCircle $circle - * @param DeprecatedMember $member - * - * @throws MemberDoesNotExistException - * @throws MemberIsNotOwnerException - * @throws MemberIsOwnerException + * @param Member $member + * @param Member $initiator */ - private function verifySwitchOwner(GSEvent $event, DeprecatedCircle $circle, DeprecatedMember $member) { - if (!$event->isForced()) { - $isMod = $circle->getHigherViewer(); - $this->circlesService->hasToBeOwner($isMod); - } - - $member->hasToBeMember(); - $member->cantBeOwner(); + private function verifySwitchOwner(Member $member, Member $initiator) { + // TODO: check on NO_OWNER circle + $initiatorHelper = new MemberHelper($initiator); + $memberHelper = new MemberHelper($member); + + $initiatorHelper->mustBeOwner(); + $memberHelper->mustBeMember(); + $memberHelper->cannotBeOwner(); } } diff --git a/lib/FederatedItems/MemberRemove.php b/lib/FederatedItems/MemberRemove.php new file mode 100644 index 000000000..937e8c8b7 --- /dev/null +++ b/lib/FederatedItems/MemberRemove.php @@ -0,0 +1,106 @@ + + * @copyright 2017 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\FederatedItems; + + +use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\IFederatedItem; +use OCA\Circles\IFederatedItemMemberRequired; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\Helpers\MemberHelper; + + +/** + * Class MemberLevel + * + * @package OCA\Circles\FederatedItems + */ +class MemberRemove implements + IFederatedItem, + IFederatedItemMemberRequired { + + + /** @var MemberRequest */ + private $memberRequest; + + + /** + * MemberAdd constructor. + * + * @param MemberRequest $memberRequest + */ + public function __construct(MemberRequest $memberRequest) { + $this->memberRequest = $memberRequest; + } + + + /** + * @param FederatedEvent $event + * + * @throws FederatedItemException + */ + public function verify(FederatedEvent $event): void { + $circle = $event->getCircle(); + $member = $event->getMember(); + $initiator = $circle->getInitiator(); + + $initiatorHelper = new MemberHelper($initiator); + $initiatorHelper->mustBeModerator(); + $initiatorHelper->mustBeHigherLevelThan($member); + + $memberHelper = new MemberHelper($member); + $memberHelper->mustBeMember(); + $memberHelper->cannotBeOwner(); + + $event->setDataOutcome([]); + $event->setReadingOutcome('member is no more'); + } + + + /** + * @param FederatedEvent $event + */ + public function manage(FederatedEvent $event): void { + $member = $event->getMember(); + $this->memberRequest->delete($member); + } + + + /** + * @param FederatedEvent[] $events + */ + public function result(array $events): void { + } + +} + diff --git a/lib/IFederatedItemAsync.php b/lib/IFederatedItemAsync.php new file mode 100644 index 000000000..956cfddb6 --- /dev/null +++ b/lib/IFederatedItemAsync.php @@ -0,0 +1,43 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + + +/** + * Interface IFederatedItemMustBeLocal + * + * @package OCA\Circles + */ +interface IFederatedItemAsync { + +} + diff --git a/lib/Model/Circle.php b/lib/Model/Circle.php index 61c93df6a..4387976bc 100644 --- a/lib/Model/Circle.php +++ b/lib/Model/Circle.php @@ -95,8 +95,6 @@ class Circle extends ManagedModel implements INC21Convert, INC21QueryRow, JsonSe const CFG_ROOT = 4096; // Circle cannot be inside another Circle const CFG_FEDERATED = 8192; // Federated - const ID_LENGTH = 15; - static $DEF = [ 1 => 'S|Single', @@ -510,8 +508,13 @@ public function getCreation(): int { * @param array $data * * @return $this + * @throws InvalidItemException */ public function import(array $data): INC21Convert { + if ($this->get('id', $data) === '') { + throw new InvalidItemException(); + } + $this->setId($this->get('id', $data)) ->setName($this->get('name', $data)) ->setAltName($this->get('alt_name', $data)) @@ -522,6 +525,7 @@ public function import(array $data): INC21Convert { ->setDescription($this->get('description', $data)) ->setCreation($this->getInt('creation', $data)); + try { /** @var Member $owner */ $owner = $this->convert($this->getArray('owner', $data), Member::class); diff --git a/lib/Model/Federated/FederatedEvent.php b/lib/Model/Federated/FederatedEvent.php index 42506a413..3c93dc7d8 100644 --- a/lib/Model/Federated/FederatedEvent.php +++ b/lib/Model/Federated/FederatedEvent.php @@ -32,6 +32,7 @@ namespace OCA\Circles\Model\Federated; +use daita\MySmallPhpTools\Exceptions\InvalidItemException; use daita\MySmallPhpTools\Model\SimpleDataStore; use daita\MySmallPhpTools\Traits\TArrayTools; use JsonSerializable; @@ -389,16 +390,16 @@ public function getReadingOutcome(): SimpleDataStore { /** * @param string $message * @param array $params - * @param bool $success + * @param bool $fail * * @return $this */ - public function setReadingOutcome(string $message, array $params = [], bool $success = true): self { + public function setReadingOutcome(string $message, array $params = [], bool $fail = false): self { $this->readingOutcome = new SimpleDataStore( [ 'message' => $message, 'params' => $params, - 'success' => $success + 'fail' => $fail ] ); @@ -447,6 +448,7 @@ public function setResult(SimpleDataStore $result): self { * @param array $data * * @return self + * @throws InvalidItemException */ public function import(array $data): self { $this->setClass($this->get('class', $data)); @@ -454,7 +456,6 @@ public function import(array $data): self { $this->setData(new SimpleDataStore($this->getArray('data', $data))); $this->setResult(new SimpleDataStore($this->getArray('result', $data))); $this->setSource($this->get('source', $data)); - $this->setAsync($this->getBool('async', $data)); if (array_key_exists('circle', $data)) { $circle = new Circle(); @@ -485,8 +486,7 @@ function jsonSerialize(): array { 'outcome' => [ 'message' => $this->getReadingOutcome(), 'data' => $this->getDataOutcome() - ], - 'async' => $this->isAsync() + ] ]; if ($this->hasCircle()) { diff --git a/lib/Model/Helpers/MemberHelper.php b/lib/Model/Helpers/MemberHelper.php new file mode 100644 index 000000000..9d5c575e7 --- /dev/null +++ b/lib/Model/Helpers/MemberHelper.php @@ -0,0 +1,168 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Model\Helpers; + +use daita\MySmallPhpTools\Traits\TArrayTools; +use OCA\Circles\Exceptions\MemberHelperException; +use OCA\Circles\Exceptions\MemberLevelException; +use OCA\Circles\Model\Member; + + +/** + * Class MemberHelper + * + * + * @method void mustBeMember() @throws MemberHelperException + * @method void mustBeModerator() @throws MemberHelperException + * @method void mustBeAdmin() @throws MemberHelperException + * @method void mustBeOwner() @throws MemberHelperException + * @method void cannotBeMember() @throws MemberHelperException + * @method void cannotBeModerator() @throws MemberHelperException + * @method void cannotBeAdmin() @throws MemberHelperException + * @method void cannotBeOwner() @throws MemberHelperException + * + * @package OCA\Circles\Model\Helpers + */ +class MemberHelper { + + + use TArrayTools; + + + /** @var Member */ + private $member; + + + /** + * Member constructor. + * + * @param Member $member + */ + public function __construct(Member $member) { + $this->member = $member; + } + + + /** + * @param string $name + * @param array $arguments + * + * @throws MemberHelperException + * @throws MemberLevelException + */ + public function __call(string $name, array $arguments): void { + if (substr(strtolower($name), 0, 8) === 'cannotbe') { + $this->cannotBe(substr($name, 8), $arguments); + return; + } + if (substr(strtolower($name), 0, 6) === 'mustbe') { + $this->mustBe(substr($name, 6), $arguments); + return; + } + + throw new MemberHelperException('unknown method call'); + } + + + /** + * @param string $levelString + * @param array $arguments + * + * @throws MemberHelperException + * @throws MemberLevelException + */ + private function mustBe(string $levelString, array $arguments): void { + try { + $level = Member::parseLevelString($levelString); + } catch (MemberLevelException $e) { + throw new MemberHelperException('method ' . $levelString . ' not found'); + } + + $this->mustHaveLevelEqualOrAbove($level); + } + + + /** + * @param string $levelString + * @param array $arguments + * + * @throws MemberHelperException + * @throws MemberLevelException + */ + private function cannotBe(string $levelString, array $arguments): void { + try { + $level = Member::parseLevelString($levelString); + } catch (MemberLevelException $e) { + throw new MemberHelperException('method ' . $levelString . ' not found'); + } + + if ($this->member->getLevel() >= $level) { + throw new MemberLevelException('Member cannot be ' . $levelString); + } + } + + + /** + * @param int $level + * + * @throws MemberLevelException + */ + public function mustHaveLevelAbove(int $level) { + if ($this->member->getLevel() <= $level) { + throw new MemberLevelException('Insufficient rights'); + } + } + + + /** + * @param int $level + * + * @throws MemberLevelException + */ + public function mustHaveLevelEqualOrAbove(int $level) { + if ($this->member->getLevel() < $level) { + throw new MemberLevelException('Insufficient rights'); + } + } + + + /** + * @param Member $compare + * + * @throws MemberLevelException + */ + public function mustBeHigherLevelThan(Member $compare) { + $this->mustHaveLevelAbove($compare->getLevel()); + } + +} + diff --git a/lib/Model/ManagedModel.php b/lib/Model/ManagedModel.php index aff0c3e69..ae6d1c16b 100644 --- a/lib/Model/ManagedModel.php +++ b/lib/Model/ManagedModel.php @@ -42,6 +42,9 @@ class ManagedModel { + const ID_LENGTH = 15; + + /** @var ModelManager */ private $modelManager; diff --git a/lib/Model/Member.php b/lib/Model/Member.php index c484880de..7f03d5113 100644 --- a/lib/Model/Member.php +++ b/lib/Model/Member.php @@ -32,10 +32,13 @@ namespace OCA\Circles\Model; use daita\MySmallPhpTools\Db\Nextcloud\nc21\INC21QueryRow; +use daita\MySmallPhpTools\Exceptions\InvalidItemException; use daita\MySmallPhpTools\Model\Nextcloud\nc21\INC21Convert; +use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Convert; use daita\MySmallPhpTools\Traits\TArrayTools; use DateTime; use JsonSerializable; +use OCA\Circles\Exceptions\MemberLevelException; use OCA\Circles\Exceptions\MemberNotFoundException; use OCA\Circles\IFederatedUser; @@ -49,6 +52,7 @@ class Member extends ManagedModel implements IFederatedUser, INC21Convert, INC21 use TArrayTools; + use TNC21Convert; const LEVEL_NONE = 0; @@ -70,8 +74,6 @@ class Member extends ManagedModel implements IFederatedUser, INC21Convert, INC21 const STATUS_BLOCKED = 'Blocked'; const STATUS_KICKED = 'Kicked'; - const ID_LENGTH = 15; - static $DEF_LEVEL = [ 1 => 'Member', 4 => 'Moderator', @@ -440,18 +442,23 @@ public function isMember(): bool { /** * @param Member $member + * @param bool $full * * @return bool */ - public function compareWith(Member $member): bool { + public function compareWith(Member $member, bool $full = true): bool { if ($this->getId() !== $member->getId() || $this->getCircleId() !== $member->getCircleId() - || $this->getSingleId() !== $member->getSingleId() + // || $this->getSingleId() !== $member->getSingleId() || $this->getUserId() !== $member->getUserId() || $this->getUserType() <> $member->getUserType() - || $this->getInstance() !== $member->getInstance() - || $this->getLevel() <> $member->getLevel() - || $this->getStatus() !== $member->getStatus()) { + || $this->getInstance() !== $member->getInstance()) { + return false; + } + + if ($full + && ($this->getLevel() <> $member->getLevel() + || $this->getStatus() !== $member->getStatus())) { return false; } @@ -463,8 +470,13 @@ public function compareWith(Member $member): bool { * @param array $data * * @return $this + * @throws InvalidItemException */ public function import(array $data): INC21Convert { + if ($this->get('user_id', $data) === '') { + throw new InvalidItemException(); + } + $this->setId($this->get('id', $data)); $this->setCircleId($this->get('circle_id', $data)); $this->setSingleId($this->get('single_id', $data)); @@ -480,6 +492,13 @@ public function import(array $data): INC21Convert { $this->setContactMeta($this->get('contact_meta', $data)); $this->setJoined($this->getInt('joined', $data)); + try { + /** @var Circle $circle */ + $circle = $this->convert($this->getArray('circle', $data), Circle::class); + $this->setCircle($circle); + } catch (InvalidItemException $e) { + } + return $this; } @@ -561,5 +580,24 @@ public function importFromDatabase(array $data, string $prefix = ''): INC21Query return $this; } + + /** + * @param string $levelString + * + * @return int + * @throws MemberLevelException + */ + public static function parseLevelString(string $levelString): int { + $levelString = ucfirst(strtolower($levelString)); + $level = array_search($levelString, Member::$DEF_LEVEL); + + if (!$level) { + $all = implode(', ', array_values(self::$DEF_LEVEL)); + throw new MemberLevelException('Available levels: ' . $all); + } + + return (int)$level; + } + } diff --git a/lib/Service/CircleService.php b/lib/Service/CircleService.php index d2e3f82a2..2e1b974c2 100644 --- a/lib/Service/CircleService.php +++ b/lib/Service/CircleService.php @@ -44,9 +44,11 @@ use OCA\Circles\Exceptions\InitiatorNotFoundException; use OCA\Circles\Model\Circle; use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\FederatedItems\CircleCreate; +use OCA\Circles\Model\ModelManager; /** @@ -116,11 +118,11 @@ public function create(string $name, ?FederatedUser $owner = null): Circle { $circle = new Circle(); $circle->setName($name); - $circle->setId($this->token(Circle::ID_LENGTH)); + $circle->setId($this->token(ManagedModel::ID_LENGTH)); $member = new Member(); $member->importFromIFederatedUser($owner); - $member->setId($this->token(Member::ID_LENGTH)) + $member->setId($this->token(ManagedModel::ID_LENGTH)) ->setCircleId($circle->getId()) ->setLevel(Member::LEVEL_OWNER) ->setStatus(Member::STATUS_MEMBER); diff --git a/lib/Service/FederatedEventService.php b/lib/Service/FederatedEventService.php index 25f3e4b73..0d83d1253 100644 --- a/lib/Service/FederatedEventService.php +++ b/lib/Service/FederatedEventService.php @@ -51,6 +51,7 @@ use OCA\Circles\Exceptions\RemoteResourceNotFoundException; use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\IFederatedItem; +use OCA\Circles\IFederatedItemAsync; use OCA\Circles\IFederatedItemCircleCheckNotRequired; use OCA\Circles\IFederatedItemInitiatorCheckNotRequired; use OCA\Circles\IFederatedItemLocalOnly; @@ -150,6 +151,9 @@ public function newEvent(FederatedEvent $event): void { $this->initBroadcast($event); } else { $this->remoteUpstreamService->confirmEvent($event); + if (!$event->isAsync()) { + $federatedItem->manage($event); + } } } @@ -252,6 +256,7 @@ public function getFederatedItem(FederatedEvent $event, bool $local = false): IF $this->setFederatedEventBypass($event, $item); $this->confirmRequiredCondition($event, $item, $local); + $this->configureEvent($event, $item); return $item; } @@ -312,13 +317,25 @@ private function confirmRequiredCondition( } + /** + * @param FederatedEvent $event + * @param IFederatedItem $item + */ + private function configureEvent(FederatedEvent $event, IFederatedItem $item) { + if ($item instanceof IFederatedItemAsync) { + $event->setAsync(true); + } + } + + /** * async the process, generate a local request that will be closed. * * @param FederatedEvent $event + * @param array $filter */ - public function initBroadcast(FederatedEvent $event): void { - $instances = $this->getInstances($event->isAsync()); + public function initBroadcast(FederatedEvent $event, array $filter = []): void { + $instances = array_diff($this->getInstances($event->isAsync()), $filter); if (empty($instances)) { return; } diff --git a/lib/Service/FederatedUserService.php b/lib/Service/FederatedUserService.php index 9b65ab18c..b6032919a 100644 --- a/lib/Service/FederatedUserService.php +++ b/lib/Service/FederatedUserService.php @@ -46,6 +46,7 @@ use OCA\Circles\IFederatedUser; use OCA\Circles\Model\Circle; use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; use OCA\Circles\Model\Membership; use OCP\IUserManager; @@ -327,7 +328,7 @@ public function getSingleCircle(FederatedUser $federatedUser): Circle { return $this->circleRequest->getInitiatorCircle($federatedUser); } catch (CircleNotFoundException $e) { $circle = new Circle(); - $id = $this->token(Circle::ID_LENGTH); + $id = $this->token(ManagedModel::ID_LENGTH); $circle->setName('single:' . $federatedUser->getUserId() . ':' . $id) ->setId($id) diff --git a/lib/Service/MemberService.php b/lib/Service/MemberService.php index 00d19e82a..78128832c 100644 --- a/lib/Service/MemberService.php +++ b/lib/Service/MemberService.php @@ -54,6 +54,7 @@ use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\FederatedItems\MemberAdd; use OCA\Circles\FederatedItems\MemberLevel; +use OCA\Circles\FederatedItems\MemberRemove; use OCA\Circles\IFederatedUser; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\FederatedUser; @@ -194,9 +195,10 @@ public function addMember(string $circleId, IFederatedUser $member): SimpleDataS /** * @param string $memberId - * @param int $level * + * @return SimpleDataStore * @throws FederatedEventException + * @throws FederatedItemException * @throws InitiatorNotConfirmedException * @throws InitiatorNotFoundException * @throws MemberNotFoundException @@ -207,39 +209,50 @@ public function addMember(string $circleId, IFederatedUser $member): SimpleDataS * @throws SignatoryException * @throws UnknownRemoteException */ - public function memberLevel(string $memberId, int $level): void { + public function removeMember(string $memberId): SimpleDataStore { $this->federatedUserService->mustHaveCurrentUser(); - $member = $this->memberRequest->getMember($memberId, $this->federatedUserService->getCurrentUser()); - $event = new FederatedEvent(MemberLevel::class); + + $event = new FederatedEvent(MemberRemove::class); $event->setCircle($member->getCircle()); $event->setMember($member); - $event->setData(new SimpleDataStore(['level' => $level])); $this->federatedEventService->newEvent($event); + return $event->getOutcome(); } - /** - * @param string $levelString + * @param string $memberId + * @param int $level * - * @return int - * @throws MemberLevelException + * @return SimpleDataStore + * @throws FederatedEventException + * @throws InitiatorNotConfirmedException + * @throws InitiatorNotFoundException + * @throws MemberNotFoundException + * @throws OwnerNotFoundException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestNetworkException + * @throws SignatoryException + * @throws UnknownRemoteException + * @throws FederatedItemException */ - public function parseLevelString(string $levelString): int { - $levelString = ucfirst(strtolower($levelString)); - $level = array_search($levelString, Member::$DEF_LEVEL); + public function memberLevel(string $memberId, int $level): SimpleDataStore { + $this->federatedUserService->mustHaveCurrentUser(); - if (!$level) { - throw new MemberLevelException( - 'Available levels: ' . implode(', ', array_values(Member::$DEF_LEVEL)) - ); - } + $member = $this->memberRequest->getMember($memberId, $this->federatedUserService->getCurrentUser()); - return (int)$level; - } + $event = new FederatedEvent(MemberLevel::class); + $event->setCircle($member->getCircle()); + $event->setMember($member); + $event->setData(new SimpleDataStore(['level' => $level])); + $this->federatedEventService->newEvent($event); + + return $event->getOutcome(); + } } diff --git a/lib/Service/RemoteDownstreamService.php b/lib/Service/RemoteDownstreamService.php index 6ae0b5052..ba2bf9ddb 100644 --- a/lib/Service/RemoteDownstreamService.php +++ b/lib/Service/RemoteDownstreamService.php @@ -126,31 +126,23 @@ public function __construct( * @throws FederatedItemException */ public function requestedEvent(FederatedEvent $event): void { - $gs = $this->federatedEventService->getFederatedItem($event, false); + $item = $this->federatedEventService->getFederatedItem($event, false); if (!$this->configService->isLocalInstance($event->getCircle()->getInstance())) { throw new FederatedEventException('Circle is not from this instance'); } $this->federatedEventService->confirmInitiator($event, false); - $this->confirmContent($event); + $this->confirmContent($event, true); + $item->verify($event); - $gs->verify($event); - -// Async ?? - $this->asyncObj($event->getOutcome()); - -// if (!$event->isAsync()) { -// $gs->manage($event); -// } -// -// $this->initBroadcast($event); -// } else { -// $this->remoteUpstreamService->confirmEvent($event); -// } -// + $filter = []; + if (!$event->isAsync()) { + $item->manage($event); + $filter[] = $event->getIncomingOrigin(); + } - exit(); + $this->federatedEventService->initBroadcast($event, $filter); } @@ -164,7 +156,7 @@ public function incomingEvent(FederatedEvent $event): array { try { $gs = $this->federatedEventService->getFederatedItem($event); $this->confirmOriginEvent($event); - $this->confirmContent($event); + $this->confirmContent($event, false); $gs->manage($event); } catch (Exception $e) { @@ -177,13 +169,14 @@ public function incomingEvent(FederatedEvent $event): array { /** * @param FederatedEvent $event + * @param bool $full * * @throws FederatedEventDSyncException * @throws OwnerNotFoundException */ - private function confirmContent(FederatedEvent $event): void { + private function confirmContent(FederatedEvent $event, bool $full = true): void { $this->confirmCircle($event); - $this->confirmMember($event); + $this->confirmMember($event, $full); } @@ -230,12 +223,13 @@ private function verifyCircle(FederatedEvent $event): bool { /** * @param FederatedEvent $event + * @param bool $full * * @throws FederatedEventDSyncException */ - private function confirmMember(FederatedEvent $event): void { + private function confirmMember(FederatedEvent $event, bool $full): void { if ($event->canBypass(FederatedEvent::BYPASS_LOCALMEMBERCHECK) || !$event->hasMember() - || $this->verifyMember($event)) { + || $this->verifyMember($event, $full)) { return; } @@ -244,10 +238,11 @@ private function confirmMember(FederatedEvent $event): void { /** * @param FederatedEvent $event + * @param bool $full * * @return bool */ - private function verifyMember(FederatedEvent $event): bool { + private function verifyMember(FederatedEvent $event, bool $full): bool { $this->debug('verifyMember()', ['event' => $event]); $member = $event->getMember(); @@ -259,7 +254,7 @@ private function verifyMember(FederatedEvent $event): bool { return false; } - if (!$localMember->compareWith($member)) { + if (!$localMember->compareWith($member, $full)) { $this->debug( 'failed to compare Members', ['localMember' => json_encode($localMember), 'member' => json_encode($member)] @@ -267,6 +262,8 @@ private function verifyMember(FederatedEvent $event): bool { return false; } + + return true; } diff --git a/lib/Service/RemoteUpstreamService.php b/lib/Service/RemoteUpstreamService.php index c82ad85aa..4b39b0cfd 100644 --- a/lib/Service/RemoteUpstreamService.php +++ b/lib/Service/RemoteUpstreamService.php @@ -40,6 +40,7 @@ use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Request; use Exception; use OCA\Circles\Db\RemoteWrapperRequest; +use OCA\Circles\Exceptions\FederatedEventDSyncException; use OCA\Circles\Exceptions\FederatedEventException; use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RemoteNotFoundException; @@ -170,6 +171,7 @@ public function broadcastEvent(FederatedEvent $event, string $instance): void { * @throws OwnerNotFoundException * @throws RequestNetworkException * @throws FederatedEventException + * @throws FederatedEventDSyncException */ public function confirmEvent(FederatedEvent $event): void { $data = $this->remoteService->requestRemoteInstance( @@ -180,29 +182,27 @@ public function confirmEvent(FederatedEvent $event): void { ); // TODO: check what is happening if website is down... - if (!$data->getOutgoingRequest()->hasResult() - || $data->getOutgoingRequest()->getResult()->hasException()) { + if (!$data->getOutgoingRequest()->hasResult()) { throw new RequestNetworkException(); } $result = $data->getOutgoingRequest()->getResult(); - $this->manageRequestOutcome($event, $result->getAsArray()); + $this->manageRequestOutcome($event, $result->getAsArray()); $reading = $event->getReadingOutcome(); - if ($result->getStatusCode() === Http::STATUS_OK && $reading->gBool('success')) { + + if ($result->getStatusCode() === Http::STATUS_CONFLICT) { + throw new FederatedEventDSyncException($reading->g('translated')); + } + + if ($result->getStatusCode() === Http::STATUS_OK && !$reading->gBool('fail')) { return; } throw new FederatedEventException($reading->g('translated')); } - - - - - - // - // + // // // @@ -382,7 +382,7 @@ private function manageRequestOutcome(FederatedEvent $event, array $result): voi $event->setReadingOutcome( $outcome->g('reading.message'), $outcome->gArray('reading.params'), - $outcome->gBool('reading.success') + $outcome->gBool('reading.fail') ); $reading = $event->getReadingOutcome(); diff --git a/toto.json b/toto.json index 900363512..c398472fb 100644 --- a/toto.json +++ b/toto.json @@ -1,79 +1,34 @@ { - "statusCode": 200, - "headers": { - "Date": [ - "Fri, 05 Feb 2021 13:03:32 GMT" - ], - "Server": [ - "Apache\/2.4.41 (Ubuntu)" - ], - "Referrer-Policy": [ - "no-referrer" - ], - "X-Content-Type-Options": [ - "nosniff" - ], - "X-Download-Options": [ - "noopen" - ], - "X-Frame-Options": [ - "SAMEORIGIN" - ], - "X-Permitted-Cross-Domain-Policies": [ - "none" - ], - "X-Robots-Tag": [ - "none" - ], - "X-XSS-Protection": [ - "1; mode=block" - ], - "Upgrade": [ - "h2" - ], - "Connection": [ - "Upgrade" - ], - "Set-Cookie": [ - "oc0201p1pefh=s3hdajv6iugfolmko7a510eunk; path=\/; HttpOnly; SameSite=Lax", - "oc_sessionPassphrase=pO7t0ajn7HAzcw4AOQ0DOmMIZsCdV4Y9CnDERyaz5mUb%2BNwqWrujpVDqSe5TW0YbOwWb2Vr0KqOQ%2BbUcWuKa6VXamEcwqJlNGckghQ6O%2BShgaJDUkgdBiSwg07DoC%2Bqv; path=\/; HttpOnly; SameSite=Lax", - "oc0201p1pefh=9n3emd13i85jorjr6cbempijc4; path=\/; HttpOnly; SameSite=Lax", - "nc_sameSiteCookielax=true; path=\/; httponly;expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax", - "nc_sameSiteCookiestrict=true; path=\/; httponly;expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=strict" - ], - "Expires": [ - "Thu, 19 Nov 1981 08:52:00 GMT" - ], - "Cache-Control": [ - "no-cache, no-store, must-revalidate" - ], - "Pragma": [ - "no-cache" - ], - "Content-Security-Policy": [ - "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'" - ], - "Feature-Policy": [ - "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'" - ], - "Content-Type": [ - "application\/json; charset=utf-8" - ], - "x-encoded-content-encoding": [ - "gzip" - ], - "x-encoded-content-length": [ - "117" - ] - }, - "content": "{\"reading\":{\"message\":\"Insufficient rights to add members to this Circle\",\"params\":[],\"success\":false},\"data\":[]}", - "contentAsArray": { - "reading": { - "message": "Insufficient rights to add members to this Circle", - "params": [], - "success": false + "signedRequest": { + "body": "{\"class\":\"OCA\\\\\\\\Circles\\\\\\\\FederatedItems\\\\\\\\MemberAdd\",\"severity\":1,\"data\":[],\"result\":[],\"source\":\"nc21.local\",\"outcome\":{\"message\":[],\"data\":[]},\"circle\":{\"id\":\"D5cXC2jmRZNk3y\",\"name\":\"test\",\"creation\":1612169835,\"owner\":{\"id\":\"9dab10e1c62249\",\"circle_id\":\"D5cXC2jmRZNk3y\",\"user_id\":\"test3\",\"user_type\":1,\"instance\":\"nc21b.local\",\"level\":9,\"status\":\"Member\",\"cached_update\":1612267989,\"joined\":1612267989},\"initiator\":{\"id\":\"fLKAuR2ivoRdyf\",\"circle_id\":\"D5cXC2jmRZNk3y\",\"user_id\":\"test2\",\"user_type\":1,\"instance\":\"nc21.local\",\"level\":8,\"status\":\"Member\",\"cached_update\":1612169835,\"joined\":1612169835}},\"member\":{\"id\":\"cfee0067fc304bf\",\"circle_id\":\"D5cXC2jmRZNk3y\",\"user_id\":\"cult\",\"user_type\":1,\"instance\":\"nc21c.local\",\"level\":1,\"status\":\"Member\"}}", + "time": 1612700862, + "incomingRequest": true, + "outgoingRequest": false, + "origin": "nc21b.local", + "digest": "SHA-256=6FRZSn84bji2ui\\/VEZtxuocKgmDHr\\/+TLc1\\/MNSNkm0=", + "signatureHeader": { + "keyId": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/#main-key", + "algorithm": "ras-sha256", + "headers": "content-length date digest host", + "signature": "DhDbZ8vBveeuO+YnPnCmRgMLB8+a2\\/w8PG02vIvax49b6Dqty5Ypq028OvFsqCF1Xwor8KoDIB6noFJV1B6sWwG1zhbIkhzuYLOTmK7Bw2ZdapiNEcBKvfN0W0rRhQUJmyNSxH1JJ+U545v7Rq8xaq7OLDZpOW\\/Bl11tEErxryShjAufNrW1R0fDdXEzCuirxjtBbluowcq8gH5c0DR6yCvpblS+lDO2OUI\\/dlGuVnCI\\/h9BnVySfoOWzdukehsZZslNahyAhYQtf3uD4P4dm21eKyU+QI+ZIO2BYWv201iqC+vkYb0U9aFEqe9IWa9+NzkajmCMenuzbMxJdryASg==" }, - "data": [] - }, - "contentType": 2 + "host": "nc21b.local", + "clearSignature": "(request-target): post \\/index.php\\/apps\\/circles\\/incoming\\ncontent-length: 748\\ndate: Sun, 07 Feb 2021 12:27:42 GMT\\ndigest: SHA-256=6FRZSn84bji2ui\\/VEZtxuocKgmDHr\\/+TLc1\\/MNSNkm0=\\nhost: nc21b.local", + "signedSignature": "RGhEYlo4dkJ2ZWV1TytZblBuQ21SZ01MQjgrYTIvdzhQRzAydkl2YXg0OWI2RHF0eTVZcHEwMjhPdkZzcUNGMVh3b3I4S29ESUI2bm9GSlYxQjZzV3dHMXpoYklraHp1WUxPVG1LN0J3MlpkYXBpTkVjQkt2Zk4wVzByUmhRVUpteU5TeEgxSkorVTU0NXY3UnE4eGFxN09MRFpwT1cvQmwxMXRFRXJ4cnlTaGpBdWZOclcxUjBmRGRYRXpDdWlyeGp0QmJsdW93Y3E4Z0g1YzBEUjZ5Q3ZwYmxTK2xETzJPVUkvZGxHdVZuQ0kvaDlCblZ5U2ZvT1d6ZHVrZWhzWlpzbE5haHlBaFlRdGYzdUQ0UDRkbTIxZUt5VStRSStaSU8yQllXdjIwMWlxQyt2a1liMFU5YUZFcWU5SVdhOStOemtham1DTWVudXpiTXhKZHJ5QVNnPT0=", + "signatory": { + "uid": "ad7628837e70bdfcfa", + "event": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/event", + "incoming": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/incoming", + "test": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/test", + "circles": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/circles", + "members": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/members", + "auth-signed": "sha256:sha256:tE500UoYfKE1dXrOt5Y5faKUmJKYP7c6jB9AFqXN0n7Pkr5mnUOo07wf5ZbfnPh7iW2qQJKTj1itFinmO7sJMC5iAHbbHXPc1JG4OK6OssdWZuZa3ymikSrVKWWvL5BuR3aYCskD4VBw7SJMRdtmP90NJw9RwzNt79aHEn6wH\\/yC7Fr6RelXghBZ3Yaq\\/nXplD8SGOunST6jm4vANW6l3pwbuF8EzFlI3KrQkTrSNRex9gy0OZpIDF1W9U2oHR8oajBnQ4q\\/Yvw+u7QN3JwE7\\/jUHOqhOjFVSwOPMUPzdBPFUWZ\\/dtPmliQJw3D\\/JlZjgnTukeeiWRD3rzaep0GtAA==", + "id": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/", + "publicKey": { + "id": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/#main-key", + "owner": "http:\\/\\/nc21b.local\\/index.php\\/apps\\/circles\\/", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3ylBJNFXoGNmNGvAqS3Z\\nkSq9uOoTpGxarsKz7b3qTMytjIfrRoHVS\\/kgE7b64zF+3TJcwMhUkEEPHHCzZDQR\\nH+sjGkFZDkHV0C6Yox6xMif63lCd+JF1ONodDSrOxSShfB107OIrgrUW5ly2BhAi\\n2nUmgBcmgd4vy5f4+ekXAc12dd\\/zKU5MT0yCyu2g1mmUBAF4o5QrLgYOxbsWqbve\\nmJt4Nv+Dq5IItfB6zy8yXs6XsCtA\\/R1mCJCEiuCp+3i7ZFhxmsOea0tHCqpl5STU\\n9bX5gyEPYkn7iTY0g3WKHoVGoSrMuwG9tsAe1AzIp0Xq66KDCn5Dp3Ow+R2Qtxsw\\nkwIDAQAB\\n-----END PUBLIC KEY-----\\n" + } + } + } }