diff options
author | René Gieling <github@dartcafe.de> | 2022-10-24 16:27:30 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-24 16:27:30 +0300 |
commit | 58f455473591bff6a9ee6fc8c1e46ecf23106f05 (patch) | |
tree | 111d9c250981adfa5939c624a1dba11c4c6c12f9 | |
parent | 36101e5795bdef3a1eee3d00ccd6febea9a8704c (diff) |
Change handling of objects which refer to deleted shares (#2640)
* add fake share for delete users and hash user id
* fix #2636
-rw-r--r-- | lib/Db/Comment.php | 44 | ||||
-rw-r--r-- | lib/Db/EntityWithUser.php | 86 | ||||
-rw-r--r-- | lib/Db/IEntityWithUser.php | 46 | ||||
-rw-r--r-- | lib/Db/Option.php | 53 | ||||
-rw-r--r-- | lib/Db/Poll.php | 31 | ||||
-rw-r--r-- | lib/Db/Share.php | 8 | ||||
-rw-r--r-- | lib/Db/ShareMapper.php | 41 | ||||
-rw-r--r-- | lib/Db/Vote.php | 41 | ||||
-rw-r--r-- | lib/Exceptions/NotFoundException.php | 5 | ||||
-rw-r--r-- | lib/Exceptions/ShareNotFoundException.php | 32 | ||||
-rw-r--r-- | lib/Model/Acl.php | 3 | ||||
-rw-r--r-- | lib/Model/Mail/NotificationMail.php | 2 | ||||
-rw-r--r-- | lib/Provider/ActivityProvider.php | 8 | ||||
-rw-r--r-- | lib/Service/AnonymizeService.php | 19 | ||||
-rw-r--r-- | lib/Service/PollService.php | 6 | ||||
-rw-r--r-- | lib/Service/ShareService.php | 30 | ||||
-rw-r--r-- | lib/Service/UserService.php | 10 |
17 files changed, 256 insertions, 209 deletions
diff --git a/lib/Db/Comment.php b/lib/Db/Comment.php index 6e6e9ef7..07ee8a9c 100644 --- a/lib/Db/Comment.php +++ b/lib/Db/Comment.php @@ -27,12 +27,6 @@ namespace OCA\Polls\Db; use JsonSerializable; -use OCA\Polls\Helper\Container; -use OCP\IUser; -use OCP\IUserManager; -use OCP\AppFramework\Db\Entity; -use OCP\AppFramework\Db\DoesNotExistException; - /** * @method int getId() * @method void setId(integer $value) @@ -45,7 +39,7 @@ use OCP\AppFramework\Db\DoesNotExistException; * @method int getTimestamp() * @method void setTimestamp(integer $value) */ -class Comment extends Entity implements JsonSerializable { +class Comment extends EntityWithUser implements JsonSerializable { public const TABLE = 'polls_comments'; /** @var array $subComments */ @@ -63,17 +57,9 @@ class Comment extends Entity implements JsonSerializable { /** @var string $comment */ protected $comment = ''; - /** @var IUserManager */ - private $userManager; - - /** @var ShareMapper */ - private $shareMapper; - public function __construct() { $this->addType('pollId', 'int'); $this->addType('timestamp', 'int'); - $this->userManager = Container::queryClass(IUserManager::class); - $this->shareMapper = Container::queryClass(ShareMapper::class); } /** @@ -101,32 +87,4 @@ class Comment extends Entity implements JsonSerializable { public function getSubComments(): array { return $this->subComments; } - - public function getDisplayName(): string { - if (!strncmp($this->userId, 'deleted_', 8)) { - return 'Deleted User'; - } - - if ($this->getIsNoUser()) { - // get displayName from share - try { - $share = $this->shareMapper->findByPollAndUser($this->getPollId(), $this->userId); - return $share->getDisplayName(); - } catch (DoesNotExistException $e) { - return $this->userId; - } - } - return $this->userManager->get($this->userId)->getDisplayName(); - } - - public function getUser(): array { - return [ - 'userId' => $this->getUserId(), - 'displayName' => $this->getDisplayName(), - 'isNoUser' => $this->getIsNoUser(), - ]; - } - public function getIsNoUser(): bool { - return !($this->userManager->get($this->userId) instanceof IUser); - } } diff --git a/lib/Db/EntityWithUser.php b/lib/Db/EntityWithUser.php new file mode 100644 index 00000000..6168ae22 --- /dev/null +++ b/lib/Db/EntityWithUser.php @@ -0,0 +1,86 @@ +<?php +/** + * @copyright Copyright (c) 2017 Kai Schröer <git@schroeer.co> + * + * @author Kai Schröer <git@schroeer.co> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Polls\Db; + +use OCA\Polls\Exceptions\ShareNotFoundException; +use OCA\Polls\Helper\Container; +use OCP\AppFramework\Db\Entity; +use OCP\IUser; +use OCP\IUserManager; + +/** + * @method string getUserId() + * @method int getPollId() + */ + +abstract class EntityWithUser extends Entity { + /** @var string $publicUserId */ + protected $publicUserId = ''; + + public function getIsNoUser(): bool { + return !(Container::queryClass(IUserManager::class)->get($this->getUserId()) instanceof IUser); + } + + public function getDisplayName(): string { + if (!$this->getUserId()) { + return ''; + } + if ($this->getIsNoUser()) { + // get displayName from share + try { + $share = Container::queryClass(ShareMapper::class)->findByPollAndUser($this->getPollId(), $this->getUserId()); + } catch (ShareNotFoundException $e) { + // User seems to be probaly deleted, use fake share + $share = Container::queryClass(ShareMapper::class)->getReplacement($this->getPollId(), $this->getUserId()); + } + return $share->getDisplayName(); + } + + return Container::queryClass(IUserManager::class)->get($this->getUserId())->getDisplayName(); + } + + private function getPublicUserId(): string { + if (!$this->getUserId()) { + return ''; + } + + if ($this->publicUserId) { + return $this->publicUserId; + } + + return $this->getUserId(); + } + + public function generateHashedUserId(): void { + $this->publicUserId = hash('md5', $this->getUserId()); + } + + public function getUser(): array { + return [ + 'userId' => $this->getPublicUserId(), + 'displayName' => $this->getDisplayName(), + 'isNoUser' => $this->getIsNoUser(), + ]; + } +} diff --git a/lib/Db/IEntityWithUser.php b/lib/Db/IEntityWithUser.php new file mode 100644 index 00000000..5a2a7bd3 --- /dev/null +++ b/lib/Db/IEntityWithUser.php @@ -0,0 +1,46 @@ +<?php +/** + * @copyright Copyright (c) 2017 Kai Schröer <git@schroeer.co> + * + * @author Kai Schröer <git@schroeer.co> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Polls\Db; + +interface IEntityWithUser { + /** + * Is this object'suser or owner an internal user or external + */ + public function getUserId(): string; + + /** + * Returns the displayname of this object's user or owner + */ + public function getDisplayName(): string; + + /** + * Creates a hashed version of the userId + */ + public function generateHashedUserId(): void; + + /** + * Returns an array with user attributes for jsonSerialize() + */ + public function getUser(): array; +} diff --git a/lib/Db/Option.php b/lib/Db/Option.php index 965d5fc3..9aea04fd 100644 --- a/lib/Db/Option.php +++ b/lib/Db/Option.php @@ -30,12 +30,6 @@ use DateTime; use DateTimeImmutable; use DateTimeZone; use JsonSerializable; - -use OCA\Polls\Helper\Container; -use OCP\AppFramework\Db\Entity; -use OCP\IUser; -use OCP\IUserManager; -use OCP\AppFramework\Db\DoesNotExistException; use OCP\IL10N; /** @@ -58,7 +52,7 @@ use OCP\IL10N; * @method int getTimestamp() * @method void setTimestamp(integer $value) */ -class Option extends Entity implements JsonSerializable { +class Option extends EntityWithUser implements JsonSerializable { public const TABLE = 'polls_options'; /** @var int $pollId */ @@ -107,12 +101,6 @@ class Option extends Entity implements JsonSerializable { /** @var bool $isBookedUp */ public $isBookedUp = false; - /** @var IUserManager */ - private $userManager; - - /** @var ShareMapper */ - private $shareMapper; - public function __construct() { $this->addType('released', 'int'); $this->addType('pollId', 'int'); @@ -120,8 +108,6 @@ class Option extends Entity implements JsonSerializable { $this->addType('order', 'int'); $this->addType('confirmed', 'int'); $this->addType('duration', 'int'); - $this->userManager = Container::queryClass(IUserManager::class); - $this->shareMapper = Container::queryClass(ShareMapper::class); } /** @@ -145,15 +131,10 @@ class Option extends Entity implements JsonSerializable { 'votes' => $this->votes, 'isBookedUp' => $this->isBookedUp, ], - 'owner' => [ - 'userId' => $this->getOwner(), - 'displayName' => $this->getDisplayName(), - 'isNoUser' => $this->getOwnerIsNoUser(), - ], + 'owner' => $this->getUser(), ]; } - public function getPollOptionText(): string { if ($this->getTimestamp() && $this->getDuration()) { return date('c', $this->getTimestamp()) . ' - ' . date('c', $this->getTimestamp() + $this->getDuration()); @@ -194,30 +175,6 @@ class Option extends Entity implements JsonSerializable { $this->setOwner($userId); } - // used for 1.9.0-beta1 installations - public function getOwner() : string { - if ($this->owner === 'disallow' || $this->owner === null) { - return ''; - } - return $this->owner; - } - - public function getDisplayName(): ?string { - if (!strncmp($this->getOwner(), 'deleted_', 8)) { - return 'Deleted User'; - } - - if ($this->getOwnerIsNoUser()) { - try { - $share = $this->shareMapper->findByPollAndUser($this->getPollId(), $this->getOwner()); - return $share->getDisplayName(); - } catch (DoesNotExistException $e) { - return $this->getOwner(); - } - } - return $this->userManager->get($this->getOwner())->getDisplayName(); - } - public function getDateStringLocalized(DateTimeZone $timeZone, IL10N $l10n) { $mutableFrom = DateTime::createFromImmutable($this->getDateObjectFrom($timeZone)); $mutableTo = DateTime::createFromImmutable($this->getDateObjectTo($timeZone)); @@ -251,9 +208,9 @@ class Option extends Entity implements JsonSerializable { return $dateTimeFrom . ' - ' . $dateTimeTo; } - private function getOwnerIsNoUser(): bool { - return !$this->userManager->get($this->getOwner()) instanceof IUser; - } + // private function getOwnerIsNoUser(): bool { + // return !$this->userManager->get($this->getOwner()) instanceof IUser; + // } /** * Check, if the date option spans one or more whole days (from 00:00 to 24:00) diff --git a/lib/Db/Poll.php b/lib/Db/Poll.php index b22c710a..2b60161c 100644 --- a/lib/Db/Poll.php +++ b/lib/Db/Poll.php @@ -28,9 +28,6 @@ namespace OCA\Polls\Db; use JsonSerializable; use OCA\Polls\Exceptions\NoDeadLineException; use OCA\Polls\Helper\Container; -use OCP\AppFramework\Db\Entity; -use OCP\IUser; -use OCP\IUserManager; use OCP\IURLGenerator; /** @@ -78,7 +75,7 @@ use OCP\IURLGenerator; * @method void setMiscSettings(string $value) */ -class Poll extends Entity implements JsonSerializable { +class Poll extends EntityWithUser implements JsonSerializable { public const TABLE = 'polls_polls'; public const TYPE_DATE = 'datePoll'; public const TYPE_TEXT = 'textPoll'; @@ -165,9 +162,6 @@ class Poll extends Entity implements JsonSerializable { /** @var IURLGenerator */ private $urlGenerator; - /** @var IUserManager */ - private $userManager; - /** @var OptionMapper */ private $optionMapper; @@ -185,9 +179,8 @@ class Poll extends Entity implements JsonSerializable { $this->addType('important', 'int'); $this->addType('hideBookedUp', 'int'); $this->addType('useNo', 'int'); - $this->urlGenerator = Container::queryClass(IURLGenerator::class); - $this->userManager = Container::queryClass(IUserManager::class); $this->optionMapper = Container::queryClass(OptionMapper::class); + $this->urlGenerator = Container::queryClass(IURLGenerator::class); } /** @@ -217,10 +210,7 @@ class Poll extends Entity implements JsonSerializable { 'hideBookedUp' => $this->getHideBookedUp(), 'useNo' => $this->getUseNo(), 'autoReminder' => $this->getAutoReminder(), - 'owner' => [ - 'userId' => $this->getOwner(), - 'displayName' => $this->getDisplayName(), - ], + 'owner' => $this->getUser(), ]; } @@ -322,18 +312,16 @@ class Poll extends Entity implements JsonSerializable { return htmlspecialchars($this->description); } - public function getDisplayName(): string { - return $this->userManager->get($this->owner) instanceof IUser - ? $this->userManager->get($this->owner)->getDisplayName() - : $this->owner; - } - private function setMiscSettingsArray(array $value) : void { $this->setMiscSettings(json_encode($value)); } - private function getMiscSettingsArray() : ?array { - return json_decode($this->getMiscSettings(), true); + private function getMiscSettingsArray() : array { + if ($this->getMiscSettings()) { + return json_decode($this->getMiscSettings(), true); + } + + return []; } public function getTimeToDeadline(int $time = 0): ?int { @@ -372,7 +360,6 @@ class Poll extends Entity implements JsonSerializable { throw new NoDeadLineException(); } - /** * @param bool|string|int|array $value */ diff --git a/lib/Db/Share.php b/lib/Db/Share.php index 153857eb..864cafef 100644 --- a/lib/Db/Share.php +++ b/lib/Db/Share.php @@ -221,8 +221,12 @@ class Share extends Entity implements JsonSerializable { $this->setMiscSettings(json_encode($value)); } - private function getMiscSettingsArray() : ?array { - return json_decode($this->getMiscSettings(), true); + private function getMiscSettingsArray() : array { + if ($this->getMiscSettings()) { + return json_decode($this->getMiscSettings(), true); + } + + return []; } /** diff --git a/lib/Db/ShareMapper.php b/lib/Db/ShareMapper.php index 49228c42..d2716921 100644 --- a/lib/Db/ShareMapper.php +++ b/lib/Db/ShareMapper.php @@ -24,6 +24,9 @@ namespace OCA\Polls\Db; +use OCA\Polls\Exceptions\ShareNotFoundException; +use OCA\Polls\Model\UserBase; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\QBMapper; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -102,22 +105,44 @@ class ShareMapper extends QBMapper { $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) ); - return $this->findEntity($qb); + try { + return $this->findEntity($qb); + } catch (DoesNotExistException $e) { + throw new ShareNotFoundException("Share not found by userId and pollId"); + } } /** - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found + * Returns a fake share in case of deleted shares */ + public function getReplacement($pollId, $userId): ?Share { + if (!$userId) { + return null; + } + + $share = new Share; + $share->setUserId($userId); + $share->setPollId($pollId); + $share->setType(UserBase::TYPE_EXTERNAL); + $share->setToken('deleted_share_' . $userId . '_' . $pollId); + $share->setDisplayName('Deleted User'); + return $share; + } + public function findByToken(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); + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('token', $qb->createNamedParameter($token, IQueryBuilder::PARAM_STR)) + ); + + try { + return $this->findEntity($qb); + } catch (DoesNotExistException $e) { + throw new ShareNotFoundException('Token ' . $token . ' does not exist'); + } } public function deleteByPoll(int $pollId): void { diff --git a/lib/Db/Vote.php b/lib/Db/Vote.php index 1c00c21e..243d9e6b 100644 --- a/lib/Db/Vote.php +++ b/lib/Db/Vote.php @@ -26,11 +26,6 @@ namespace OCA\Polls\Db; use JsonSerializable; -use OCA\Polls\Helper\Container; -use OCP\IUser; -use OCP\IUserManager; -use OCP\AppFramework\Db\Entity; -use OCP\AppFramework\Db\DoesNotExistException; /** * @method int getPollId() @@ -44,7 +39,7 @@ use OCP\AppFramework\Db\DoesNotExistException; * @method string getVoteAnswer() * @method void setVoteAnswer(string $value) */ -class Vote extends Entity implements JsonSerializable { +class Vote extends EntityWithUser implements JsonSerializable { public const TABLE = 'polls_votes'; /** @var int $pollId */ @@ -62,18 +57,10 @@ class Vote extends Entity implements JsonSerializable { /** @var string $voteAnswer */ protected $voteAnswer; - /** @var IUserManager */ - private $userManager; - - /** @var ShareMapper */ - private $shareMapper; - public function __construct() { $this->addType('id', 'int'); $this->addType('pollId', 'int'); $this->addType('voteOptionId', 'int'); - $this->userManager = Container::queryClass(IUserManager::class); - $this->shareMapper = Container::queryClass(ShareMapper::class); } /** @@ -85,31 +72,7 @@ class Vote extends Entity implements JsonSerializable { 'pollId' => $this->getPollId(), 'optionText' => $this->getVoteOptionText(), 'answer' => $this->getVoteAnswer(), - 'user' => [ - 'userId' => $this->getUserId(), - 'displayName' => $this->getDisplayName(), - 'isNoUser' => $this->getIsNoUser(), - ], + 'user' => $this->getUser(), ]; } - - public function getDisplayName(): string { - if (!strncmp($this->userId, 'deleted_', 8)) { - return 'Deleted User'; - } - - if ($this->getIsNoUser()) { - try { - $share = $this->shareMapper->findByPollAndUser($this->getPollId(), $this->userId); - return $share->getDisplayName(); - } catch (DoesNotExistException $e) { - return $this->userId; - } - } - return $this->userManager->get($this->userId)->getDisplayName(); - } - - public function getIsNoUser(): bool { - return !($this->userManager->get($this->userId) instanceof IUser); - } } diff --git a/lib/Exceptions/NotFoundException.php b/lib/Exceptions/NotFoundException.php index bb678965..dbd70466 100644 --- a/lib/Exceptions/NotFoundException.php +++ b/lib/Exceptions/NotFoundException.php @@ -27,9 +27,8 @@ use OCP\AppFramework\Http; class NotFoundException extends Exception { public function __construct( - string $e = 'Not found', - int $status = Http::STATUS_NOT_FOUND + string $e = 'Not found' ) { - parent::__construct($e, $status); + parent::__construct($e, Http::STATUS_NOT_FOUND); } } diff --git a/lib/Exceptions/ShareNotFoundException.php b/lib/Exceptions/ShareNotFoundException.php new file mode 100644 index 00000000..60d88d89 --- /dev/null +++ b/lib/Exceptions/ShareNotFoundException.php @@ -0,0 +1,32 @@ +<?php +/** + * @copyright Copyright (c) 2020 René Gieling <github@dartcafe.de> + * + * @author René Gieling <github@dartcafe.de> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Polls\Exceptions; + +class ShareNotFoundException extends NotFoundException { + public function __construct( + string $e = 'Share not found' + ) { + parent::__construct($e); + } +} diff --git a/lib/Model/Acl.php b/lib/Model/Acl.php index bf492402..8c47be4c 100644 --- a/lib/Model/Acl.php +++ b/lib/Model/Acl.php @@ -33,6 +33,7 @@ use OCA\Polls\Db\OptionMapper; use OCA\Polls\Db\PollMapper; use OCA\Polls\Db\VoteMapper; use OCA\Polls\Db\ShareMapper; +use OCA\Polls\Exceptions\ShareNotFoundException; use OCP\IUserManager; use OCP\IUserSession; use OCP\IGroupManager; @@ -130,7 +131,7 @@ class Acl implements JsonSerializable { $this->poll = $this->pollMapper->find($this->share->getPollId()); $this->validateShareAccess(); $this->request($permission); - } catch (DoesNotExistException $e) { + } catch (ShareNotFoundException $e) { throw new NotAuthorizedException('Error loading share ' . $token); } diff --git a/lib/Model/Mail/NotificationMail.php b/lib/Model/Mail/NotificationMail.php index 6b0ff2e2..d3b6ced3 100644 --- a/lib/Model/Mail/NotificationMail.php +++ b/lib/Model/Mail/NotificationMail.php @@ -108,6 +108,6 @@ class NotificationMail extends MailBase { VoteEvent::SET => $this->l10n->t('%s has voted.', [$displayName]), ]; - return $logStrings[$logItem->getMessageId()] ?? $logItem->getMessageId() . " (" . $displayName . ")"; + return $logStrings[$logItem->getMessageId()] ?? $logItem->getMessageId() . ' (' . $displayName . ')'; } } diff --git a/lib/Provider/ActivityProvider.php b/lib/Provider/ActivityProvider.php index 5992b909..7c2ba47d 100644 --- a/lib/Provider/ActivityProvider.php +++ b/lib/Provider/ActivityProvider.php @@ -34,6 +34,7 @@ use OCP\Activity\IEventMerger; use OCP\Activity\IEvent; use OCA\Polls\Service\ActivityService; use OCA\Polls\Db\ShareMapper; +use OCA\Polls\Exceptions\ShareNotFoundException; class ActivityProvider implements IProvider { /** @var IFactory */ @@ -110,7 +111,12 @@ class ActivityProvider implements IProvider { 'name' => $actor->getDisplayName(), ]; } else { - $share = $this->shareMapper->findByPollAndUser($event->getObjectId(), $event->getAuthor()); + try { + $share = $this->shareMapper->findByPollAndUser($event->getObjectId(), $event->getAuthor()); + } catch (ShareNotFoundException $e) { + // User seems to be probaly deleted, use fake share + $share = $this->shareMapper->getReplacement($event->getObjectId(), $event->getAuthor()); + } $parameters['actor'] = [ 'type' => 'guest', 'id' => $share->getUserId(), diff --git a/lib/Service/AnonymizeService.php b/lib/Service/AnonymizeService.php index c8321e19..af9f685e 100644 --- a/lib/Service/AnonymizeService.php +++ b/lib/Service/AnonymizeService.php @@ -28,7 +28,6 @@ use OCA\Polls\Db\Vote; use OCA\Polls\Db\VoteMapper; use OCA\Polls\Db\Comment; use OCA\Polls\Db\CommentMapper; -use OCA\Polls\Db\Option; use OCA\Polls\Db\OptionMapper; use OCA\Polls\Db\Poll; @@ -112,21 +111,13 @@ class AnonymizeService { return; } - /** - * Replaces userIds with displayName to avoid exposing usernames in public polls - */ public static function replaceUserId(&$arrayOrObject, string $userId) : void { if (is_array($arrayOrObject)) { foreach ($arrayOrObject as $item) { if ($item->getUserId() === $userId) { continue; } - if ($item instanceof Comment || $item instanceof Vote) { - $item->setUserId($item->getDisplayName()); - } - if ($item instanceof Option || $item instanceof Poll) { - $item->setOwner($item->getDisplayName()); - } + $item->generateHashedUserId(); } return; } @@ -135,13 +126,7 @@ class AnonymizeService { return; } - if ($arrayOrObject instanceof Option || $arrayOrObject instanceof Poll) { - $arrayOrObject->setOwner($arrayOrObject->getDisplayName()); - } - - if ($arrayOrObject instanceof Comment || $arrayOrObject instanceof Vote) { - $arrayOrObject->setUserId($arrayOrObject->getDisplayName()); - } + $arrayOrObject->generateHashedUserId(); return; } diff --git a/lib/Service/PollService.php b/lib/Service/PollService.php index c5b8a636..f9df6dbe 100644 --- a/lib/Service/PollService.php +++ b/lib/Service/PollService.php @@ -208,8 +208,12 @@ class PollService { /** * get poll configuration + * + * @return (\OCA\Polls\Db\Comment|\OCA\Polls\Db\Option|\OCA\Polls\Db\Vote)[]|Poll + * + * @psalm-return Poll|array<\OCA\Polls\Db\Comment|\OCA\Polls\Db\Option|\OCA\Polls\Db\Vote> */ - public function get(int $pollId) : Poll { + public function get(int $pollId) { $this->acl->setPollId($pollId); $this->poll = $this->pollMapper->find($pollId); diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index 9b23def4..ad6c452f 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -37,6 +37,7 @@ use OCA\Polls\Exceptions\InvalidShareTypeException; use OCA\Polls\Exceptions\ShareAlreadyExistsException; use OCA\Polls\Exceptions\NotFoundException; use OCA\Polls\Exceptions\InvalidUsernameException; +use OCA\Polls\Exceptions\ShareNotFoundException; use OCA\Polls\Model\Acl; use OCA\Polls\Model\UserBase; use OCP\AppFramework\Db\DoesNotExistException; @@ -144,13 +145,9 @@ class ShareService { * Get share by token for accessing the poll */ public function get(string $token, bool $validateShareType = false): Share { - try { - $this->share = $this->shareMapper->findByToken($token); - if ($validateShareType) { - $this->validateShareType(); - } - } catch (DoesNotExistException $e) { - throw new NotFoundException('Token ' . $token . ' does not exist'); + $this->share = $this->shareMapper->findByToken($token); + if ($validateShareType) { + $this->validateShareType(); } // Exception: logged in user accesses the poll via public share link @@ -184,15 +181,10 @@ class ShareService { * Change share type */ public function setType(string $token, string $type): Share { - try { - $this->share = $this->shareMapper->findByToken($token); - $this->acl->setPollId($this->share->getPollId(), Acl::PERMISSION_POLL_EDIT); - $this->share->setType($type); - $this->share = $this->shareMapper->update($this->share); - } catch (DoesNotExistException $e) { - throw new NotFoundException('Token ' . $token . ' does not exist'); - } - + $this->share = $this->shareMapper->findByToken($token); + $this->acl->setPollId($this->share->getPollId(), Acl::PERMISSION_POLL_EDIT); + $this->share->setType($type); + $this->share = $this->shareMapper->update($this->share); $this->eventDispatcher->dispatchTyped(new ShareTypeChangedEvent($this->share)); return $this->share; @@ -207,7 +199,7 @@ class ShareService { $this->acl->setPollId($this->share->getPollId(), Acl::PERMISSION_POLL_EDIT); $this->share->setPublicPollEmail($value); $this->share = $this->shareMapper->update($this->share); - } catch (DoesNotExistException $e) { + } catch (ShareNotFoundException $e) { throw new NotFoundException('Token ' . $token . ' does not exist'); } $this->eventDispatcher->dispatchTyped(new ShareChangedRegistrationConstraintEvent($this->share)); @@ -338,7 +330,7 @@ class ShareService { $this->share = $this->shareMapper->findByToken($token); $this->acl->setPollId($this->share->getPollId(), Acl::PERMISSION_POLL_EDIT); $this->shareMapper->delete($this->share); - } catch (DoesNotExistException $e) { + } catch (ShareNotFoundException $e) { // silently catch } @@ -431,7 +423,7 @@ class ShareService { throw new ShareAlreadyExistsException; } catch (MultipleObjectsReturnedException $e) { throw new ShareAlreadyExistsException; - } catch (DoesNotExistException $e) { + } catch (ShareNotFoundException $e) { // continue } } diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php index 2d41ccf7..39c865fe 100644 --- a/lib/Service/UserService.php +++ b/lib/Service/UserService.php @@ -26,8 +26,8 @@ namespace OCA\Polls\Service; use OCA\Polls\Db\Share; use OCA\Polls\Db\ShareMapper; use OCA\Polls\Db\VoteMapper; -use OCA\Polls\Exceptions\Exception; use OCA\Polls\Exceptions\InvalidShareTypeException; +use OCA\Polls\Exceptions\ShareNotFoundException; use OCA\Polls\Model\User\Admin; use OCA\Polls\Model\Group\Circle; use OCA\Polls\Model\Group\ContactGroup; @@ -127,10 +127,12 @@ class UserService { // Otherwise get it from a share that belongs to the poll and return the share user try { $share = $this->shareMapper->findByPollAndUser($pollId, $userId); - return $this->getUserFromShare($share); - } catch (Exception $e) { - return null; + } catch (ShareNotFoundException $e) { + // User seems to be probaly deleted, use fake share + $share = $this->shareMapper->getReplacement($pollId, $userId); } + + return $this->getUserFromShare($share); } /** |