diff options
author | Joas Schilling <coding@schilljs.com> | 2018-04-25 14:01:29 +0300 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2018-04-26 16:23:38 +0300 |
commit | c761676e96974d3f9b3268294e1bf55f685fc216 (patch) | |
tree | d1dfaf1ba062174528139ec70839f5a9127c4af7 | |
parent | c4bd6092eabe40ec74f6d67bc44d3f5345f8e66b (diff) |
Start autocomplete for mentions
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r-- | appinfo/routes.php | 9 | ||||
-rw-r--r-- | lib/Chat/AutoComplete/SearchPlugin.php | 127 | ||||
-rw-r--r-- | lib/Chat/AutoComplete/Sorter.php | 47 | ||||
-rw-r--r-- | lib/Controller/ChatController.php | 75 |
4 files changed, 257 insertions, 1 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php index f93bbb1a2..86ca86b23 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -129,6 +129,15 @@ return [ 'token' => '^[a-z0-9]{4,30}$', ], ], + [ + 'name' => 'Chat#autoComplete', + 'url' => '/api/{apiVersion}/chat/{token}/autocomplete', + 'verb' => 'GET', + 'requirements' => [ + 'apiVersion' => 'v1', + 'token' => '^[a-z0-9]{4,30}$', + ], + ], /** * Room diff --git a/lib/Chat/AutoComplete/SearchPlugin.php b/lib/Chat/AutoComplete/SearchPlugin.php new file mode 100644 index 000000000..a6e99cf66 --- /dev/null +++ b/lib/Chat/AutoComplete/SearchPlugin.php @@ -0,0 +1,127 @@ +<?php +/** + * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com> + * + * @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\Spreed\Chat\AutoComplete; + + +use OCA\Spreed\Room; +use OCP\Collaboration\Collaborators\ISearchPlugin; +use OCP\Collaboration\Collaborators\ISearchResult; +use OCP\Collaboration\Collaborators\SearchResultType; +use OCP\IUser; +use OCP\IUserManager; + +class SearchPlugin implements ISearchPlugin { + + /** @var IUserManager */ + protected $userManager; + + public function __construct(IUserManager $userManager) { + $this->userManager = $userManager; + } + + /** @var Room */ + protected $room; + + public function setContext(array $context) { + $this->room = $context['room']; + } + + /** + * @param string $search + * @param int $limit + * @param int $offset + * @param ISearchResult $searchResult + * @return bool whether the plugin has more results + * @since 13.0.0 + */ + public function search($search, $limit, $offset, ISearchResult $searchResult) { + + $participants = $this->room->getParticipants(); + + $this->searchUsers($search, array_map('strval', array_keys($participants['users'])), $searchResult); + + // FIXME Handle guests + + return false; + } + + protected function searchUsers($search, array $userIds, ISearchResult $searchResult) { + $matches = $exactMatches = []; + foreach ($userIds as $userId) { + if ($search === '') { + $matches[] = $this->createResult('user', $userId, ''); + continue; + } + + if ($userId === $search) { + $exactMatches[] = $this->createResult('user', $userId, ''); + continue; + } + + if (strpos($userId, $search) !== false) { + $matches[] = $this->createResult('user', $userId, ''); + continue; + } + + $user = $this->userManager->get($userId); + if (!$user instanceof IUser) { + continue; + } + + if ($user->getDisplayName() === $search) { + $exactMatches[] = $this->createResult('user', $user->getUID(), $user->getDisplayName()); + continue; + } + + if (strpos($user->getDisplayName(), $search) !== false) { + $matches[] = $this->createResult('user', $user->getUID(), $user->getDisplayName()); + continue; + } + } + + $type = new SearchResultType('users'); + $searchResult->addResultSet($type, $matches, $exactMatches); + } + + /** + * @param string $type + * @param string $uid + * @param string $name + * @return array + */ + public function createResult($type, $uid, $name) { + if ($type === 'user' && $name === '') { + $user = $this->userManager->get($uid); + if ($user instanceof IUser) { + $name = $user->getDisplayName(); + } + } + + return [ + 'label' => $name, + 'value' => [ + 'shareType' => $type, + 'shareWith' => $uid, + ], + ]; + } +} diff --git a/lib/Chat/AutoComplete/Sorter.php b/lib/Chat/AutoComplete/Sorter.php new file mode 100644 index 000000000..7514f4db4 --- /dev/null +++ b/lib/Chat/AutoComplete/Sorter.php @@ -0,0 +1,47 @@ +<?php +/** + * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com> + * + * @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\Spreed\Chat\AutoComplete; + + +use OCP\Collaboration\AutoComplete\ISorter; + +class Sorter implements ISorter { + + /** + * @return string The ID of the sorter, e.g. commenters + * @since 13.0.0 + */ + public function getId() { + return 'talk_chat_participants'; + } + + /** + * executes the sort action + * + * @param array $sortArray the array to be sorted, provided as reference + * @param array $context carries key 'itemType' and 'itemId' of the source object (e.g. a file) + * @since 13.0.0 + */ + public function sort(array &$sortArray, array $context) { + // TODO: Implement sort() method. + } +} diff --git a/lib/Controller/ChatController.php b/lib/Controller/ChatController.php index 81a24116d..48f10299b 100644 --- a/lib/Controller/ChatController.php +++ b/lib/Controller/ChatController.php @@ -23,6 +23,8 @@ namespace OCA\Spreed\Controller; +use OC\Collaboration\Collaborators\SearchResult; +use OCA\Spreed\Chat\AutoComplete\SearchPlugin; use OCA\Spreed\Chat\ChatManager; use OCA\Spreed\Chat\RichMessageHelper; use OCA\Spreed\Exceptions\ParticipantNotFoundException; @@ -34,6 +36,8 @@ use OCA\Spreed\TalkSession; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCSController; +use OCP\Collaboration\AutoComplete\IManager; +use OCP\Collaboration\Collaborators\ISearchResult; use OCP\Comments\IComment; use OCP\IRequest; use OCP\IUser; @@ -68,6 +72,15 @@ class ChatController extends OCSController { /** @var RichMessageHelper */ private $richMessageHelper; + /** @var IManager */ + private $autoCompleteManager; + + /** @var SearchPlugin */ + private $searchPlugin; + + /** @var ISearchResult */ + private $searchResult; + /** * @param string $appName * @param string $UserId @@ -77,6 +90,10 @@ class ChatController extends OCSController { * @param Manager $manager * @param ChatManager $chatManager * @param GuestManager $guestManager + * @param RichMessageHelper $richMessageHelper + * @param IManager $autoCompleteManager + * @param SearchPlugin $searchPlugin + * @param SearchResult $searchResult */ public function __construct($appName, $UserId, @@ -86,7 +103,10 @@ class ChatController extends OCSController { Manager $manager, ChatManager $chatManager, GuestManager $guestManager, - RichMessageHelper $richMessageHelper) { + RichMessageHelper $richMessageHelper, + IManager $autoCompleteManager, + SearchPlugin $searchPlugin, + SearchResult $searchResult) { parent::__construct($appName, $request); $this->userId = $UserId; @@ -96,6 +116,9 @@ class ChatController extends OCSController { $this->chatManager = $chatManager; $this->guestManager = $guestManager; $this->richMessageHelper = $richMessageHelper; + $this->autoCompleteManager = $autoCompleteManager; + $this->searchPlugin = $searchPlugin; + $this->searchResult = $searchResult; } /** @@ -274,4 +297,54 @@ class ChatController extends OCSController { return $response; } + + /** + * @PublicPage + * + * @param string $token the room token + * @param string $search + * @param int $limit + * @return DataResponse + */ + public function autoComplete($token, $search, $limit = 20) { + $room = $this->getRoom($token); + if ($room === null) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + $this->searchPlugin->setContext([ + 'itemType' => 'chat', + 'itemId' => $room->getId(), + 'room' => $room, + ]); + $this->searchPlugin->search((string) $search, $limit, 0, $this->searchResult); + + $results = $this->searchResult->asArray(); + $exactMatches = $results['exact']; + unset($results['exact']); + $results = array_merge_recursive($exactMatches, $results); + + $this->autoCompleteManager->runSorters(['talk_chat_participants'], $results, [ + 'itemType' => 'chat', + 'itemId' => $room->getId(), + ]); + + $results = $this->prepareResultArray($results); + return new DataResponse($results); + } + + + protected function prepareResultArray(array $results) { + $output = []; + foreach ($results as $type => $subResult) { + foreach ($subResult as $result) { + $output[] = [ + 'id' => $result['value']['shareWith'], + 'label' => $result['label'], + 'source' => $type, + ]; + } + } + return $output; + } } |