'));
+ $('#testArea').append($('
'));
+ $selector1 = $('#selector1');
+ $selector2 = $('#selector2');
+ $appendTo = $('#appendTo');
+ });
+
+ afterEach(function() {
+ $selector1.remove();
+ $selector2.remove();
+ $appendTo.remove();
+ });
+
+ describe('shareType', function() {
+ it('stops if type not supported', function() {
+ $selector1.contactsMenu('user', 1, $appendTo);
+ expect($appendTo.children().length).toEqual(0);
+
+ $selector1.contactsMenu('user', 2, $appendTo);
+ expect($appendTo.children().length).toEqual(0);
+
+ $selector1.contactsMenu('user', 3, $appendTo);
+ expect($appendTo.children().length).toEqual(0);
+
+ $selector1.contactsMenu('user', 5, $appendTo);
+ expect($appendTo.children().length).toEqual(0);
+ });
+
+ it('append list if shareType supported', function() {
+ $selector1.contactsMenu('user', 0, $appendTo);
+ expect($appendTo.children().length).toEqual(1);
+ expect($appendTo.html()).toEqual('');
+ });
+ });
+
+ describe('open on click', function() {
+ it('with one selector', function() {
+ $selector1.contactsMenu('user', 0, $appendTo);
+ expect($appendTo.children().length).toEqual(1);
+ expect($appendTo.find('div.contactsmenu-popover').hasClass('hidden')).toEqual(true);
+ $selector1.click();
+ expect($appendTo.find('div.contactsmenu-popover').hasClass('hidden')).toEqual(false);
+ });
+
+ it('with multiple selectors - 1', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+
+ expect($appendTo.children().length).toEqual(1);
+ expect($appendTo.find('div.contactsmenu-popover').hasClass('hidden')).toEqual(true);
+ $selector1.click();
+ expect($appendTo.find('div.contactsmenu-popover').hasClass('hidden')).toEqual(false);
+ });
+
+ it('with multiple selectors - 2', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+
+ expect($appendTo.children().length).toEqual(1);
+ expect($appendTo.find('div.contactsmenu-popover').hasClass('hidden')).toEqual(true);
+ $selector2.click();
+ expect($appendTo.find('div.contactsmenu-popover').hasClass('hidden')).toEqual(false);
+ });
+
+ it ('should close when clicking the selector again - 1', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+
+ expect($appendTo.children().length).toEqual(1);
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(true);
+ $selector1.click();
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(false);
+ $selector1.click();
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(true);
+ });
+
+ it ('should close when clicking the selector again - 1', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+
+ expect($appendTo.children().length).toEqual(1);
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(true);
+ $selector1.click();
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(false);
+ $selector2.click();
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(true);
+ });
+ });
+
+ describe('send requests to the server and render', function() {
+ it('load a topaction only', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+ $selector1.click();
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json; charset=utf-8' },
+ JSON.stringify({
+ "id": null,
+ "fullName": "Name 123",
+ "topAction": {
+ "title": "bar@baz.wtf",
+ "icon": "foo.svg",
+ "hyperlink": "mailto:bar%40baz.wtf"},
+ "actions": []
+ })
+ );
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual('http://localhost/index.php/contactsmenu/findOne');
+
+ expect($appendTo.html()).toEqual('');
+ });
+
+ it('load topaction and more actions', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+ $selector1.click();
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json; charset=utf-8' },
+ JSON.stringify({
+ "id": null,
+ "fullName": "Name 123",
+ "topAction": {
+ "title": "bar@baz.wtf",
+ "icon": "foo.svg",
+ "hyperlink": "mailto:bar%40baz.wtf"},
+ "actions": [{
+ "title": "Details",
+ "icon": "details.svg",
+ "hyperlink": "http:\/\/localhost\/index.php\/apps\/contacts"
+ }]
+ })
+ );
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual('http://localhost/index.php/contactsmenu/findOne');
+
+ expect($appendTo.html()).toEqual('');
+ });
+
+ it('load no actions', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+ $selector1.click();
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json; charset=utf-8' },
+ JSON.stringify({
+ "id": null,
+ "fullName": "Name 123",
+ "topAction": null,
+ "actions": []
+ })
+ );
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual('http://localhost/index.php/contactsmenu/findOne');
+
+ expect($appendTo.html()).toEqual('');
+ });
+
+ it('should throw an error', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+ $selector1.click();
+
+ fakeServer.requests[0].respond(
+ 400,
+ { 'Content-Type': 'application/json; charset=utf-8' },
+ JSON.stringify([])
+ );
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual('http://localhost/index.php/contactsmenu/findOne');
+
+ expect($appendTo.html()).toEqual('');
+ });
+
+ it('should handle 404', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+ $selector1.click();
+
+ fakeServer.requests[0].respond(
+ 404,
+ { 'Content-Type': 'application/json; charset=utf-8' },
+ JSON.stringify([])
+ );
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual('http://localhost/index.php/contactsmenu/findOne');
+
+ expect($appendTo.html()).toEqual('');
+ });
+ });
+
+ it('click anywhere else to close the menu', function() {
+ $('#selector1, #selector2').contactsMenu('user', 0, $appendTo);
+
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(true);
+ $selector1.click();
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(false);
+ $(document).click();
+ expect($appendTo.find('div').hasClass('hidden')).toEqual(true);
+ });
+});
diff --git a/core/routes.php b/core/routes.php
index 37db2642c1b..c167dad2f9f 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -61,6 +61,7 @@ $application->registerRoutes($this, [
['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'],
['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'],
['name' => 'contactsMenu#index', 'url' => '/contactsmenu/contacts', 'verb' => 'POST'],
+ ['name' => 'contactsMenu#findOne', 'url' => '/contactsmenu/findOne', 'verb' => 'POST'],
],
'ocs' => [
['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php
index 1cdb5d6fc5f..40a0bf87031 100644
--- a/lib/private/Contacts/ContactsMenu/ContactsStore.php
+++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php
@@ -59,6 +59,50 @@ class ContactsStore {
});
}
+ /**
+ * @param IUser $user
+ * @param integer $shareType
+ * @param string $shareWith
+ * @return IEntry|null
+ */
+ public function findOne(IUser $user, $shareType, $shareWith) {
+ switch($shareType) {
+ case 0:
+ case 6:
+ $filter = ['UID'];
+ break;
+ case 4:
+ $filter = ['EMAIL'];
+ break;
+ default:
+ return null;
+ }
+
+ $userId = $user->getUID();
+ $allContacts = $this->contactsManager->search($shareWith, $filter);
+ $contacts = array_filter($allContacts, function($contact) use ($userId) {
+ return $contact['UID'] !== $userId;
+ });
+ $match = null;
+
+ foreach ($contacts as $contact) {
+ if ($shareType === 4 && isset($contact['EMAIL'])) {
+ if (in_array($shareWith, $contact['EMAIL'])) {
+ $match = $contact;
+ break;
+ }
+ }
+ if ($shareType === 0 || $shareType === 6) {
+ if ($contact['UID'] === $shareWith && $contact['isLocalSystemBook'] === true) {
+ $match = $contact;
+ break;
+ }
+ }
+ }
+
+ return $match ? $this->contactArrayToEntry($match) : null;
+ }
+
/**
* @param array $contact
* @return Entry
diff --git a/lib/private/Contacts/ContactsMenu/Manager.php b/lib/private/Contacts/ContactsMenu/Manager.php
index 16d77c2df08..766b4623253 100644
--- a/lib/private/Contacts/ContactsMenu/Manager.php
+++ b/lib/private/Contacts/ContactsMenu/Manager.php
@@ -51,7 +51,7 @@ class Manager {
}
/**
- * @param string $user
+ * @param IUser $user
* @param string $filter
* @return array
*/
@@ -69,6 +69,21 @@ class Manager {
];
}
+ /**
+ * @param IUser $user
+ * @param integer $shareType
+ * @param string $shareWith
+ * @return IEntry
+ */
+ public function findOne(IUser $user, $shareType, $shareWith) {
+ $entry = $this->store->findOne($user, $shareType, $shareWith);
+ if ($entry) {
+ $this->processEntries([$entry], $user);
+ }
+
+ return $entry;
+ }
+
/**
* @param IEntry[] $entries
* @return IEntry[]
diff --git a/tests/Core/Controller/ContactsMenuControllerTest.php b/tests/Core/Controller/ContactsMenuControllerTest.php
index bf6188e9097..92a185cf2ad 100644
--- a/tests/Core/Controller/ContactsMenuControllerTest.php
+++ b/tests/Core/Controller/ContactsMenuControllerTest.php
@@ -76,4 +76,35 @@ class ContactsMenuControllerTest extends TestCase {
$this->assertEquals($entries, $response);
}
+ public function testFindOne() {
+ $user = $this->createMock(IUser::class);
+ $entry = $this->createMock(IEntry::class);
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+ $this->contactsManager->expects($this->once())
+ ->method('findOne')
+ ->with($this->equalTo($user), $this->equalTo(42), $this->equalTo('test-search-phrase'))
+ ->willReturn($entry);
+
+ $response = $this->controller->findOne(42, 'test-search-phrase');
+
+ $this->assertEquals($entry, $response);
+ }
+
+ public function testFindOne404() {
+ $user = $this->createMock(IUser::class);
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+ $this->contactsManager->expects($this->once())
+ ->method('findOne')
+ ->with($this->equalTo($user), $this->equalTo(42), $this->equalTo('test-search-phrase'))
+ ->willReturn(null);
+
+ $response = $this->controller->findOne(42, 'test-search-phrase');
+
+ $this->assertEquals([], $response->getData());
+ $this->assertEquals(404, $response->getStatus());
+ }
}
diff --git a/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php b/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
index 80c26a9078e..08da360388f 100644
--- a/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
+++ b/tests/lib/Contacts/ContactsMenu/ContactsStoreTest.php
@@ -157,4 +157,99 @@ class ContactsStoreTest extends TestCase {
$this->assertEquals('https://photo', $entries[1]->getAvatar());
}
+ public function testFindOneUser() {
+ $user = $this->createMock(IUser::class);
+ $this->contactsManager->expects($this->once())
+ ->method('search')
+ ->with($this->equalTo('a567'), $this->equalTo(['UID']))
+ ->willReturn([
+ [
+ 'UID' => 123,
+ 'isLocalSystemBook' => false
+ ],
+ [
+ 'UID' => 'a567',
+ 'FN' => 'Darren Roner',
+ 'EMAIL' => [
+ 'darren@roner.au'
+ ],
+ 'isLocalSystemBook' => true
+ ],
+ ]);
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('user123');
+
+ $entry = $this->contactsStore->findOne($user, 0, 'a567');
+
+ $this->assertEquals([
+ 'darren@roner.au'
+ ], $entry->getEMailAddresses());
+ }
+
+ public function testFindOneEMail() {
+ $user = $this->createMock(IUser::class);
+ $this->contactsManager->expects($this->once())
+ ->method('search')
+ ->with($this->equalTo('darren@roner.au'), $this->equalTo(['EMAIL']))
+ ->willReturn([
+ [
+ 'UID' => 123,
+ 'isLocalSystemBook' => false
+ ],
+ [
+ 'UID' => 'a567',
+ 'FN' => 'Darren Roner',
+ 'EMAIL' => [
+ 'darren@roner.au'
+ ],
+ 'isLocalSystemBook' => false
+ ],
+ ]);
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('user123');
+
+ $entry = $this->contactsStore->findOne($user, 4, 'darren@roner.au');
+
+ $this->assertEquals([
+ 'darren@roner.au'
+ ], $entry->getEMailAddresses());
+ }
+
+ public function testFindOneNotSupportedType() {
+ $user = $this->createMock(IUser::class);
+
+ $entry = $this->contactsStore->findOne($user, 42, 'darren@roner.au');
+
+ $this->assertEquals(null, $entry);
+ }
+
+ public function testFindOneNoMatches() {
+ $user = $this->createMock(IUser::class);
+ $this->contactsManager->expects($this->once())
+ ->method('search')
+ ->with($this->equalTo('a567'), $this->equalTo(['UID']))
+ ->willReturn([
+ [
+ 'UID' => 123,
+ 'isLocalSystemBook' => false
+ ],
+ [
+ 'UID' => 'a567',
+ 'FN' => 'Darren Roner',
+ 'EMAIL' => [
+ 'darren@roner.au123'
+ ],
+ 'isLocalSystemBook' => false
+ ],
+ ]);
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('user123');
+
+ $entry = $this->contactsStore->findOne($user, 0, 'a567');
+
+ $this->assertEquals(null, $entry);
+ }
}
diff --git a/tests/lib/Contacts/ContactsMenu/ManagerTest.php b/tests/lib/Contacts/ContactsMenu/ManagerTest.php
index 9c92ec54b9f..783e5590a29 100644
--- a/tests/lib/Contacts/ContactsMenu/ManagerTest.php
+++ b/tests/lib/Contacts/ContactsMenu/ManagerTest.php
@@ -99,4 +99,49 @@ class ManagerTest extends TestCase {
$this->assertEquals($expected, $data);
}
+ public function testFindOne() {
+ $shareTypeFilter = 42;
+ $shareWithFilter = 'foobar';
+
+ $user = $this->createMock(IUser::class);
+ $entry = current($this->generateTestEntries());
+ $provider = $this->createMock(IProvider::class);
+ $this->contactsStore->expects($this->once())
+ ->method('findOne')
+ ->with($user, $shareTypeFilter, $shareWithFilter)
+ ->willReturn($entry);
+ $this->actionProviderStore->expects($this->once())
+ ->method('getProviders')
+ ->with($user)
+ ->willReturn([$provider]);
+ $provider->expects($this->once())
+ ->method('process');
+
+ $data = $this->manager->findOne($user, $shareTypeFilter, $shareWithFilter);
+
+ $this->assertEquals($entry, $data);
+ }
+
+ public function testFindOne404() {
+ $shareTypeFilter = 42;
+ $shareWithFilter = 'foobar';
+
+ $user = $this->createMock(IUser::class);
+ $provider = $this->createMock(IProvider::class);
+ $this->contactsStore->expects($this->once())
+ ->method('findOne')
+ ->with($user, $shareTypeFilter, $shareWithFilter)
+ ->willReturn(null);
+ $this->actionProviderStore->expects($this->never())
+ ->method('getProviders')
+ ->with($user)
+ ->willReturn([$provider]);
+ $provider->expects($this->never())
+ ->method('process');
+
+ $data = $this->manager->findOne($user, $shareTypeFilter, $shareWithFilter);
+
+ $this->assertEquals(null, $data);
+ }
+
}