diff --git a/appinfo/routes.php b/appinfo/routes.php index 9b4b6d21e..4f7c4a896 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -55,6 +55,7 @@ ], ['name' => 'Local#circleJoin', 'url' => '/circles/{circleId}/join', 'verb' => 'PUT'], ['name' => 'Local#circleLeave', 'url' => '/circles/{circleId}/leave', 'verb' => 'PUT'], + ['name' => 'Local#memberships', 'url' => '/memberships', 'verb' => 'GET'], ['name' => 'Local#editName', 'url' => '/circles/{circleId}/name', 'verb' => 'PUT'], ['name' => 'Local#editDescription', 'url' => '/circles/{circleId}/description', 'verb' => 'PUT'], @@ -93,6 +94,7 @@ ], ['name' => 'Admin#circleJoin', 'url' => '/admin/{emulated}/circles/{circleId}/join', 'verb' => 'PUT'], ['name' => 'Admin#circleLeave', 'url' => '/admin/{emulated}/circles/{circleId}/leave', 'verb' => 'PUT'], + ['name' => 'Admin#memberships', 'url' => '/admin/{emulated}/memberships', 'verb' => 'GET'], ['name' => 'Admin#editName', 'url' => '/admin/{emulated}/circles/{circleId}/name', 'verb' => 'PUT'], ['name' => 'Admin#editDescription', 'url' => '/admin/{emulated}/circles/{circleId}/description', 'verb' => 'PUT'], ['name' => 'Admin#editSetting', 'url' => '/admin/{emulated}/circles/{circleId}/setting', 'verb' => 'PUT'], diff --git a/lib/Controller/AdminController.php b/lib/Controller/AdminController.php index 37d7d31a4..cf3170e2d 100644 --- a/lib/Controller/AdminController.php +++ b/lib/Controller/AdminController.php @@ -31,8 +31,6 @@ namespace OCA\Circles\Controller; -use OCA\Circles\Tools\Traits\TDeserialize; -use OCA\Circles\Tools\Traits\TNCLogger; use Exception; use OCA\Circles\Exceptions\ContactAddressBookNotFoundException; use OCA\Circles\Exceptions\ContactFormatException; @@ -46,12 +44,15 @@ use OCA\Circles\Model\Member; use OCA\Circles\Model\Probes\BasicProbe; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\Probes\MemberProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; use OCA\Circles\Service\MembershipService; use OCA\Circles\Service\SearchService; +use OCA\Circles\Tools\Traits\TDeserialize; +use OCA\Circles\Tools\Traits\TNCLogger; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCSController; @@ -150,11 +151,11 @@ public function create( } catch (Exception $e) { $this->e( $e, [ - 'emulated' => $emulated, - 'name' => $name, - 'members' => $personal, - 'local' => $local - ] + 'emulated' => $emulated, + 'name' => $name, + 'members' => $personal, + 'local' => $local + ] ); throw new OcsException($e->getMessage(), $e->getCode()); } @@ -211,11 +212,11 @@ public function memberAdd(string $emulated, string $circleId, string $userId, in } catch (Exception $e) { $this->e( $e, [ - 'emulated' => $emulated, - 'circleId' => $circleId, - 'userId' => $userId, - 'type' => $type - ] + 'emulated' => $emulated, + 'circleId' => $circleId, + 'userId' => $userId, + 'type' => $type + ] ); throw new OCSException($e->getMessage(), $e->getCode()); } @@ -263,6 +264,7 @@ public function memberLevel(string $emulated, string $circleId, string $memberId * @param string $emulated * @param int $limit * @param int $offset + * * @return DataResponse * @throws OCSException */ @@ -468,7 +470,12 @@ public function editDescription(string $emulated, string $circleId, string $valu * @return DataResponse * @throws OCSException */ - public function editSetting(string $emulated, string $circleId, string $setting, ?string $value = null): DataResponse { + public function editSetting( + string $emulated, + string $circleId, + string $setting, + ?string $value = null + ): DataResponse { try { $this->setLocalFederatedUser($emulated); @@ -482,9 +489,6 @@ public function editSetting(string $emulated, string $circleId, string $setting, } - - - /** * @param string $emulated * @param string $circleId @@ -528,6 +532,39 @@ public function link(string $emulated, string $circleId, string $singleId): Data } + /** + * @param string $emulated + * @param string $type + * @param int $level + * @param string $details + * + * @return DataResponse + * @throws OCSException + */ + public function memberships( + string $emulated, + string $type = 'inherited', + int $level = Member::LEVEL_MEMBER, + string $details = 'false' + ): DataResponse { + try { + $this->setLocalFederatedUser($emulated); + + $probe = new MemberProbe(); + $probe->setMinimumLevel($level); + $probe->initiatorAsDirectMember((strtolower($type) === 'direct')); + $probe->detailedMembership(strtolower($details) === 'true'); + + $result = $this->memberService->getMemberships($probe); + + return new DataResponse($this->serializeArray($result)); + } catch (Exception $e) { + $this->e($e, ['type' => $type, 'level' => $level]); + throw new OCSException($e->getMessage(), $e->getCode()); + } + } + + /** * @param string $emulated * diff --git a/lib/Controller/LocalController.php b/lib/Controller/LocalController.php index efa78363b..94ce73b92 100644 --- a/lib/Controller/LocalController.php +++ b/lib/Controller/LocalController.php @@ -31,8 +31,6 @@ namespace OCA\Circles\Controller; -use OCA\Circles\Tools\Traits\TDeserialize; -use OCA\Circles\Tools\Traits\TNCLogger; use Exception; use OCA\Circles\Exceptions\FederatedUserException; use OCA\Circles\Exceptions\FederatedUserNotFoundException; @@ -44,12 +42,15 @@ use OCA\Circles\Model\Member; use OCA\Circles\Model\Probes\BasicProbe; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\Probes\MemberProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; use OCA\Circles\Service\MembershipService; use OCA\Circles\Service\SearchService; +use OCA\Circles\Tools\Traits\TDeserialize; +use OCA\Circles\Tools\Traits\TNCLogger; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCSController; @@ -326,6 +327,39 @@ public function circleLeave(string $circleId): DataResponse { } + /** + * @NoAdminRequired + * + * @param string $type + * @param int $level + * @param bool $details + * + * @return DataResponse + * @throws OCSException + */ + public function memberships( + string $type = 'inherited', + int $level = Member::LEVEL_MEMBER, + string $details = 'false' + ): DataResponse { + try { + $this->setCurrentFederatedUser(); + + $probe = new MemberProbe(); + $probe->setMinimumLevel($level) + ->initiatorAsDirectMember((strtolower($type) === 'direct')) + ->detailedMembership(strtolower($details) === 'true'); + + $result = $this->memberService->getMemberships($probe); + + return new DataResponse($this->serializeArray($result)); + } catch (Exception $e) { + $this->e($e, ['type' => $type, 'level' => $level]); + throw new OCSException($e->getMessage(), $e->getCode()); + } + } + + /** * @NoAdminRequired * @@ -512,7 +546,11 @@ public function editDescription(string $circleId, string $value): DataResponse { * @return DataResponse * @throws OCSException */ - public function editSetting(string $circleId, string $setting, ?string $value = null): DataResponse { + public function editSetting( + string $circleId, + string $setting, + ?string $value = null + ): DataResponse { try { $this->setCurrentFederatedUser(); diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index 5f1992e7b..8ef850705 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -163,6 +163,13 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { ] ], self::MEMBERSHIPS => [ + self::CIRCLE => [ + self::MEMBERSHIPS => [ // needed ? + self::CONFIG, + self::INITIATOR + ], + self::INITIATOR => [self::INHERITED_BY => [self::MEMBERSHIPS]] + ], self::CONFIG ], self::SHARE => [ @@ -385,6 +392,14 @@ public function limitToShareParent(int $shareId): void { } + /** + * @param int $level + */ + public function minLevel(int $level): void { + $this->gt('level', $level, true); + } + + /** * @param Circle $circle */ @@ -1131,7 +1146,6 @@ public function leftJoinInitiator( ) ); - $listMembershipCircleAlias = [$aliasMembership]; if ($this->getBool('initiatorDirectMember', $options, false)) { try { diff --git a/lib/Db/MembershipRequest.php b/lib/Db/MembershipRequest.php index 0d1f5ccd5..6cec645e8 100644 --- a/lib/Db/MembershipRequest.php +++ b/lib/Db/MembershipRequest.php @@ -32,8 +32,10 @@ namespace OCA\Circles\Db; use OCA\Circles\Exceptions\MembershipNotFoundException; +use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Membership; +use OCA\Circles\Model\Probes\MemberProbe; use OCP\DB\QueryBuilder\IQueryBuilder; /** @@ -102,12 +104,38 @@ public function getMembership(string $circleId, string $singleId): Membership { } + /** + * @param MemberProbe|null $probe + * @param FederatedUser|null $initiator + * + * @return Membership[] + * @throws RequestBuilderException + */ + public function getMemberships(FederatedUser $initiator, MemberProbe $probe): array { + $qb = $this->getMembershipSelectSql(); + $qb->limitToSingleId($initiator->getSingleId()); + $qb->leftJoinCircleConfig(CoreQueryBuilder::MEMBERSHIPS); + + $qb->minLevel($probe->getMinimumLevel()); + if ($probe->directMemberInitiator()) { + $qb->limitInt('inheritance_depth', 1); + } + + if ($probe->isDetailedMembership()) { + $qb->setOptions([CoreQueryBuilder::MEMBERSHIPS, CoreQueryBuilder::CIRCLE], ['getData' => true]); + $qb->leftJoinCircle(CoreQueryBuilder::MEMBERSHIPS, $initiator); + } + + return $this->getItemsFromRequest($qb); + } + + /** * @param string $singleId * * @return Membership[] */ - public function getMemberships(string $singleId): array { + public function getMembershipsBySingleId(string $singleId): array { $qb = $this->getMembershipSelectSql(); $qb->limitToSingleId($singleId); $qb->leftJoinCircleConfig(CoreQueryBuilder::MEMBERSHIPS); diff --git a/lib/Model/Membership.php b/lib/Model/Membership.php index bba5145ce..59203854e 100644 --- a/lib/Model/Membership.php +++ b/lib/Model/Membership.php @@ -74,6 +74,9 @@ class Membership extends ManagedModel implements IDeserializable, IQueryRow, Jso /** @var array */ private $inheritanceDetails = []; + /** @var Circle */ + private $circle; + /** * Membership constructor. @@ -271,6 +274,21 @@ public function getInheritanceDetails(): array { } + public function hasCircle(): bool { + return (!is_null($this->circle)); + } + + public function setCircle(Circle $circle): self { + $this->circle = $circle; + + return $this; + } + + public function getCircle(): Circle { + return $this->circle; + } + + /** * @param array $data * @@ -315,6 +333,8 @@ public function importFromDatabase(array $data, string $prefix = ''): IQueryRow $this->setInheritancePath($this->getArray($prefix . 'inheritance_path', $data)); $this->setInheritanceDepth($this->getInt($prefix . 'inheritance_depth', $data)); + $this->getManager()->manageImportFromDatabase($this, $data, $prefix); + return $this; } @@ -338,6 +358,11 @@ public function jsonSerialize(): array { $result['inheritanceDetails'] = $this->getInheritanceDetails(); } + if ($this->hasCircle()) { + $result['circle'] = $this->getCircle(); + } + return $result; } + } diff --git a/lib/Model/ModelManager.php b/lib/Model/ModelManager.php index 175214b90..09620ad2b 100644 --- a/lib/Model/ModelManager.php +++ b/lib/Model/ModelManager.php @@ -31,7 +31,6 @@ namespace OCA\Circles\Model; -use OCA\Circles\Tools\Traits\TNCLogger; use OCA\Circles\AppInfo\Application; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\CoreQueryBuilder; @@ -57,6 +56,7 @@ use OCA\Circles\Service\InterfaceService; use OCA\Circles\Service\MembershipService; use OCA\Circles\Service\RemoteService; +use OCA\Circles\Tools\Traits\TNCLogger; use OCP\IURLGenerator; /** @@ -208,7 +208,7 @@ public function getRemoteInheritedMembers(Circle $circle, bool $detailed = false * @param IEntity $member */ public function getMemberships(IEntity $member): void { - $memberships = $this->membershipRequest->getMemberships($member->getSingleId()); + $memberships = $this->membershipRequest->getMembershipsBySingleId($member->getSingleId()); $member->setMemberships($memberships); } @@ -245,6 +245,12 @@ public function manageImportFromDatabase(ManagedModel $model, array $data, strin } } + if ($model instanceof Membership) { + if ($base === '') { + $base = CoreQueryBuilder::MEMBERSHIPS; + } + } + if ($model instanceof ShareWrapper) { if ($base === '') { $base = CoreQueryBuilder::SHARE; @@ -272,6 +278,10 @@ private function importBasedOnPath(ManagedModel $model, array $data, string $pat $this->importIntoMember($model, $data, $path, $prefix); } + if ($model instanceof Membership) { + $this->importIntoMembership($model, $data, $path, $prefix); + } + if ($model instanceof FederatedUser) { $this->importIntoFederatedUser($model, $data, $path, $prefix); } @@ -391,6 +401,31 @@ private function importIntoMember(Member $member, array $data, string $path, str } + /** + * @param Membership $membership + * @param array $data + * @param string $path + * @param string $prefix + */ + private function importIntoMembership( + Membership $membership, + array $data, + string $path, + string $prefix + ): void { + switch ($path) { + case CoreQueryBuilder::CIRCLE: + try { + $circle = new Circle(); + $circle->importFromDatabase($data, $prefix); + $membership->setCircle($circle); + } catch (CircleNotFoundException $e) { + } + break; + } + } + + /** * @param FederatedUser $federatedUser * @param array $data diff --git a/lib/Model/Probes/MemberProbe.php b/lib/Model/Probes/MemberProbe.php index e2cdb1bb8..60a1f42c5 100644 --- a/lib/Model/Probes/MemberProbe.php +++ b/lib/Model/Probes/MemberProbe.php @@ -53,6 +53,9 @@ class MemberProbe extends BasicProbe { /** @var bool */ private $initiatorDirectMember = false; + /** @var bool */ + private $detailedMembership = false; + /** * allow the initiator as a requesting member @@ -75,6 +78,19 @@ public function isRequestingMembership(): bool { } + /** + * returns memberships with details about Circle and Initiator + */ + public function detailedMembership(bool $detailed = true): self { + $this->detailedMembership = $detailed; + + return $this; + } + + public function isDetailedMembership(): bool { + return $this->detailedMembership; + } + /** * @param bool $include * @@ -110,6 +126,17 @@ public function isEmulatingVisitor(): bool { } + /** + * @param int $level + * + * @return $this + */ + public function setMinimumLevel(int $level): self { + $this->minimumLevel = $level; + + return $this; + } + /** * @return int */ diff --git a/lib/Service/MemberService.php b/lib/Service/MemberService.php index 58e1d261c..4f4967297 100644 --- a/lib/Service/MemberService.php +++ b/lib/Service/MemberService.php @@ -33,6 +33,7 @@ use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Db\MembershipRequest; use OCA\Circles\Exceptions\CircleNotFoundException; use OCA\Circles\Exceptions\ContactAddressBookNotFoundException; use OCA\Circles\Exceptions\ContactFormatException; @@ -59,6 +60,7 @@ use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; +use OCA\Circles\Model\Membership; use OCA\Circles\Model\Probes\MemberProbe; use OCA\Circles\Tools\Model\SimpleDataStore; use OCA\Circles\Tools\Traits\TArrayTools; @@ -82,6 +84,9 @@ class MemberService { /** @var MemberRequest */ private $memberRequest; + /** @var MembershipRequest */ + private $membershipRequest; + /** @var FederatedUserService */ private $federatedUserService; @@ -100,13 +105,16 @@ class MemberService { * * @param CircleRequest $circleRequest * @param MemberRequest $memberRequest + * @param MembershipRequest $membershipRequest * @param FederatedUserService $federatedUserService + * @param MembershipService $membershipService * @param FederatedEventService $federatedEventService * @param RemoteStreamService $remoteStreamService */ public function __construct( CircleRequest $circleRequest, MemberRequest $memberRequest, + MembershipRequest $membershipRequest, FederatedUserService $federatedUserService, MembershipService $membershipService, FederatedEventService $federatedEventService, @@ -114,6 +122,7 @@ public function __construct( ) { $this->circleRequest = $circleRequest; $this->memberRequest = $memberRequest; + $this->membershipRequest = $membershipRequest; $this->federatedUserService = $federatedUserService; $this->membershipService = $membershipService; $this->federatedEventService = $federatedEventService; @@ -367,4 +376,27 @@ public function insertOrUpdate(Member $member): bool { return true; } + + + /** + * @param MemberProbe|null $probe + * + * @return Membership[] + * @throws InitiatorNotFoundException + * @throws RequestBuilderException + */ + public function getMemberships(?MemberProbe $probe = null): array { + $this->federatedUserService->mustHaveCurrentUser(); + + if (is_null($probe)) { + $probe = new MemberProbe(); + $probe->mustBeMember(); + } + + return $this->membershipRequest->getMemberships( + $this->federatedUserService->getCurrentUser(), + $probe + ); + } + } diff --git a/lib/Service/MembershipService.php b/lib/Service/MembershipService.php index faa535376..cbd69ea8e 100644 --- a/lib/Service/MembershipService.php +++ b/lib/Service/MembershipService.php @@ -31,8 +31,6 @@ namespace OCA\Circles\Service; -use OCA\Circles\Tools\Exceptions\ItemNotFoundException; -use OCA\Circles\Tools\Traits\TNCLogger; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\MemberRequest; use OCA\Circles\Db\MembershipRequest; @@ -44,6 +42,8 @@ use OCA\Circles\Model\FederatedUser; use OCA\Circles\Model\Member; use OCA\Circles\Model\Membership; +use OCA\Circles\Tools\Exceptions\ItemNotFoundException; +use OCA\Circles\Tools\Traits\TNCLogger; /** * Class MembershipService @@ -232,7 +232,7 @@ private function generateMemberships( * @return int */ private function updateMembershipsDatabase(string $singleId, array $memberships): int { - $known = $this->membershipRequest->getMemberships($singleId); + $known = $this->membershipRequest->getMembershipsBySingleId($singleId); $deprecated = $this->removeDeprecatedMemberships($memberships, $known); if (!empty($deprecated)) {