diff --git a/lib/Api/v1/Circles.php b/lib/Api/v1/Circles.php index d29f23cfb..2bc933e34 100644 --- a/lib/Api/v1/Circles.php +++ b/lib/Api/v1/Circles.php @@ -29,7 +29,6 @@ namespace OCA\Circles\Api\v1; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use OCA\Circles\Exceptions\CircleNotFoundException; use OCA\Circles\Exceptions\FederatedUserException; use OCA\Circles\Exceptions\FederatedUserNotFoundException; @@ -39,6 +38,7 @@ use OCA\Circles\Exceptions\SingleCircleNotFoundException; use OCA\Circles\Model\Circle; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\FederatedUserService; @@ -101,11 +101,10 @@ public static function listCircles($type, $name = '', $level = 0, $userId = '', /** @var CircleService $circleService */ $circleService = \OC::$server->get(CircleService::class); - return $circleService->getCircles( - null, - null, - new SimpleDataStore(['includePersonalCircles' => $personalCircle]) - ); + $probe = new CircleProbe(); + $probe->includePersonalCircles($personalCircle); + + return $circleService->getCircles($probe); } @@ -145,16 +144,11 @@ public static function joinedCircles($userId = '', $forceAll = false) { /** @var CircleService $circleService */ $circleService = \OC::$server->get(CircleService::class); - return $circleService->getCircles( - null, - null, - new SimpleDataStore( - [ - 'mustBeMember' => true, - 'includePersonalCircles' => $personalCircle - ] - ) - ); + $probe = new CircleProbe(); + $probe->mustBeMember(); + $probe->includePersonalCircles($personalCircle); + + return $circleService->getCircles($probe); } diff --git a/lib/CirclesManager.php b/lib/CirclesManager.php index 130defaaa..24746888e 100644 --- a/lib/CirclesManager.php +++ b/lib/CirclesManager.php @@ -33,6 +33,9 @@ use ArtificialOwl\MySmallPhpTools\Exceptions\InvalidItemException; use OCA\Circles\Exceptions\CircleNotFoundException; +use OCA\Circles\Exceptions\ContactAddressBookNotFoundException; +use OCA\Circles\Exceptions\ContactFormatException; +use OCA\Circles\Exceptions\ContactNotFoundException; use OCA\Circles\Exceptions\FederatedEventException; use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\FederatedUserException; @@ -41,6 +44,7 @@ use OCA\Circles\Exceptions\InitiatorNotFoundException; use OCA\Circles\Exceptions\InvalidIdException; use OCA\Circles\Exceptions\MemberNotFoundException; +use OCA\Circles\Exceptions\MembershipNotFoundException; use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RemoteInstanceException; use OCA\Circles\Exceptions\RemoteNotFoundException; @@ -52,9 +56,12 @@ use OCA\Circles\Model\Circle; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Membership; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; +use OCA\Circles\Service\MembershipService; use OCP\IUserSession; /** @@ -77,6 +84,9 @@ class CirclesManager { /** @var MemberService */ private $memberService; + /** @var MembershipService */ + private $membershipService; + /** * CirclesManager constructor. @@ -91,11 +101,13 @@ public function __construct( FederatedUserService $federatedUserService, CircleService $circleService, MemberService $memberService, + MembershipService $membershipService, CirclesQueryHelper $circlesQueryHelper ) { $this->federatedUserService = $federatedUserService; $this->circleService = $circleService; $this->memberService = $memberService; + $this->membershipService = $membershipService; $this->circlesQueryHelper = $circlesQueryHelper; } @@ -267,36 +279,114 @@ public function destroyCircle(string $singleId): void { * @throws InitiatorNotFoundException * @throws RequestBuilderException */ - public function getCircles(): array { - return $this->circleService->getCircles(); + public function getCircles(?CircleProbe $probe = null): array { + return $this->circleService->getCircles($probe); } /** * @param string $singleId + * @param CircleProbe|null $probe * * @return Circle * @throws CircleNotFoundException * @throws InitiatorNotFoundException * @throws RequestBuilderException */ - public function getCircle(string $singleId): Circle { - return $this->circleService->getCircle($singleId); + public function getCircle(string $singleId, ?CircleProbe $probe = null): Circle { + return $this->circleService->getCircle($singleId, $probe); } + /** + * @param string $circleId + * @param FederatedUser $federatedUser + * + * @return Member + * @throws CircleNotFoundException + * @throws ContactAddressBookNotFoundException + * @throws ContactFormatException + * @throws ContactNotFoundException + * @throws FederatedEventException + * @throws FederatedItemException + * @throws FederatedUserException + * @throws InitiatorNotConfirmedException + * @throws InitiatorNotFoundException + * @throws InvalidIdException + * @throws InvalidItemException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws SingleCircleNotFoundException + * @throws UnknownRemoteException + */ + public function addMember(string $circleId, FederatedUser $federatedUser): Member { + $outcome = $this->memberService->addMember($circleId, $federatedUser); + $member = new Member(); + $member->import($outcome); + + return $member; + } + /** - * WIP + * @param string $memberId + * @param int $level * - * @return Circle[] + * @return Member + * @throws FederatedEventException + * @throws FederatedItemException + * @throws InitiatorNotConfirmedException * @throws InitiatorNotFoundException + * @throws InvalidItemException + * @throws MemberNotFoundException + * @throws OwnerNotFoundException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException * @throws RequestBuilderException + * @throws UnknownRemoteException */ -// public function getAllCircles(): array { -// $this->federatedUserService->bypassCurrentUserCondition(true); -// $this->circleService->getCircles(); -// } + public function levelMember(string $memberId, int $level): Member { + $outcome = $this->memberService->memberLevel($memberId, $level); + $member = new Member(); + $member->import($outcome); + + return $member; + } + + + /** + * @param string $memberId + * + * @throws FederatedEventException + * @throws FederatedItemException + * @throws InitiatorNotConfirmedException + * @throws InitiatorNotFoundException + * @throws MemberNotFoundException + * @throws OwnerNotFoundException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ + public function removeMember(string $memberId): void { + $this->memberService->removeMember($memberId); + } + + + /** + * @param string $circleId + * @param string $singleId + * + * @return Membership + * @throws MembershipNotFoundException + * @throws RequestBuilderException + */ + public function getLink(string $circleId, string $singleId): Membership { + return $this->membershipService->getMembership($circleId, $singleId); + } /** diff --git a/lib/CirclesQueryHelper.php b/lib/CirclesQueryHelper.php index 97b5e5906..5dbf0cd43 100644 --- a/lib/CirclesQueryHelper.php +++ b/lib/CirclesQueryHelper.php @@ -37,6 +37,7 @@ use OCA\Circles\Exceptions\FederatedUserNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Member; use OCA\Circles\Service\FederatedUserService; use OCP\DB\QueryBuilder\ICompositeExpression; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -108,7 +109,7 @@ public function limitToSession( [CoreQueryBuilder::HELPER], [ 'getData' => $fullDetails, - 'mustBeMember' => true + 'minimumLevel' => Member::LEVEL_MEMBER ] ); @@ -141,7 +142,7 @@ public function limitToInheritedMembers( [CoreQueryBuilder::HELPER], [ 'getData' => $fullDetails, - 'mustBeMember' => true + 'minimumLevel' => Member::LEVEL_MEMBER ] ); diff --git a/lib/Collaboration/v2/CollaboratorSearchPlugin.php b/lib/Collaboration/v2/CollaboratorSearchPlugin.php index e38d25298..1666993b6 100644 --- a/lib/Collaboration/v2/CollaboratorSearchPlugin.php +++ b/lib/Collaboration/v2/CollaboratorSearchPlugin.php @@ -31,10 +31,10 @@ namespace OCA\Circles\Collaboration\v2; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use Exception; use OC\Share20\Share; use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\FederatedUserService; use OCP\Collaboration\Collaborators\ISearchPlugin; @@ -85,15 +85,16 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b try { $this->federatedUserService->initCurrentUser(); - $circles = $this->circleService->getCircles( - $filterCircle, null, - new SimpleDataStore( - [ - 'limit' => $limit, - 'offset' => $offset - ] - ) - ); + + $probe = new CircleProbe(); + $probe->setItemsLimit($limit); + $probe->setItemsOffset($offset); + $probe->setFilterCircle($filterCircle); + + // Issue when searching for circle to be added as member + $probe->mustBeMember(); + + $circles = $this->circleService->getCircles($probe); } catch (Exception $e) { return false; } diff --git a/lib/Command/CirclesList.php b/lib/Command/CirclesList.php index 88ce0a50c..9bb2aeb81 100644 --- a/lib/Command/CirclesList.php +++ b/lib/Command/CirclesList.php @@ -33,7 +33,6 @@ use ArtificialOwl\MySmallPhpTools\Exceptions\RequestNetworkException; use ArtificialOwl\MySmallPhpTools\Exceptions\SignatoryException; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools; use ArtificialOwl\MySmallPhpTools\Traits\TStringTools; use OC\Core\Command\Base; @@ -55,6 +54,7 @@ use OCA\Circles\Model\Circle; use OCA\Circles\Model\Member; use OCA\Circles\Model\ModelManager; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; @@ -183,8 +183,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int true ); - $params = new SimpleDataStore(['includeSystemCircles' => $input->getOption('all')]); - $circles = $this->circleService->getCircles(null, $filterMember, $params); + $probe = new CircleProbe(); + if ($input->getOption('all')) { + $probe->includeSystemCircles() + ->includeSingleCircles() + ->includePersonalCircles(); + } + $circles = $this->circleService->getCircles($probe); } if (strtolower($input->getOption('output')) === 'json') { diff --git a/lib/Command/CirclesMemberships.php b/lib/Command/CirclesMemberships.php index 743ad1bd6..260b95b63 100644 --- a/lib/Command/CirclesMemberships.php +++ b/lib/Command/CirclesMemberships.php @@ -61,6 +61,7 @@ use OCA\Circles\Model\Circle; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; @@ -366,8 +367,10 @@ private function manageAllMemberships() { $this->federatedUserService->bypassCurrentUserCondition(true); - $params = new SimpleDataStore(['includeSystemCircles' => true]); - $circles = $this->circleService->getCircles(null, null, $params); + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->includePersonalCircles(); + $circles = $this->circleService->getCircles($probe); $output = new ConsoleOutput(); $output = $output->section(); diff --git a/lib/Command/CirclesReport.php b/lib/Command/CirclesReport.php index 9c962a33c..f7a83d8f0 100644 --- a/lib/Command/CirclesReport.php +++ b/lib/Command/CirclesReport.php @@ -35,7 +35,6 @@ use ArtificialOwl\MySmallPhpTools\Exceptions\InvalidItemException; use ArtificialOwl\MySmallPhpTools\IInteractiveShellClient; use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc22\NC22InteractiveShellSession; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize; use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools; use OC\Core\Command\Base; @@ -46,6 +45,7 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; use OCA\Circles\Model\Membership; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\Report; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; @@ -173,11 +173,9 @@ private function generateReport(): Report { $report->setSource($this->interfaceService->getLocalInstance()); $this->federatedUserService->bypassCurrentUserCondition(true); - $raw = $this->circleService->getCircles( - null, - null, - new SimpleDataStore(['includeSystemCircles' => true]) - ); + $probe = new CircleProbe(); + $probe->includeSystemCircles(); + $raw = $this->circleService->getCircles($probe); $circles = []; foreach ($raw as $circle) { diff --git a/lib/Command/SharesFiles.php b/lib/Command/SharesFiles.php index f7ffdc615..d51ab0bc4 100644 --- a/lib/Command/SharesFiles.php +++ b/lib/Command/SharesFiles.php @@ -39,6 +39,7 @@ use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\SingleCircleNotFoundException; use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\ShareWrapper; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; @@ -302,12 +303,13 @@ private function getShares( } if ($with !== '') { + $probe = new CircleProbe(); + $probe->includePersonalCircles(); + return $this->shareWrapperService->getSharedWith( $this->federatedUserService->getLocalFederatedUser($with), $fileId, - -1, - 0, - true + $probe ); } diff --git a/lib/Controller/RemoteController.php b/lib/Controller/RemoteController.php index ee863907e..8f9024ce9 100644 --- a/lib/Controller/RemoteController.php +++ b/lib/Controller/RemoteController.php @@ -55,6 +55,7 @@ use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; @@ -253,7 +254,12 @@ public function circles(): DataResponse { $filterCircle = $data->gObj('filterCircle'); /** @var Member $filterMember */ $filterMember = $data->gObj('filterMember'); - $circles = $this->circleService->getCircles($filterCircle, $filterMember); + + $probe = new CircleProbe(); + $probe->setFilterCircle($filterCircle) + ->setFilterMember($filterMember); + + $circles = $this->circleService->getCircles($probe); return new DataResponse($circles); } catch (Exception $e) { diff --git a/lib/Db/CircleRequest.php b/lib/Db/CircleRequest.php index 3b908f530..29dbaed97 100644 --- a/lib/Db/CircleRequest.php +++ b/lib/Db/CircleRequest.php @@ -31,7 +31,6 @@ namespace OCA\Circles\Db; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use OCA\Circles\Exceptions\CircleNotFoundException; use OCA\Circles\Exceptions\FederatedUserNotFoundException; use OCA\Circles\Exceptions\InvalidIdException; @@ -40,9 +39,9 @@ use OCA\Circles\Exceptions\SingleCircleNotFoundException; use OCA\Circles\IFederatedUser; use OCA\Circles\Model\Circle; -use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; /** * Class CircleRequest @@ -151,54 +150,42 @@ public function updateConfig(Circle $circle) { /** - * @param Circle|null $circleFilter - * @param Member|null $memberFilter * @param IFederatedUser|null $initiator - * @param RemoteInstance|null $remoteInstance - * @param SimpleDataStore $params + * @param CircleProbe $probe * * @return Circle[] * @throws RequestBuilderException */ - public function getCircles( - ?Circle $circleFilter, - ?Member $memberFilter, - ?IFederatedUser $initiator, - ?RemoteInstance $remoteInstance, - SimpleDataStore $params - ): array { + public function getCircles(?IFederatedUser $initiator, CircleProbe $probe): array { $qb = $this->getCircleSelectSql(); $qb->leftJoinOwner(CoreQueryBuilder::CIRCLE); $qb->setOptions( [CoreQueryBuilder::CIRCLE], - [ - 'getData' => true, - 'mustBeMember' => $params->gBool('mustBeMember'), - 'initiatorDirectMember' => true - ] + array_merge( + $probe->getAsOptions(), + [ + 'getData' => true, + 'initiatorDirectMember' => true + ] + ) ); - if (!$params->gBool('includeSystemCircles')) { - $qb->filterCircles( - CoreQueryBuilder::CIRCLE, - Circle::CFG_SINGLE | Circle::CFG_HIDDEN | Circle::CFG_BACKEND - ); - } + $qb->filterCircles(CoreQueryBuilder::CIRCLE, $probe->filtered()); if (!is_null($initiator)) { $qb->limitToInitiator(CoreQueryBuilder::CIRCLE, $initiator); } - if (!is_null($memberFilter)) { - $qb->limitToDirectMembership(CoreQueryBuilder::CIRCLE, $memberFilter); + if ($probe->hasFilterMember()) { + $qb->limitToDirectMembership(CoreQueryBuilder::CIRCLE, $probe->getFilterMember()); } - if (!is_null($circleFilter)) { - $qb->filterCircle($circleFilter); + if ($probe->hasFilterCircle()) { + $qb->filterCircle($probe->getFilterCircle()); } - if (!is_null($remoteInstance)) { - $qb->limitToRemoteInstance(CoreQueryBuilder::CIRCLE, $remoteInstance, false); + if ($probe->hasFilterRemoteInstance()) { + $qb->limitToRemoteInstance(CoreQueryBuilder::CIRCLE, $probe->getFilterRemoteInstance(), false); } $qb->countMembers(CoreQueryBuilder::CIRCLE); - $qb->chunk($params->gInt('offset'), $params->gInt('limit')); + $qb->chunk($probe->getItemsOffset(), $probe->getItemsLimit()); return $this->getItemsFromRequest($qb); } @@ -212,7 +199,9 @@ public function getCircles( */ public function getCirclesByIds(array $circleIds): array { $qb = $this->getCircleSelectSql(); - $qb->setOptions([CoreQueryBuilder::CIRCLE], ['getData' => true, 'canBeVisitor' => true]); + $qb->setOptions( + [CoreQueryBuilder::CIRCLE], ['getData' => true, 'minimumLevel' => Member::LEVEL_NONE] + ); $qb->limitInArray('unique_id', $circleIds); // $qb->filterCircles(CoreQueryBuilder::CIRCLE, $filter); @@ -224,8 +213,7 @@ public function getCirclesByIds(array $circleIds): array { /** * @param string $id * @param IFederatedUser|null $initiator - * @param RemoteInstance|null $remoteInstance - * @param int $filter + * @param CircleProbe|null $probe * * @return Circle * @throws CircleNotFoundException @@ -234,34 +222,43 @@ public function getCirclesByIds(array $circleIds): array { public function getCircle( string $id, ?IFederatedUser $initiator = null, - ?RemoteInstance $remoteInstance = null, - int $filter = Circle::CFG_BACKEND | Circle::CFG_SINGLE | Circle::CFG_HIDDEN + ?CircleProbe $probe = null ): Circle { + if (is_null($probe)) { + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->includeBackendCircles() + ->includeHiddenCircles() + ->emulateVisitor(); + } + $qb = $this->getCircleSelectSql(); $qb->setOptions( [CoreQueryBuilder::CIRCLE], - [ - 'getData' => true, - 'canBeVisitor' => true, - 'initiatorDirectMember' => true - ] + array_merge( + $probe->getAsOptions(), + [ + 'getData' => true, + 'initiatorDirectMember' => true + ] + ) ); $qb->limitToUniqueId($id); - $qb->filterCircles(CoreQueryBuilder::CIRCLE, $filter); + $qb->filterCircles(CoreQueryBuilder::CIRCLE, $probe->filtered()); $qb->leftJoinOwner(CoreQueryBuilder::CIRCLE); // $qb->setOptions( // [CoreRequestBuilder::CIRCLE, CoreRequestBuilder::INITIATOR], [ // 'mustBeMember' => false, -// 'canBeVisitor' => true +// 'viewableAsVisitor' => true // ] // ); if (!is_null($initiator)) { $qb->limitToInitiator(CoreQueryBuilder::CIRCLE, $initiator); } - if (!is_null($remoteInstance)) { - $qb->limitToRemoteInstance(CoreQueryBuilder::CIRCLE, $remoteInstance, false); + if ($probe->hasFilterRemoteInstance()) { + $qb->limitToRemoteInstance(CoreQueryBuilder::CIRCLE, $probe->getFilterRemoteInstance(), false); } $qb->countMembers(CoreQueryBuilder::CIRCLE); diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index 68596e881..698a8f997 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -127,8 +127,7 @@ class CoreQueryBuilder extends NC22ExtendedQueryBuilder { ], self::INITIATOR => [ self::OPTIONS => [ - 'mustBeMember' => true, - 'canBeVisitor' => false + 'minimumLevel' => Member::LEVEL_MEMBER ], self::BASED_ON, self::INHERITED_BY => [ @@ -395,6 +394,9 @@ public function filterCircle(Circle $circle): void { if ($circle->getDisplayName() !== '') { $this->searchInDBField('display_name', '%' . $circle->getDisplayName() . '%'); } + if ($circle->getSource() > 0) { + $this->limitInt('source', $circle->getSource()); + } if ($circle->getConfig() > 0) { $this->limitBitwise('config', $circle->getConfig()); } @@ -1208,7 +1210,7 @@ public function leftJoinInitiator( ); $default = []; - if ($this->getBool('canBeVisitor', $options, false)) { + if ($this->getBool('emulateVisitor', $options)) { $default = [ 'user_id' => $initiator->getUserId(), 'single_id' => $initiator->getSingleId(), @@ -1241,8 +1243,6 @@ protected function limitInitiatorVisibility(string $alias): ICompositeExpression array_push($levelCheck, $this->generateAlias($alias, self::DIRECT_INITIATOR, $options)); } - $filterPersonalCircle = $this->getBool('filterPersonalCircle', $options, true); - $expr = $this->expr(); // Visibility to non-member is @@ -1251,7 +1251,8 @@ protected function limitInitiatorVisibility(string $alias): ICompositeExpression // - 4 (Visible to everyone) $orX = $expr->orX(); - if ($filterPersonalCircle) { + // filterPersonalCircles will remove access to Personal Circles as Owner + if (!$this->getBool('filterPersonalCircles', $options, false)) { $orX->add( $expr->andX( $this->exprLimitBitwise('config', Circle::CFG_PERSONAL, $aliasMembershipCircle), @@ -1260,28 +1261,31 @@ protected function limitInitiatorVisibility(string $alias): ICompositeExpression ); } + $minimumLevel = $this->getInt('minimumLevel', $options); $andXMember = $expr->andX(); $andXMember->add( - $this->orXCheckLevel($levelCheck, Member::LEVEL_MEMBER), + $this->orXCheckLevel($levelCheck, $minimumLevel) ); - if ($filterPersonalCircle) { + + if (!$this->getBool('includePersonalCircles', $options, false)) { $andXMember->add( $this->exprFilterBitwise('config', Circle::CFG_PERSONAL, $aliasMembershipCircle) ); } $orX->add($andXMember); - if (!$this->getBool('mustBeMember', $options, true)) { + if ($minimumLevel === 0 && $alias === self::CIRCLE) { $orX->add($this->exprLimitBitwise('config', Circle::CFG_VISIBLE, $alias)); } - if ($this->getBool('canBeVisitor', $options, false)) { - // TODO: should find a better way, also filter on remote initiator on non-federated ? - $orX->add($this->exprFilterInt('config', Circle::CFG_PERSONAL, $alias)); - } - if ($this->getBool('canBeVisitorOnOpen', $options, false)) { + + // if Member can be Visitor, we only filter access to Personal Circles + if ($this->getBool('viewableThroughKeyhole', $options, false)) { $andOpen = $expr->andX(); $andOpen->add($this->exprLimitBitwise('config', Circle::CFG_OPEN, $alias)); - $andOpen->add($this->exprFilterBitwise('config', Circle::CFG_REQUEST, $alias)); + $andOpen->add($this->exprLimitBitwise('config', Circle::CFG_VISIBLE, $alias)); + if (!$this->configService->getAppValueBool(ConfigService::KEYHOLE_CFG_REQUEST)) { + $andOpen->add($this->exprFilterBitwise('config', Circle::CFG_REQUEST, $alias)); + } $orX->add($andOpen); } @@ -1308,15 +1312,10 @@ protected function limitInitiatorVisibility(string $alias): ICompositeExpression /** - * CFG_SINGLE, CFG_HIDDEN and CFG_BACKEND means hidden from listing. - * * @param string $aliasCircle * @param int $flag */ - public function filterCircles( - string $aliasCircle, - int $flag = Circle::CFG_SINGLE | Circle::CFG_HIDDEN | Circle::CFG_BACKEND - ): void { + public function filterCircles(string $aliasCircle, int $flag): void { if ($flag === 0) { return; } diff --git a/lib/Db/MemberRequest.php b/lib/Db/MemberRequest.php index 9051ef9c9..46372adfb 100644 --- a/lib/Db/MemberRequest.php +++ b/lib/Db/MemberRequest.php @@ -36,9 +36,9 @@ use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\IFederatedUser; use OCA\Circles\Model\Circle; -use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\MemberProbe; /** * Class MemberRequest @@ -210,8 +210,7 @@ public function updateLevel(Member $member): void { /** * @param string $singleId * @param IFederatedUser|null $initiator - * @param RemoteInstance|null $remoteInstance - * @param Member|null $filter + * @param MemberProbe|null $probe * * @return Member[] * @throws RequestBuilderException @@ -219,22 +218,38 @@ public function updateLevel(Member $member): void { public function getMembers( string $singleId, ?IFederatedUser $initiator = null, - ?RemoteInstance $remoteInstance = null, - ?Member $filter = null + ?MemberProbe $probe = null ): array { + if (is_null($probe)) { + $probe = new MemberProbe(); + } + $qb = $this->getMemberSelectSql($initiator); $qb->limitToCircleId($singleId); - $qb->setOptions([CoreQueryBuilder::MEMBER], ['canBeVisitorOnOpen' => true]); + $qb->setOptions( + [CoreQueryBuilder::MEMBER], + array_merge( + $probe->getAsOptions(), + ['viewableThroughKeyhole' => true] + ) + ); + $qb->leftJoinCircle(CoreQueryBuilder::MEMBER, $initiator); $qb->leftJoinInvitedBy(CoreQueryBuilder::MEMBER); - if (!is_null($remoteInstance)) { + if ($probe->hasFilterRemoteInstance()) { $aliasCircle = $qb->generateAlias(CoreQueryBuilder::MEMBER, CoreQueryBuilder::CIRCLE); - $qb->limitToRemoteInstance(CoreQueryBuilder::MEMBER, $remoteInstance, true, $aliasCircle); + $qb->limitToRemoteInstance( + CoreQueryBuilder::MEMBER, + $probe->getFilterRemoteInstance(), + true, + $aliasCircle + ); } - if (!is_null($filter)) { - $qb->filterDirectMembership(CoreQueryBuilder::MEMBER, $filter); + + if ($probe->hasFilterMember()) { + $qb->filterDirectMembership(CoreQueryBuilder::MEMBER, $probe->getFilterMember()); } $qb->orderBy($qb->getDefaultSelectAlias() . '.level', 'desc'); @@ -290,7 +305,7 @@ public function getMember(string $circleId, string $singleId): Member { /** * @param string $memberId * @param FederatedUser|null $initiator - * @param bool $canBeVisitor + * @param MemberProbe|null $probe * * @return Member * @throws MemberNotFoundException @@ -299,13 +314,17 @@ public function getMember(string $circleId, string $singleId): Member { public function getMemberById( string $memberId, ?FederatedUser $initiator = null, - bool $canBeVisitor = false + ?MemberProbe $probe = null ): Member { + if (is_null($probe)) { + $probe = new MemberProbe(); + } + $qb = $this->getMemberSelectSql(); $qb->limitToMemberId($memberId); + $qb->setOptions([CoreQueryBuilder::MEMBER], $probe->getAsOptions()); if (!is_null($initiator)) { - $qb->setOptions([CoreQueryBuilder::MEMBER], ['canBeVisitor' => $canBeVisitor]); $qb->leftJoinCircle(CoreQueryBuilder::MEMBER, $initiator); } diff --git a/lib/Db/ShareWrapperRequest.php b/lib/Db/ShareWrapperRequest.php index f992dc8a5..7625bee07 100644 --- a/lib/Db/ShareWrapperRequest.php +++ b/lib/Db/ShareWrapperRequest.php @@ -35,6 +35,7 @@ use OCA\Circles\Exceptions\ShareWrapperNotFoundException; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Membership; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\ShareWrapper; use OCP\Files\NotFoundException; use OCP\Share\Exceptions\IllegalIDChangeException; @@ -307,12 +308,18 @@ public function getSharesByFileId(int $fileId, bool $getData = false): array { public function getSharedWith( FederatedUser $federatedUser, int $nodeId, - int $offset, - int $limit, - bool $getData = false + CircleProbe $probe ): array { $qb = $this->getShareSelectSql(); - $qb->setOptions([CoreQueryBuilder::SHARE], ['getData' => $getData, 'filterPersonalCircle' => false]); + $qb->setOptions( + [CoreQueryBuilder::SHARE], + array_merge( + $probe->getAsOptions(), + ['getData' => true] + ) + ); + + $getData = true; if ($getData) { $qb->leftJoinCircle(CoreQueryBuilder::SHARE, null, 'share_with'); } @@ -327,7 +334,7 @@ public function getSharedWith( $qb->limitToFileSource($nodeId); } - $qb->chunk($offset, $limit); + $qb->chunk($probe->getItemsOffset(), $probe->getItemsLimit()); return $this->getItemsFromRequest($qb); } @@ -450,4 +457,15 @@ public function delete(int $shareId): void { $qb->execute(); } + + + /** + * @param string $circleId + */ + public function deleteFromCircle(string $circleId): void { + $qb = $this->getShareDeleteSql(); + $qb->andWhere($qb->exprLimit('share_with', $circleId)); + + $qb->execute(); + } } diff --git a/lib/IQueryProbe.php b/lib/IQueryProbe.php new file mode 100644 index 000000000..971a89e5c --- /dev/null +++ b/lib/IQueryProbe.php @@ -0,0 +1,102 @@ + + * @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; + +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Model\Member; + +/** + * Interface IQueryProbe + * + * @package OCA\Circles + */ +interface IQueryProbe { + + + /** + * @return int + */ + public function getItemsOffset(): int; + + /** + * @return int + */ + public function getItemsLimit(): int; + + /** + * @return int + */ + public function getDetails(): int; + + /** + * @param int $details + * + * @return bool + */ + public function showDetails(int $details): bool; + + /** + * @return Circle + */ + public function getFilterCircle(): Circle; + + /** + * @return bool + */ + public function hasFilterCircle(): bool; + + /** + * @return Member + */ + public function getFilterMember(): Member; + + /** + * @return bool + */ + public function hasFilterMember(): bool; + + /** + * @return RemoteInstance + */ + public function getFilterRemoteInstance(): RemoteInstance; + + /** + * @return bool + */ + public function hasFilterRemoteInstance(): bool; + + /** + * @return array + */ + public function getAsOptions(): array; +} diff --git a/lib/Listeners/DeprecatedListener.php b/lib/Listeners/DeprecatedListener.php index 3da31f733..241df229e 100644 --- a/lib/Listeners/DeprecatedListener.php +++ b/lib/Listeners/DeprecatedListener.php @@ -31,7 +31,6 @@ namespace OCA\Circles\Listeners; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use Exception; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Exceptions\ContactAddressBookNotFoundException; @@ -45,6 +44,7 @@ use OCA\Circles\Exceptions\SingleCircleNotFoundException; use OCA\Circles\FederatedItems\MemberDisplayName; use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\FederatedEventService; use OCA\Circles\Service\FederatedUserService; @@ -111,8 +111,12 @@ public function userAccountUpdated(IUser $user) { $this->circleRequest->updateDisplayName($federatedUser->getSingleId(), $user->getDisplayName()); $this->federatedUserService->setCurrentUser($federatedUser); - $params = new SimpleDataStore(['includeSystemCircles' => true]); - $circles = $this->circleService->getCircles(null, null, $params); + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->mustBeMember() + ->canBeRequestingMembership(); + + $circles = $this->circleService->getCircles($probe); foreach ($circles as $circle) { $event = new FederatedEvent(MemberDisplayName::class); diff --git a/lib/Model/Probes/BasicProbe.php b/lib/Model/Probes/BasicProbe.php new file mode 100644 index 000000000..ee6a95dab --- /dev/null +++ b/lib/Model/Probes/BasicProbe.php @@ -0,0 +1,272 @@ + + * @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\Probes; + +use OCA\Circles\IQueryProbe; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Model\Member; + +/** + * Class BasicProbe + * + * @package OCA\Circles\Model\Probes + */ +class BasicProbe implements IQueryProbe { + public const DETAILS_NONE = 0; + public const DETAILS_ALL = 64; + + + /** @var int */ + private $itemsOffset = 0; + + /** @var int */ + private $itemsLimit = -1; + + /** @var int */ + private $details = 0; + + /** @var Circle */ + private $filterCircle; + + /** @var Member */ + private $filterMember; + + /** @var RemoteInstance */ + private $filterRemoteInstance; + + /** @var array */ + private $options = []; + + + /** + * @param int $itemsOffset + * + * @return BasicProbe + */ + public function setItemsOffset(int $itemsOffset): self { + $this->itemsOffset = $itemsOffset; + + return $this; + } + + /** + * @return int + */ + public function getItemsOffset(): int { + return $this->itemsOffset; + } + + + /** + * @param int $itemsLimit + * + * @return BasicProbe + */ + public function setItemsLimit(int $itemsLimit): self { + $this->itemsLimit = $itemsLimit; + + return $this; + } + + /** + * @return int + */ + public function getItemsLimit(): int { + return $this->itemsLimit; + } + + + /** + * @param int $details + * + * @return $this + */ + public function setDetails(int $details): self { + $this->details = $details; + } + + /** + * @return int + */ + public function getDetails(): int { + return $this->details; + } + + + /** + * @param int $details + * + * @return bool + */ + public function showDetails(int $details): bool { + return (($this->getDetails() & $details) !== 0); + } + + + /** + * @param Circle $filterCircle + * + * @return CircleProbe + */ + public function setFilterCircle(Circle $filterCircle): self { + $this->filterCircle = $filterCircle; + + return $this; + } + + /** + * @return Circle + */ + public function getFilterCircle(): Circle { + return $this->filterCircle; + } + + /** + * @return bool + */ + public function hasFilterCircle(): bool { + return !is_null($this->filterCircle); + } + + + /** + * @param Member $filterMember + * + * @return CircleProbe + */ + public function setFilterMember(Member $filterMember): self { + $this->filterMember = $filterMember; + + return $this; + } + + /** + * @return Member + */ + public function getFilterMember(): Member { + return $this->filterMember; + } + + /** + * @return bool + */ + public function hasFilterMember(): bool { + return !is_null($this->filterMember); + } + + + /** + * @param RemoteInstance $filterRemoteInstance + * + * @return CircleProbe + */ + public function setFilterRemoteInstance(RemoteInstance $filterRemoteInstance): self { + $this->filterRemoteInstance = $filterRemoteInstance; + + return $this; + } + + /** + * @return RemoteInstance + */ + public function getFilterRemoteInstance(): RemoteInstance { + return $this->filterRemoteInstance; + } + + /** + * @return bool + */ + public function hasFilterRemoteInstance(): bool { + return !is_null($this->filterRemoteInstance); + } + + + /** + * @param string $key + * @param string $value + * + * @return $this + */ + public function addOption(string $key, string $value): self { + $this->options[$key] = $value; + + return $this; + } + + /** + * @param string $key + * @param int $value + * + * @return $this + */ + public function addOptionInt(string $key, int $value): self { + $this->options[$key] = $value; + + return $this; + } + + /** + * @param string $key + * @param bool $value + * + * @return $this + */ + public function addOptionBool(string $key, bool $value): self { + $this->options[$key] = $value; + + return $this; + } + + /** + * @return array + */ + public function getAsOptions(): array { + return array_merge( + $this->options, + [ + 'offset' => $this->getItemsOffset(), + 'limit' => $this->getItemsLimit(), + 'details' => $this->getDetails(), + 'detailsAll' => ($this->getDetails() === self::DETAILS_ALL) + ] + ); + } + + + /** + * @return array + */ + public function JsonSerialize(): array { + return $this->getAsOptions(); + } +} diff --git a/lib/Model/Probes/CircleProbe.php b/lib/Model/Probes/CircleProbe.php new file mode 100644 index 000000000..7a5a3787f --- /dev/null +++ b/lib/Model/Probes/CircleProbe.php @@ -0,0 +1,180 @@ + + * @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\Probes; + +use OCA\Circles\Model\Circle; + +/** + * Class CircleProbe + * + * @package OCA\Circles\Model\Probes + */ +class CircleProbe extends MemberProbe { + + + /** @var array */ + public static $filters = [ + Circle::CFG_SINGLE, + Circle::CFG_HIDDEN, + Circle::CFG_BACKEND, + ]; + + /** @var int */ + private $include = 0; + + + /** + * @param bool $include + * + * @return $this + */ + public function includePersonalCircles(bool $include = true): self { + $this->include |= Circle::CFG_PERSONAL; + if (!$include) { + $this->include -= Circle::CFG_PERSONAL; + } + + return $this; + } + + /** + * @param bool $include + * + * @return $this + */ + public function includeSingleCircles(bool $include = true): self { + $this->include |= Circle::CFG_SINGLE; + if (!$include) { + $this->include -= Circle::CFG_SINGLE; + } + + return $this; + } + + /** + * @param bool $include + * + * @return $this + */ + public function includeSystemCircles(bool $include = true): self { + $this->include |= Circle::CFG_SYSTEM; + if (!$include) { + $this->include -= Circle::CFG_SYSTEM; + } + + return $this; + } + + /** + * @param bool $include + * + * @return $this + */ + public function includeHiddenCircles(bool $include = true): self { + $this->include |= Circle::CFG_HIDDEN; + if (!$include) { + $this->include -= Circle::CFG_HIDDEN; + } + + return $this; + } + + /** + * @param bool $include + * + * @return $this + */ + public function includeBackendCircles(bool $include = true): self { + $this->include |= Circle::CFG_BACKEND; + if (!$include) { + $this->include -= Circle::CFG_BACKEND; + } + + return $this; + } + + + /** + * @return int + */ + public function included(): int { + return $this->include; + } + + /** + * @param int $config + * + * @return bool + */ + public function isIncluded(int $config): bool { + return (($this->included() & $config) !== 0); + } + + /** + * @return int + */ + public function filtered(): int { + $filtered = 0; + foreach (self::$filters as $filter) { + if ($this->isIncluded($filter)) { + continue; + } + $filtered += $filter; + } + + return $filtered; + } + + /** + * @return array + */ + public function getAsOptions(): array { + return array_merge( + [ + 'included' => $this->included(), + 'includeHiddenCircles' => $this->isIncluded(Circle::CFG_HIDDEN), + 'includeBackendCircles' => $this->isIncluded(Circle::CFG_BACKEND), + 'includeSystemCircles' => $this->isIncluded(Circle::CFG_SYSTEM), + 'includePersonalCircles' => $this->isIncluded(Circle::CFG_PERSONAL), + ], + parent::getAsOptions() + ); + } + + + /** + * @return array + */ + public function JsonSerialize(): array { + return $this->getAsOptions(); + } +} diff --git a/lib/Model/Probes/MemberProbe.php b/lib/Model/Probes/MemberProbe.php new file mode 100644 index 000000000..8d3e62934 --- /dev/null +++ b/lib/Model/Probes/MemberProbe.php @@ -0,0 +1,160 @@ + + * @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\Probes; + +use OCA\Circles\Model\Member; + +/** + * Class CircleProbe + * + * @package OCA\Circles\Model\Probes + */ +class MemberProbe extends BasicProbe { + + + /** @var int */ + private $minimumLevel = Member::LEVEL_NONE; + + /** @var bool */ + private $emulateVisitor = false; + + /** @var bool */ + private $requestingMembership = false; + + + /** + * allow the initiator as a requesting member + * + * @param bool $can + * + * @return $this + */ + public function canBeRequestingMembership(bool $can = true): self { + $this->requestingMembership = $can; + + return $this; + } + + /** + * @return bool + */ + public function isRequestingMembership(): bool { + return $this->requestingMembership; + } + + + /** + * force the generation an initiator if visitor + * + * @return $this + */ + public function emulateVisitor(): self { + $this->emulateVisitor = true; + + return $this; + } + + public function isEmulatingVisitor(): bool { + return $this->emulateVisitor; + } + + + /** + * @return int + */ + public function getMinimumLevel(): int { + return $this->minimumLevel; + } + + /** + * @return $this + */ + public function mustBeMember(bool $must = true): self { + if ($must) { + $this->minimumLevel = Member::LEVEL_MEMBER; + } else { + $this->minimumLevel = Member::LEVEL_NONE; + } + + return $this; + } + + /** + * @return $this + */ + public function mustBeModerator(): self { + $this->minimumLevel = Member::LEVEL_MODERATOR; + + return $this; + } + + /** + * @return $this + */ + public function mustBeAdmin(): self { + $this->minimumLevel = Member::LEVEL_ADMIN; + + return $this; + } + + /** + * @return $this + */ + public function mustBeOwner(): self { + $this->minimumLevel = Member::LEVEL_OWNER; + + return $this; + } + + + /** + * @return array + */ + public function getAsOptions(): array { + return array_merge( + [ + 'minimumLevel' => $this->getMinimumLevel(), + 'emulateVisitor' => $this->isEmulatingVisitor(), + 'allowRequestingMembership' => $this->isRequestingMembership() + ], + parent::getAsOptions() + ); + } + + + /** + * @return array + */ + public function JsonSerialize(): array { + return $this->getAsOptions(); + } +} diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php index ed3ec359d..969fd28cf 100644 --- a/lib/Notification/Notifier.php +++ b/lib/Notification/Notifier.php @@ -42,6 +42,7 @@ use OCA\Circles\Exceptions\MemberNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\SingleCircleNotFoundException; +use OCA\Circles\Model\Probes\MemberProbe; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; use OCP\Contacts\IManager; @@ -170,10 +171,12 @@ public function prepare(INotification $notification, string $languageCode): INot */ private function prepareMemberNotification(INotification $notification) { $this->federatedUserService->initCurrentUser(); + $probe = new MemberProbe(); + $member = $this->memberService->getMemberById( $notification->getObjectId(), '', - true + $probe ); switch ($notification->getSubject()) { diff --git a/lib/Service/CircleService.php b/lib/Service/CircleService.php index 6801ee80d..a91193c62 100644 --- a/lib/Service/CircleService.php +++ b/lib/Service/CircleService.php @@ -63,6 +63,8 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\Probes\MemberProbe; use OCA\Circles\StatusCode; /** @@ -426,56 +428,35 @@ public function circleLeave(string $circleId, bool $force = false): array { */ public function getCircle( string $circleId, - int $filter = Circle::CFG_BACKEND | Circle::CFG_SINGLE | Circle::CFG_HIDDEN + ?CircleProbe $probe = null ): Circle { $this->federatedUserService->mustHaveCurrentUser(); return $this->circleRequest->getCircle( $circleId, $this->federatedUserService->getCurrentUser(), - $this->federatedUserService->getRemoteInstance(), - $filter + $probe ); } /** - * @param Circle|null $circleFilter - * @param Member|null $memberFilter - * @param SimpleDataStore|null $params + * @param CircleProbe|null $probe * * @return Circle[] * @throws InitiatorNotFoundException * @throws RequestBuilderException */ - public function getCircles( - ?Circle $circleFilter = null, - ?Member $memberFilter = null, - ?SimpleDataStore $params = null - ): array { + public function getCircles(?CircleProbe $probe = null): array { $this->federatedUserService->mustHaveCurrentUser(); - if ($params === null) { - $params = new SimpleDataStore(); + if (is_null($probe)) { + $probe = new CircleProbe(); } - $params->default( - [ - 'limit' => -1, - 'offset' => 0, - 'mustBeMember' => false, - 'includeHiddenCircles' => false, - 'includeBackendCircles' => false, - 'includeSystemCircles' => false, - 'includePersonalCircles' => false - ] - ); return $this->circleRequest->getCircles( - $circleFilter, - $memberFilter, $this->federatedUserService->getCurrentUser(), - $this->federatedUserService->getRemoteInstance(), - $params + $probe ); } @@ -597,9 +578,12 @@ public function confirmCircleNotFull(Circle $circle): void { * @throws RequestBuilderException */ public function isCircleFull(Circle $circle): bool { - $filter = new Member(); - $filter->setLevel(Member::LEVEL_MEMBER); - $members = $this->memberRequest->getMembers($circle->getSingleId(), null, null, $filter); + $filterMember = new Member(); + $filterMember->setLevel(Member::LEVEL_MEMBER); + $probe = new MemberProbe(); + $probe->setFilterMember($filterMember); + + $members = $this->memberRequest->getMembers($circle->getSingleId(), null, $probe); $limit = $this->getInt('members_limit', $circle->getSettings()); if ($limit === 0) { diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php index 8628292f3..4aa0ea09f 100644 --- a/lib/Service/ConfigService.php +++ b/lib/Service/ConfigService.php @@ -80,6 +80,7 @@ class ConfigService { public const HARD_MODERATION = 'hard_moderation'; public const FRONTEND_ENABLED = 'frontend_enabled'; + public const KEYHOLE_CFG_REQUEST = 'keyhole_cfg_request'; public const ROUTE_TO_CIRCLE = 'route_to_circle'; public const EVENT_EXAMPLES = 'event_examples'; @@ -89,6 +90,7 @@ class ConfigService { public const MIGRATION_BYPASS = 'migration_bypass'; public const MIGRATION_22 = 'migration_22'; + public const MIGRATION_22_CONFIRMED = 'migration_22_confirmed'; public const MIGRATION_RUN = 'migration_run'; public const MAINTENANCE_UPDATE = 'maintenance_update'; public const MAINTENANCE_RUN = 'maintenance_run'; @@ -142,6 +144,7 @@ class ConfigService { self::FRONTEND_ENABLED => '1', self::HARD_MODERATION => '0', + self::KEYHOLE_CFG_REQUEST => '0', self::ROUTE_TO_CIRCLE => 'contacts.contacts.directcircle', self::EVENT_EXAMPLES => '0', @@ -150,6 +153,7 @@ class ConfigService { self::ACTIVITY_ON_NEW_CIRCLE => '1', self::MIGRATION_BYPASS => '0', self::MIGRATION_22 => '0', + self::MIGRATION_22_CONFIRMED => '0', self::MIGRATION_RUN => '0', self::MAINTENANCE_UPDATE => '[]', self::MAINTENANCE_RUN => '0', diff --git a/lib/Service/FederatedUserService.php b/lib/Service/FederatedUserService.php index a90d3d4d2..38381c027 100644 --- a/lib/Service/FederatedUserService.php +++ b/lib/Service/FederatedUserService.php @@ -68,6 +68,7 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; @@ -544,7 +545,10 @@ public function commandLineInitiator( } if ($circleId !== '') { - $localCircle = $this->circleRequest->getCircle($circleId, null, null, 0); + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->canBeRequestingMembership(); + $localCircle = $this->circleRequest->getCircle($circleId, null, $probe); if ($this->configService->isLocalInstance($localCircle->getInstance())) { $this->setCurrentUser($localCircle->getOwner()); diff --git a/lib/Service/MaintenanceService.php b/lib/Service/MaintenanceService.php index f56bb3209..a927a4d29 100644 --- a/lib/Service/MaintenanceService.php +++ b/lib/Service/MaintenanceService.php @@ -31,16 +31,18 @@ namespace OCA\Circles\Service; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger; use Exception; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Db\ShareWrapperRequest; use OCA\Circles\Exceptions\InitiatorNotFoundException; use OCA\Circles\Exceptions\MaintenanceException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Model\Circle; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\ShareWrapper; use OCP\IUserManager; use Symfony\Component\Console\Output\OutputInterface; @@ -65,6 +67,9 @@ class MaintenanceService { /** @var MemberRequest */ private $memberRequest; + /** @var ShareWrapperRequest */ + private $shareWrapperRequest; + /** @var SyncService */ private $syncService; @@ -91,6 +96,7 @@ class MaintenanceService { * @param IUserManager $userManager * @param CircleRequest $circleRequest * @param MemberRequest $memberRequest + * @param ShareWrapperRequest $shareWrapperRequest * @param SyncService $syncService * @param FederatedUserService $federatedUserService * @param EventWrapperService $eventWrapperService @@ -101,6 +107,7 @@ public function __construct( IUserManager $userManager, CircleRequest $circleRequest, MemberRequest $memberRequest, + ShareWrapperRequest $shareWrapperRequest, SyncService $syncService, FederatedUserService $federatedUserService, EventWrapperService $eventWrapperService, @@ -110,6 +117,7 @@ public function __construct( $this->userManager = $userManager; $this->circleRequest = $circleRequest; $this->memberRequest = $memberRequest; + $this->shareWrapperRequest = $shareWrapperRequest; $this->syncService = $syncService; $this->federatedUserService = $federatedUserService; $this->eventWrapperService = $eventWrapperService; @@ -231,8 +239,10 @@ private function runMaintenance4(): void { } try { // TODO: waiting for confirmation of a good migration before cleaning orphan shares -// $this->output('remove deprecated shares'); -// $this->removeDeprecatedShares(); + if ($this->configService->getAppValue(ConfigService::MIGRATION_22_CONFIRMED)) { + $this->output('remove deprecated shares'); + $this->removeDeprecatedShares(); + } } catch (Exception $e) { } @@ -262,7 +272,11 @@ private function runMaintenance5(): void { * @throws RequestBuilderException */ private function removeCirclesWithNoOwner(): void { - $circles = $this->circleService->getCircles(); + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->includeSingleCircles() + ->includePersonalCircles(); + $circles = $this->circleService->getCircles($probe); foreach ($circles as $circle) { if (!$circle->hasOwner()) { $this->circleRequest->delete($circle); @@ -288,25 +302,29 @@ private function removeMembersWithNoCircles(): void { private function removeDeprecatedShares(): void { -// $circles = array_map( -// function(DeprecatedCircle $circle) { -// return $circle->getUniqueId(); -// }, $this->circlesRequest->forceGetCircles() -// ); -// -// $shares = array_unique( -// array_map( -// function($share) { -// return $share['share_with']; -// }, $this->fileSharesRequest->getShares() -// ) -// ); -// -// foreach ($shares as $share) { -// if (!in_array($share, $circles)) { -// $this->fileSharesRequest->removeSharesToCircleId($share); -// } -// } + $probe = new CircleProbe(); + $probe->includePersonalCircles() + ->includeSystemCircles(); + + $circles = array_map( + function (Circle $circle) { + return $circle->getSingleId(); + }, $this->circleRequest->getCircles(null, $probe) + ); + + $shares = array_unique( + array_map( + function (ShareWrapper $share) { + return $share->getSharedWith(); + }, $this->shareWrapperRequest->getShares() + ) + ); + + foreach ($shares as $share) { + if (!in_array($share, $circles)) { + $this->shareWrapperRequest->deleteFromCircle($share); + } + } } @@ -315,10 +333,16 @@ private function removeDeprecatedShares(): void { * @throws InitiatorNotFoundException */ private function refreshDisplayName(): void { - $params = new SimpleDataStore(['includeSystemCircles' => true]); $circleFilter = new Circle(); $circleFilter->setConfig(Circle::CFG_SINGLE); - $circles = $this->circleService->getCircles($circleFilter, null, $params); + + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->setFilterCircle($circleFilter) + ->mustBeMember() + ->canBeRequestingMembership(); + + $circles = $this->circleService->getCircles($probe); foreach ($circles as $circle) { $owner = $circle->getOwner(); diff --git a/lib/Service/MemberService.php b/lib/Service/MemberService.php index c6bf0996c..38b81e016 100644 --- a/lib/Service/MemberService.php +++ b/lib/Service/MemberService.php @@ -63,6 +63,7 @@ use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\MemberProbe; /** * Class MemberService @@ -145,7 +146,7 @@ public function __construct( public function getMemberById( string $memberId, string $circleId = '', - bool $canBeVisitor = false + ?MemberProbe $probe = null ): Member { $this->federatedUserService->mustHaveCurrentUser(); @@ -153,7 +154,7 @@ public function getMemberById( $this->memberRequest->getMemberById( $memberId, $this->federatedUserService->getCurrentUser(), - $canBeVisitor + $probe ); if ($circleId !== '' && $member->getCircle()->getSingleId() !== $circleId) { throw new MemberNotFoundException(); @@ -173,10 +174,16 @@ public function getMemberById( public function getMembers(string $circleId): array { $this->federatedUserService->mustHaveCurrentUser(); + $probe = new MemberProbe(); + if ($this->federatedUserService->hasRemoteInstance()) { + $probe->setFilterRemoteInstance($this->federatedUserService->getRemoteInstance()); + } + $probe->mustBeMember(); + return $this->memberRequest->getMembers( $circleId, $this->federatedUserService->getCurrentUser(), - $this->federatedUserService->getRemoteInstance() + $probe ); } diff --git a/lib/Service/MembershipService.php b/lib/Service/MembershipService.php index dbb07e1aa..55e4c975d 100644 --- a/lib/Service/MembershipService.php +++ b/lib/Service/MembershipService.php @@ -32,7 +32,6 @@ namespace OCA\Circles\Service; use ArtificialOwl\MySmallPhpTools\Exceptions\ItemNotFoundException; -use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore; use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\MemberRequest; @@ -44,6 +43,7 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; use OCA\Circles\Model\Membership; +use OCA\Circles\Model\Probes\CircleProbe; /** * Class MembershipService @@ -128,14 +128,9 @@ public function onUpdate(string $singleId): void { * */ public function manageAll(): void { - $params = new SimpleDataStore(['includeSystemCircles' => true]); - $circles = $this->circleRequest->getCircles( - null, - null, - null, - null, - $params - ); + $probe = new CircleProbe(); + $probe->includeSystemCircles(); + $circles = $this->circleRequest->getCircles(null, $probe); $this->outputService->startMigrationProgress(sizeof($circles)); diff --git a/lib/Service/RemoteDownstreamService.php b/lib/Service/RemoteDownstreamService.php index b4a9cc551..6c40b55dd 100644 --- a/lib/Service/RemoteDownstreamService.php +++ b/lib/Service/RemoteDownstreamService.php @@ -53,6 +53,7 @@ use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\Probes\CircleProbe; /** * Class RemoteDownstreamService @@ -244,7 +245,10 @@ private function verifyCircle(FederatedEvent $event): bool { $circle = $event->getCircle(); try { - $localCircle = $this->circleRequest->getCircle($circle->getSingleId(), null, null, 0); + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->includePersonalCircles(); + $localCircle = $this->circleRequest->getCircle($circle->getSingleId(), null, $probe); } catch (CircleNotFoundException $e) { try { $this->remoteService->syncRemoteCircle( diff --git a/lib/Service/ShareWrapperService.php b/lib/Service/ShareWrapperService.php index b52df30f5..81bd5ece8 100644 --- a/lib/Service/ShareWrapperService.php +++ b/lib/Service/ShareWrapperService.php @@ -36,6 +36,7 @@ use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\ShareWrapperNotFoundException; use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\ShareWrapper; use OCP\Files\NotFoundException; use OCP\Share\IShare; @@ -166,9 +167,7 @@ public function getShareByToken(string $token, ?FederatedUser $federatedUser = n /** * @param FederatedUser $federatedUser * @param int $nodeId - * @param int $offset - * @param int $limit - * @param bool $getData + * @param CircleProbe|null $probe * * @return ShareWrapper[] * @throws RequestBuilderException @@ -176,11 +175,9 @@ public function getShareByToken(string $token, ?FederatedUser $federatedUser = n public function getSharedWith( FederatedUser $federatedUser, int $nodeId, - int $offset, - int $limit, - bool $getData = false + ?CircleProbe $probe ): array { - return $this->shareWrapperRequest->getSharedWith($federatedUser, $nodeId, $offset, $limit, $getData); + return $this->shareWrapperRequest->getSharedWith($federatedUser, $nodeId, $probe); } diff --git a/lib/ShareByCircleProvider.php b/lib/ShareByCircleProvider.php index 11216f976..0a993a4e8 100644 --- a/lib/ShareByCircleProvider.php +++ b/lib/ShareByCircleProvider.php @@ -61,6 +61,7 @@ use OCA\Circles\FederatedItems\Files\FileUnshare; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Helpers\MemberHelper; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\ShareWrapper; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\EventService; @@ -545,12 +546,16 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset): arra } $federatedUser = $this->federatedUserService->getLocalFederatedUser($userId); + $probe = new CircleProbe(); + $probe->includePersonalCircles() + ->mustBeMember() + ->setItemsLimit((int)$limit) + ->setItemsOffset((int)$offset); + $wrappedShares = $this->shareWrapperService->getSharedWith( $federatedUser, (!is_null($node)) ? $node->getId() : 0, - $limit, - $offset, - true + $probe ); return array_filter(