summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2021-10-20 16:25:07 +0200
committerGitHub <noreply@github.com>2021-10-20 16:25:07 +0200
commit0e951eb9dca2f4fb5e0fc875d0daf92ae208c467 (patch)
tree79954c236ac22053ae7ca71824d08719a32dbaca
parentcf6bac8d6eac64d9db0b3f2650fb5f19f9db7442 (diff)
parent7f1dc52a66088a4478aa52708e62fbc2ffa7cb57 (diff)
downloadnextcloud-server-0e951eb9dca2f4fb5e0fc875d0daf92ae208c467.tar.gz
nextcloud-server-0e951eb9dca2f4fb5e0fc875d0daf92ae208c467.zip
Merge pull request #29269 from nextcloud/feature/28751/provide-contactsmenu-as-ocs-simple
Add an OCS endpoint for the hovercard contact actions
-rw-r--r--core/Controller/HoverCardController.php84
-rw-r--r--core/routes.php2
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/Contacts/ContactsMenu/ActionFactory.php17
-rw-r--r--lib/private/Contacts/ContactsMenu/Actions/LinkAction.php20
-rw-r--r--lib/private/Contacts/ContactsMenu/ContactsStore.php28
-rw-r--r--lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php2
-rw-r--r--lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php2
-rw-r--r--lib/public/Contacts/ContactsMenu/IAction.php12
-rw-r--r--lib/public/Contacts/ContactsMenu/IActionFactory.php6
-rw-r--r--tests/lib/Contacts/ContactsMenu/Actions/LinkActionTest.php19
-rw-r--r--tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php27
13 files changed, 178 insertions, 43 deletions
diff --git a/core/Controller/HoverCardController.php b/core/Controller/HoverCardController.php
new file mode 100644
index 00000000000..cb85da112a4
--- /dev/null
+++ b/core/Controller/HoverCardController.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2021 Joas Schilling <coding@schilljs.com>
+ *
+ * @author 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 OC\Core\Controller;
+
+use OC\Contacts\ContactsMenu\Manager;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\Contacts\ContactsMenu\IEntry;
+use OCP\IRequest;
+use OCP\IUserSession;
+use OCP\Share\IShare;
+
+class HoverCardController extends \OCP\AppFramework\OCSController {
+
+ /** @var Manager */
+ private $manager;
+
+ /** @var IUserSession */
+ private $userSession;
+
+ /**
+ * @param IRequest $request
+ * @param IUserSession $userSession
+ * @param Manager $manager
+ */
+ public function __construct(IRequest $request, IUserSession $userSession, Manager $manager) {
+ parent::__construct('core', $request);
+ $this->userSession = $userSession;
+ $this->manager = $manager;
+ }
+
+ /**
+ * @NoAdminRequired
+ *
+ * @param string $userId
+ * @return DataResponse
+ */
+ public function getUser(string $userId): DataResponse {
+ $contact = $this->manager->findOne($this->userSession->getUser(), IShare::TYPE_USER, $userId);
+
+ if (!$contact) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ $data = $this->entryToArray($contact);
+
+ $actions = $data['actions'];
+ if ($data['topAction']) {
+ array_unshift($actions, $data['topAction']);
+ }
+
+ return new DataResponse([
+ 'userId' => $userId,
+ 'displayName' => $contact->getFullName(),
+ 'actions' => $actions,
+ ]);
+ }
+
+ protected function entryToArray(IEntry $entry): array {
+ return json_decode(json_encode($entry), true);
+ }
+}
diff --git a/core/routes.php b/core/routes.php
index 59988404cd4..5750dac2ad1 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -110,6 +110,8 @@ $application->registerRoutes($this, [
['root' => '/core', 'name' => 'AppPassword#rotateAppPassword', 'url' => '/apppassword/rotate', 'verb' => 'POST'],
['root' => '/core', 'name' => 'AppPassword#deleteAppPassword', 'url' => '/apppassword', 'verb' => 'DELETE'],
+ ['root' => '/hovercard', 'name' => 'HoverCard#getUser', 'url' => '/v1/{userId}', 'verb' => 'GET'],
+
['root' => '/collaboration', 'name' => 'CollaborationResources#searchCollections', 'url' => '/resources/collections/search/{filter}', 'verb' => 'GET'],
['root' => '/collaboration', 'name' => 'CollaborationResources#listCollection', 'url' => '/resources/collections/{collectionId}', 'verb' => 'GET'],
['root' => '/collaboration', 'name' => 'CollaborationResources#renameCollection', 'url' => '/resources/collections/{collectionId}', 'verb' => 'PUT'],
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 53f75ebf27b..72e3ff8a8e4 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -920,6 +920,7 @@ return array(
'OC\\Core\\Controller\\ContactsMenuController' => $baseDir . '/core/Controller/ContactsMenuController.php',
'OC\\Core\\Controller\\CssController' => $baseDir . '/core/Controller/CssController.php',
'OC\\Core\\Controller\\GuestAvatarController' => $baseDir . '/core/Controller/GuestAvatarController.php',
+ 'OC\\Core\\Controller\\HoverCardController' => $baseDir . '/core/Controller/HoverCardController.php',
'OC\\Core\\Controller\\JsController' => $baseDir . '/core/Controller/JsController.php',
'OC\\Core\\Controller\\LoginController' => $baseDir . '/core/Controller/LoginController.php',
'OC\\Core\\Controller\\LostController' => $baseDir . '/core/Controller/LostController.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 3388cc945af..c689a1c011e 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -949,6 +949,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Controller\\ContactsMenuController' => __DIR__ . '/../../..' . '/core/Controller/ContactsMenuController.php',
'OC\\Core\\Controller\\CssController' => __DIR__ . '/../../..' . '/core/Controller/CssController.php',
'OC\\Core\\Controller\\GuestAvatarController' => __DIR__ . '/../../..' . '/core/Controller/GuestAvatarController.php',
+ 'OC\\Core\\Controller\\HoverCardController' => __DIR__ . '/../../..' . '/core/Controller/HoverCardController.php',
'OC\\Core\\Controller\\JsController' => __DIR__ . '/../../..' . '/core/Controller/JsController.php',
'OC\\Core\\Controller\\LoginController' => __DIR__ . '/../../..' . '/core/Controller/LoginController.php',
'OC\\Core\\Controller\\LostController' => __DIR__ . '/../../..' . '/core/Controller/LostController.php',
diff --git a/lib/private/Contacts/ContactsMenu/ActionFactory.php b/lib/private/Contacts/ContactsMenu/ActionFactory.php
index 8e139f6486c..891951a88e5 100644
--- a/lib/private/Contacts/ContactsMenu/ActionFactory.php
+++ b/lib/private/Contacts/ContactsMenu/ActionFactory.php
@@ -29,26 +29,21 @@ use OCP\Contacts\ContactsMenu\ILinkAction;
class ActionFactory implements IActionFactory {
/**
- * @param string $icon
- * @param string $name
- * @param string $href
- * @return ILinkAction
+ * {@inheritDoc}
*/
- public function newLinkAction($icon, $name, $href) {
+ public function newLinkAction(string $icon, string $name, string $href, string $appId = ''): ILinkAction {
$action = new LinkAction();
$action->setName($name);
$action->setIcon($icon);
$action->setHref($href);
+ $action->setAppId($appId);
return $action;
}
/**
- * @param string $icon
- * @param string $name
- * @param string $email
- * @return ILinkAction
+ * {@inheritDoc}
*/
- public function newEMailAction($icon, $name, $email) {
- return $this->newLinkAction($icon, $name, 'mailto:' . $email);
+ public function newEMailAction(string $icon, string $name, string $email, string $appId = ''): ILinkAction {
+ return $this->newLinkAction($icon, $name, 'mailto:' . $email, $appId);
}
}
diff --git a/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php b/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
index a50318903ac..5acafed2fda 100644
--- a/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
+++ b/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
@@ -38,6 +38,9 @@ class LinkAction implements ILinkAction {
/** @var int */
private $priority = 10;
+ /** @var string */
+ private $appId;
+
/**
* @param string $icon absolute URI to an icon
*/
@@ -88,6 +91,22 @@ class LinkAction implements ILinkAction {
}
/**
+ * @param string $appId
+ * @since 23.0.0
+ */
+ public function setAppId(string $appId) {
+ $this->appId = $appId;
+ }
+
+ /**
+ * @return string
+ * @since 23.0.0
+ */
+ public function getAppId(): string {
+ return $this->appId;
+ }
+
+ /**
* @return array
*/
public function jsonSerialize() {
@@ -95,6 +114,7 @@ class LinkAction implements ILinkAction {
'title' => $this->name,
'icon' => $this->icon,
'hyperlink' => $this->href,
+ 'appId' => $this->appId,
];
}
}
diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php
index a4a53bf8774..eb7e752a87a 100644
--- a/lib/private/Contacts/ContactsMenu/ContactsStore.php
+++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php
@@ -113,9 +113,18 @@ class ContactsStore implements IContactsStore {
$options
);
+ $userId = $user->getUID();
+ $contacts = array_filter($allContacts, function ($contact) use ($userId) {
+ // When searching for multiple results, we strip out the current user
+ if (array_key_exists('UID', $contact)) {
+ return $contact['UID'] !== $userId;
+ }
+ return true;
+ });
+
$entries = array_map(function (array $contact) {
return $this->contactArrayToEntry($contact);
- }, $allContacts);
+ }, $contacts);
return $this->filterContacts(
$user,
$entries,
@@ -125,12 +134,11 @@ class ContactsStore implements IContactsStore {
/**
* Filters the contacts. Applied filters:
- * 1. filter the current user
- * 2. if the `shareapi_allow_share_dialog_user_enumeration` config option is
+ * 1. if the `shareapi_allow_share_dialog_user_enumeration` config option is
* enabled it will filter all local users
- * 3. if the `shareapi_exclude_groups` config option is enabled and the
+ * 2. if the `shareapi_exclude_groups` config option is enabled and the
* current user is in an excluded group it will filter all local users.
- * 4. if the `shareapi_only_share_with_group_members` config option is
+ * 3. if the `shareapi_only_share_with_group_members` config option is
* enabled it will filter all users which doens't have a common group
* with the current user.
*
@@ -171,10 +179,6 @@ class ContactsStore implements IContactsStore {
$selfUID = $self->getUID();
return array_values(array_filter($entries, function (IEntry $entry) use ($skipLocal, $ownGroupsOnly, $selfGroups, $selfUID, $disallowEnumeration, $restrictEnumerationGroup, $restrictEnumerationPhone, $allowEnumerationFullMatch, $filter) {
- if ($entry->getProperty('UID') === $selfUID) {
- return false;
- }
-
if ($entry->getProperty('isLocalSystemBook')) {
if ($skipLocal) {
return false;
@@ -266,11 +270,7 @@ class ContactsStore implements IContactsStore {
return null;
}
- $userId = $user->getUID();
- $allContacts = $this->contactsManager->search($shareWith, $filter);
- $contacts = array_filter($allContacts, function ($contact) use ($userId) {
- return $contact['UID'] !== $userId;
- });
+ $contacts = $this->contactsManager->search($shareWith, $filter);
$match = null;
foreach ($contacts as $contact) {
diff --git a/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php b/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php
index 9ae323c18c3..d69f219e84c 100644
--- a/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php
+++ b/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php
@@ -54,7 +54,7 @@ class EMailProvider implements IProvider {
// Skip
continue;
}
- $action = $this->actionFactory->newEMailAction($iconUrl, $address, $address);
+ $action = $this->actionFactory->newEMailAction($iconUrl, $address, $address, 'email');
$entry->addAction($action);
}
}
diff --git a/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php b/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
index 4882c0ac883..88370f193a1 100644
--- a/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
+++ b/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
@@ -83,7 +83,7 @@ class ProfileProvider implements IProvider {
$iconUrl = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/profile.svg'));
$profileActionText = $this->l10nFactory->get('core')->t('View profile');
$profileUrl = $this->urlGenerator->linkToRouteAbsolute('core.ProfilePage.index', ['targetUserId' => $targetUserId]);
- $action = $this->actionFactory->newLinkAction($iconUrl, $profileActionText, $profileUrl);
+ $action = $this->actionFactory->newLinkAction($iconUrl, $profileActionText, $profileUrl, 'profile');
// Set highest priority (by descending order), other actions have the default priority 10 as defined in lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
$action->setPriority(20);
$entry->addAction($action);
diff --git a/lib/public/Contacts/ContactsMenu/IAction.php b/lib/public/Contacts/ContactsMenu/IAction.php
index 1a2bc9b33b5..9b08bbbf04b 100644
--- a/lib/public/Contacts/ContactsMenu/IAction.php
+++ b/lib/public/Contacts/ContactsMenu/IAction.php
@@ -60,4 +60,16 @@ interface IAction extends JsonSerializable {
* @since 12.0
*/
public function getPriority();
+
+ /**
+ * @param string $appId
+ * @since 23.0.0
+ */
+ public function setAppId(string $appId);
+
+ /**
+ * @return string
+ * @since 23.0.0
+ */
+ public function getAppId(): string;
}
diff --git a/lib/public/Contacts/ContactsMenu/IActionFactory.php b/lib/public/Contacts/ContactsMenu/IActionFactory.php
index f454ea117d2..b4e4eb96819 100644
--- a/lib/public/Contacts/ContactsMenu/IActionFactory.php
+++ b/lib/public/Contacts/ContactsMenu/IActionFactory.php
@@ -35,9 +35,10 @@ interface IActionFactory {
* @param string $icon full path to the action's icon
* @param string $name localized name of the action
* @param string $href target URL
+ * @param string $appId the app ID registering the action
* @return ILinkAction
*/
- public function newLinkAction($icon, $name, $href);
+ public function newLinkAction(string $icon, string $name, string $href, string $appId = ''): ILinkAction;
/**
* Construct and return a new email action for the contacts menu
@@ -47,7 +48,8 @@ interface IActionFactory {
* @param string $icon full path to the action's icon
* @param string $name localized name of the action
* @param string $email target e-mail address
+ * @param string $appId the appName registering the action
* @return ILinkAction
*/
- public function newEMailAction($icon, $name, $email);
+ public function newEMailAction(string $icon, string $name, string $email, string $appId = ''): ILinkAction;
}
diff --git a/tests/lib/Contacts/ContactsMenu/Actions/LinkActionTest.php b/tests/lib/Contacts/ContactsMenu/Actions/LinkActionTest.php
index ed6e9ace403..1f5d37e7483 100644
--- a/tests/lib/Contacts/ContactsMenu/Actions/LinkActionTest.php
+++ b/tests/lib/Contacts/ContactsMenu/Actions/LinkActionTest.php
@@ -75,10 +75,29 @@ class LinkActionTest extends TestCase {
$this->action->setName('Nickie Works');
$this->action->setPriority(33);
$this->action->setHref('example.com');
+ $this->action->setAppId('contacts');
$expected = [
'title' => 'Nickie Works',
'icon' => 'icon-contacts',
'hyperlink' => 'example.com',
+ 'appId' => 'contacts',
+ ];
+
+ $json = $this->action->jsonSerialize();
+
+ $this->assertEquals($expected, $json);
+ }
+
+ public function testJsonSerializeNoAppName() {
+ $this->action->setIcon('icon-contacts');
+ $this->action->setName('Nickie Works');
+ $this->action->setPriority(33);
+ $this->action->setHref('example.com');
+ $expected = [
+ 'title' => 'Nickie Works',
+ 'icon' => 'icon-contacts',
+ 'hyperlink' => 'example.com',
+ 'appId' => '',
];
$json = $this->action->jsonSerialize();
diff --git a/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php b/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
index 13cc7575f43..98a31254c3e 100644
--- a/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
+++ b/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
@@ -99,7 +99,7 @@ class ContactsStoreTest extends TestCase {
],
],
]);
- $user->expects($this->once())
+ $user->expects($this->exactly(2))
->method('getUID')
->willReturn('user123');
@@ -129,7 +129,7 @@ class ContactsStoreTest extends TestCase {
],
],
]);
- $user->expects($this->once())
+ $user->expects($this->exactly(2))
->method('getUID')
->willReturn('user123');
@@ -157,7 +157,7 @@ class ContactsStoreTest extends TestCase {
'PHOTO' => base64_encode('photophotophoto'),
],
]);
- $user->expects($this->once())
+ $user->expects($this->exactly(2))
->method('getUID')
->willReturn('user123');
@@ -186,7 +186,7 @@ class ContactsStoreTest extends TestCase {
'PHOTO' => 'VALUE=uri:https://photo',
],
]);
- $user->expects($this->once())
+ $user->expects($this->exactly(2))
->method('getUID')
->willReturn('user123');
@@ -210,7 +210,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -253,7 +253,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -332,7 +332,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -411,7 +411,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -469,7 +469,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -555,7 +555,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -624,7 +624,7 @@ class ContactsStoreTest extends TestCase {
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $currentUser */
$currentUser = $this->createMock(IUser::class);
- $currentUser->expects($this->once())
+ $currentUser->expects($this->exactly(2))
->method('getUID')
->willReturn('user001');
@@ -963,9 +963,8 @@ class ContactsStoreTest extends TestCase {
'isLocalSystemBook' => false
],
]);
- $user->expects($this->once())
- ->method('getUID')
- ->willReturn('user123');
+ $user->expects($this->never())
+ ->method('getUID');
$entry = $this->contactsStore->findOne($user, 0, 'a567');