From 4e941f18964cc241a4d04a4a6472cc87260161b2 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 29 Jun 2021 11:02:58 -0100 Subject: [PATCH] Overwrite initiator based on direct membership Signed-off-by: Maxence Lange --- lib/Db/CircleRequest.php | 14 ++++++-- lib/Db/CoreQueryBuilder.php | 66 +++++++++++++++++++++++++++++++------ lib/Model/Circle.php | 24 +++++++++++++- lib/Model/ModelManager.php | 9 +++++ 4 files changed, 99 insertions(+), 14 deletions(-) diff --git a/lib/Db/CircleRequest.php b/lib/Db/CircleRequest.php index 88a017cdf..2b5bce4c3 100644 --- a/lib/Db/CircleRequest.php +++ b/lib/Db/CircleRequest.php @@ -174,8 +174,9 @@ public function getCircles( $qb->setOptions( [CoreQueryBuilder::CIRCLE], [ - 'getData' => true, - 'mustBeMember' => $params->gBool('mustBeMember') + 'getData' => true, + 'mustBeMember' => $params->gBool('mustBeMember'), + 'initiatorDirectMember' => true ] ); @@ -239,7 +240,14 @@ public function getCircle( int $filter = Circle::CFG_BACKEND | Circle::CFG_SINGLE | Circle::CFG_HIDDEN ): Circle { $qb = $this->getCircleSelectSql(); - $qb->setOptions([CoreQueryBuilder::CIRCLE], ['getData' => true, 'canBeVisitor' => true]); + $qb->setOptions( + [CoreQueryBuilder::CIRCLE], + [ + 'getData' => true, + 'canBeVisitor' => true, + 'initiatorDirectMember' => true + ] + ); $qb->limitToUniqueId($id); $qb->filterCircles(CoreQueryBuilder::CIRCLE, $filter); diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index fc4f2f872..bff12154d 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -68,6 +68,7 @@ class CoreQueryBuilder extends NC22ExtendedQueryBuilder { const REMOTE = 'remote'; const BASED_ON = 'basedon'; const INITIATOR = 'initiator'; + const DIRECT_INITIATOR = 'initiatordirect'; const MEMBERSHIPS = 'memberships'; const CONFIG = 'config'; const UPSTREAM_MEMBERSHIPS = 'upstreammemberships'; @@ -88,23 +89,26 @@ class CoreQueryBuilder extends NC22ExtendedQueryBuilder { self::MEMBER ], self::CIRCLE => [ - self::OPTIONS => [ + self::OPTIONS => [ ], self::MEMBER, self::MEMBER_COUNT, - self::OWNER => [ + self::OWNER => [ self::BASED_ON ], - self::MEMBERSHIPS => [ + self::MEMBERSHIPS => [ self::CONFIG ], - self::INITIATOR => [ + self::DIRECT_INITIATOR => [ + self::BASED_ON + ], + self::INITIATOR => [ self::BASED_ON, self::INHERITED_BY => [ self::MEMBERSHIPS ] ], - self::REMOTE => [ + self::REMOTE => [ self::MEMBER, self::CIRCLE => [ self::OWNER @@ -1135,6 +1139,26 @@ public function leftJoinInitiator( return; } + // bypass memberships + if ($this->getBool('initiatorDirectMember', $options, false)) { + try { + $aliasDirectInitiator = $this->generateAlias($alias, self::DIRECT_INITIATOR, $options); + + $this->generateMemberSelectAlias($aliasDirectInitiator) + ->leftJoin( + $helperAlias, + CoreRequestBuilder::TABLE_MEMBER, + $aliasDirectInitiator, + $expr->andX( + $this->exprLimit('single_id', $initiator->getSingleId(), $aliasDirectInitiator), + $expr->eq($aliasDirectInitiator . '.circle_id', $helperAlias . '.' . $field) + ) + ); + } catch (RequestBuilderException $e) { + } + } + + try { $aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options); $this->leftJoin( @@ -1164,11 +1188,10 @@ public function leftJoinInitiator( 'instance' => $initiator->getInstance() ]; } - $this->generateMemberSelectAlias($aliasInitiator, $default); - - $this->generateMemberSelectAlias($aliasInheritedBy); $aliasInheritedByMembership = $this->generateAlias($aliasInheritedBy, self::MEMBERSHIPS); - $this->generateMembershipSelectAlias($aliasMembership, $aliasInheritedByMembership); + $this->generateMemberSelectAlias($aliasInitiator, $default) + ->generateMemberSelectAlias($aliasInheritedBy) + ->generateMembershipSelectAlias($aliasMembership, $aliasInheritedByMembership); } catch (RequestBuilderException $e) { } } @@ -1183,6 +1206,11 @@ public function leftJoinInitiator( protected function limitInitiatorVisibility(string $alias): ICompositeExpression { $aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options); $aliasMembershipCircle = $this->generateAlias($aliasMembership, self::CONFIG, $options); + $levelCheck = [$aliasMembership]; + + if ($this->getBool('initiatorDirectMember', $options, false)) { + array_push($levelCheck, $this->generateAlias($alias, self::DIRECT_INITIATOR, $options)); + } $filterPersonalCircle = $this->getBool('filterPersonalCircle', $options, true); @@ -1193,6 +1221,7 @@ protected function limitInitiatorVisibility(string $alias): ICompositeExpression // - 2 (Personal), if initiator is owner) // - 4 (Visible to everyone) $orX = $expr->orX(); + if ($filterPersonalCircle) { $orX->add( $expr->andX( @@ -1204,7 +1233,7 @@ protected function limitInitiatorVisibility(string $alias): ICompositeExpression $andXMember = $expr->andX(); $andXMember->add( - $expr->gte($aliasMembership . '.level', $this->createNamedParameter(Member::LEVEL_MEMBER)) + $this->orXCheckLevel($levelCheck, Member::LEVEL_MEMBER), ); if ($filterPersonalCircle) { $andXMember->add( @@ -1570,5 +1599,22 @@ public function getAvailablePath(string $prefix): array { return $path; } + + /** + * @param array $aliases + * @param int $level + * + * @return ICompositeExpression + */ + private function orXCheckLevel(array $aliases, int $level): ICompositeExpression { + $expr = $this->expr(); + $orX = $expr->orX(); + foreach ($aliases as $alias) { + $orX->add($expr->gte($alias . '.level', $this->createNamedParameter($level))); + } + + return $orX; + } + } diff --git a/lib/Model/Circle.php b/lib/Model/Circle.php index ff5e26395..644680ca8 100644 --- a/lib/Model/Circle.php +++ b/lib/Model/Circle.php @@ -189,6 +189,9 @@ class Circle extends ManagedModel implements IMemberships, IDeserializable, INC2 /** @var Member */ private $initiator; + /** @var Member */ + private $directInitiator; + /** @var array */ private $settings = []; @@ -516,6 +519,13 @@ public function setInitiator(?Member $initiator): self { * @return Member */ public function getInitiator(): Member { + if (is_null($this->initiator) + || ($this->initiator->getId() === '' + && !is_null($this->directInitiator) + && $this->directInitiator->getId() !== '')) { + return $this->directInitiator; + } + return $this->initiator; } @@ -523,9 +533,21 @@ public function getInitiator(): Member { * @return bool */ public function hasInitiator(): bool { - return ($this->initiator !== null); + return (!is_null($this->initiator) || !is_null($this->directInitiator)); } + /** + * @param Member|null $directInitiator + * + * @return $this + */ + public function setDirectInitiator(?Member $directInitiator): self { + $this->directInitiator = $directInitiator; + + return $this; + } + + /** * @param string $instance * diff --git a/lib/Model/ModelManager.php b/lib/Model/ModelManager.php index 71c929dec..8cff0f4f1 100644 --- a/lib/Model/ModelManager.php +++ b/lib/Model/ModelManager.php @@ -237,6 +237,15 @@ private function importIntoCircle(Circle $circle, array $data, string $path, str } catch (MemberNotFoundException $e) { } break; + + case CoreQueryBuilder::DIRECT_INITIATOR; + try { + $directInitiator = new Member(); + $directInitiator->importFromDatabase($data, $prefix); + $circle->setDirectInitiator($directInitiator); + } catch (MemberNotFoundException $e) { + } + break; } }