1<?php 2 3declare(strict_types=1); 4/** 5 * @author Joachim Bauch <mail@joachim-bauch.de> 6 * 7 * @license GNU AGPL version 3 or any later version 8 * 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU Affero General Public License as 11 * published by the Free Software Foundation, either version 3 of the 12 * License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Affero General Public License for more details. 18 * 19 * You should have received a copy of the GNU Affero General Public License 20 * along with this program. If not, see <http://www.gnu.org/licenses/>. 21 * 22 */ 23 24namespace OCA\Talk\Collaboration\Collaborators; 25 26use OCA\Talk\Config; 27use OCA\Talk\Exceptions\ParticipantNotFoundException; 28use OCA\Talk\Exceptions\RoomNotFoundException; 29use OCA\Talk\Manager; 30use OCA\Talk\MatterbridgeManager; 31use OCA\Talk\Model\Attendee; 32use OCA\Talk\Participant; 33use OCA\Talk\Room; 34use OCP\Collaboration\AutoComplete\AutoCompleteEvent; 35use OCP\Collaboration\AutoComplete\IManager; 36use OCP\EventDispatcher\IEventDispatcher; 37use OCP\IUser; 38use OCP\IUserManager; 39 40class Listener { 41 42 /** @var Manager */ 43 protected $manager; 44 /** @var IUserManager */ 45 protected $userManager; 46 /** @var Config */ 47 protected $config; 48 /** @var string[] */ 49 protected $allowedGroupIds = []; 50 /** @var string */ 51 protected $roomToken; 52 /** @var Room */ 53 protected $room; 54 55 public function __construct(Manager $manager, 56 IUserManager $userManager, 57 Config $config) { 58 $this->manager = $manager; 59 $this->userManager = $userManager; 60 $this->config = $config; 61 } 62 63 public static function register(IEventDispatcher $dispatcher): void { 64 $dispatcher->addListener(IManager::class . '::filterResults', static function (AutoCompleteEvent $event) { 65 /** @var self $listener */ 66 $listener = \OC::$server->get(self::class); 67 68 if ($event->getItemType() !== 'call') { 69 return; 70 } 71 72 $event->setResults($listener->filterUsersAndGroupsWithoutTalk($event->getResults())); 73 74 $event->setResults($listener->filterBridgeBot($event->getResults())); 75 if ($event->getItemId() !== 'new') { 76 $event->setResults($listener->filterExistingParticipants($event->getItemId(), $event->getResults())); 77 } 78 }); 79 } 80 81 protected function filterUsersAndGroupsWithoutTalk(array $results): array { 82 $this->allowedGroupIds = $this->config->getAllowedTalkGroupIds(); 83 if (empty($this->allowedGroupIds)) { 84 return $results; 85 } 86 87 if (!empty($results['groups'])) { 88 $results['groups'] = array_filter($results['groups'], [$this, 'filterBlockedGroupResult']); 89 } 90 if (!empty($results['exact']['groups'])) { 91 $results['exact']['groups'] = array_filter($results['exact']['groups'], [$this, 'filterBlockedGroupResult']); 92 } 93 94 if (!empty($results['users'])) { 95 $results['users'] = array_filter($results['users'], [$this, 'filterBlockedUserResult']); 96 } 97 if (!empty($results['exact']['users'])) { 98 $results['exact']['users'] = array_filter($results['exact']['users'], [$this, 'filterBlockedUserResult']); 99 } 100 101 return $results; 102 } 103 104 protected function filterBlockedUserResult(array $result): bool { 105 $user = $this->userManager->get($result['value']['shareWith']); 106 return $user instanceof IUser && !$this->config->isDisabledForUser($user); 107 } 108 109 protected function filterBlockedGroupResult(array $result): bool { 110 return \in_array($result['value']['shareWith'], $this->allowedGroupIds, true); 111 } 112 113 protected function filterBridgeBot(array $results): array { 114 if (!empty($results['users'])) { 115 $results['users'] = array_filter($results['users'], [$this, 'filterBridgeBotUserResult']); 116 } 117 if (!empty($results['exact']['users'])) { 118 $results['exact']['users'] = array_filter($results['exact']['users'], [$this, 'filterBridgeBotUserResult']); 119 } 120 121 return $results; 122 } 123 124 protected function filterExistingParticipants(string $token, array $results): array { 125 try { 126 $this->room = $this->manager->getRoomByToken($token); 127 } catch (RoomNotFoundException $e) { 128 return $results; 129 } 130 131 if (!empty($results['groups'])) { 132 $results['groups'] = array_filter($results['groups'], [$this, 'filterParticipantGroupResult']); 133 } 134 if (!empty($results['exact']['groups'])) { 135 $results['exact']['groups'] = array_filter($results['exact']['groups'], [$this, 'filterParticipantGroupResult']); 136 } 137 138 if (!empty($results['users'])) { 139 $results['users'] = array_filter($results['users'], [$this, 'filterParticipantUserResult']); 140 } 141 if (!empty($results['exact']['users'])) { 142 $results['exact']['users'] = array_filter($results['exact']['users'], [$this, 'filterParticipantUserResult']); 143 } 144 145 return $results; 146 } 147 148 protected function filterBridgeBotUserResult(array $result): bool { 149 return $result['value']['shareWith'] !== MatterbridgeManager::BRIDGE_BOT_USERID; 150 } 151 152 protected function filterParticipantUserResult(array $result): bool { 153 $userId = $result['value']['shareWith']; 154 155 try { 156 $participant = $this->room->getParticipant($userId, false); 157 if ($participant->getAttendee()->getParticipantType() === Participant::USER_SELF_JOINED) { 158 // do list self-joined users so they can be added as permanent participants by moderators 159 return true; 160 } 161 return false; 162 } catch (ParticipantNotFoundException $e) { 163 return true; 164 } 165 } 166 167 protected function filterParticipantGroupResult(array $result): bool { 168 $groupId = $result['value']['shareWith']; 169 170 try { 171 $this->room->getParticipantByActor(Attendee::ACTOR_GROUPS, $groupId); 172 return false; 173 } catch (ParticipantNotFoundException $e) { 174 return true; 175 } 176 } 177} 178