diff --git a/lib/Db/UserMapper.php b/lib/Db/UserMapper.php index 628aedd23..6a2e03ec9 100644 --- a/lib/Db/UserMapper.php +++ b/lib/Db/UserMapper.php @@ -127,13 +127,16 @@ public function getParticipant(string $userId, ?int $pollId = null): UserBase { // just catch and continue if not found and try to find user by share; } - try { - $share = $this->getShareByPollAndUser($userId, $pollId); - return $this->getUserFromShare($share); - } catch (ShareNotFoundException $e) { - // User seems to be probaly deleted, use fake share - return new Ghost($userId); + if ($pollId !== null) { + try { + $share = $this->getShareByPollAndUser($userId, $pollId); + return $this->getUserFromShare($share); + } catch (ShareNotFoundException $e) { + // User seems to be probably deleted, use fake share + return new Ghost($userId); + } } + return new Ghost($userId); } /** @@ -175,7 +178,7 @@ public function getUserFromUserBase(string $userId, ?int $pollId = null): User { if ($user instanceof IUser) { try { // check if we find a share, where the user got admin rights for the particular poll - if ($this->getShareByPollAndUser($userId, $pollId)->getType() === Share::TYPE_ADMIN) { + if (($pollId !== null) && $this->getShareByPollAndUser($userId, $pollId)->getType() === Share::TYPE_ADMIN) { return new Admin($userId); } } catch (Exception $e) { @@ -215,15 +218,15 @@ public function getUserObject(string $type, string $id, string $displayName = '' private function getShareByToken(string $token): Share { $qb = $this->db->getQueryBuilder(); - + $qb->select('*') ->from($this->getTableName()) ->where($qb->expr()->eq('token', $qb->createNamedParameter($token, IQueryBuilder::PARAM_STR))); - + return $this->findEntity($qb); } - private function getShareByPollAndUser(string $userId, ?int $pollId = null): Share { + private function getShareByPollAndUser(string $userId, int $pollId): Share { $qb = $this->db->getQueryBuilder(); $qb->select('*') diff --git a/lib/Model/Acl.php b/lib/Model/Acl.php index 00148e954..d317c0f30 100644 --- a/lib/Model/Acl.php +++ b/lib/Model/Acl.php @@ -70,6 +70,8 @@ class Acl implements JsonSerializable { public const PERMISSION_ALL_ACCESS = 'allAccess'; private ?int $pollId = null; private ?UserBase $currentUser = null; + // Cache whether the current poll has shares + private bool $noShare = false; /** @@ -148,13 +150,26 @@ public function setPollId(?int $pollId = null, string $permission = self::PERMIS } else { $this->pollId = $pollId; } - + $this->loadPoll(); $this->request($permission); return $this; } + /** + * Set poll id and load poll + * @return $this + */ + public function setPoll(Poll $poll, string $permission = self::PERMISSION_POLL_VIEW): static { + $this->pollId = $poll->getId(); + $this->poll = $poll; + $this->noShare = false; + $this->request($permission); + + return $this; + } + public function getPoll(): ?Poll { if ($this->getToken()) { // first verify working share @@ -173,7 +188,7 @@ public function getShare(): ?Share { return $this->share; } - + /** * load poll * @throws NotFoundException Thrown if poll not found @@ -187,6 +202,7 @@ private function loadPoll(): void { try { // otherwise load poll from db $this->poll = $this->pollMapper->find((int) $this->pollId); + $this->noShare = false; } catch (DoesNotExistException $e) { throw new NotFoundException('Error loading poll with id ' . $this->pollId); } @@ -199,16 +215,26 @@ private function loadPoll(): void { * and the pollId will get set to the share's pollId */ private function loadShare(): void { + if ($this->noShare) { + throw new ShareNotFoundException('No token was set for ACL'); + } + // no token in session, try to find a user, who matches if (!$this->getToken()) { if ($this->getCurrentUser()->getIsLoggedIn()) { // search for logged in user's share, load it and return - $this->share = $this->shareMapper->findByPollAndUser($this->getPollId(), $this->getUserId()); + try { + $this->share = $this->shareMapper->findByPollAndUser($this->getPollId(), $this->getUserId()); + } catch (\Throwable $ex) { + $this->noShare = true; + throw $ex; + } // store share in session for further validations // $this->session->set(AppConstants::SESSION_KEY_SHARE_TOKEN, $this->share->getToken()); return; } else { $this->share = new Share(); + $this->noShare = true; // must fail, if no token is present and not logged in throw new ShareNotFoundException('No token was set for ACL'); } @@ -502,7 +528,7 @@ private function getAllowAddOptions(): bool { * @return bool|null */ private function getAllowDeleteOption(?string $optionOwner, ?int $pollId) { - + if (!$pollId) { $this->logger->warning('Poll id missing'); return false; @@ -519,7 +545,7 @@ private function getAllowDeleteOption(?string $optionOwner, ?int $pollId) { $this->logger->warning('Option owner missing'); return false; } - + if ($this->matchUser($optionOwner)) { return true; diff --git a/lib/Service/PollService.php b/lib/Service/PollService.php index c8027c804..22e6d5ffa 100644 --- a/lib/Service/PollService.php +++ b/lib/Service/PollService.php @@ -81,7 +81,7 @@ public function list(): array { $this->preferences = $this->preferencesService->get(); foreach ($polls as $poll) { try { - $this->acl->setPollId($poll->getId()); + $this->acl->setPoll($poll); $relevantThreshold = $poll->getRelevantThresholdNet() + $this->preferences->getRelevantOffsetTimestamp(); // mix poll settings, currentUser attributes, permissions and relevantThreshold into one array