diff --git a/apps/dav/lib/CardDAV/AddressBookImpl.php b/apps/dav/lib/CardDAV/AddressBookImpl.php index 5034b16ed2..1aedd5d564 100644 --- a/apps/dav/lib/CardDAV/AddressBookImpl.php +++ b/apps/dav/lib/CardDAV/AddressBookImpl.php @@ -88,16 +88,26 @@ class AddressBookImpl implements IAddressBook { /** * @param string $pattern which should match within the $searchProperties * @param array $searchProperties defines the properties within the query pattern should match - * @param array $options - for future use. One should always have options! + * @param array $options Options to define the output format + * - types boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array + * example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => 'g@h.i']] + * @return array an array of contacts which are arrays of key-value-pairs + * example result: + * [ + * ['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c', 'GEO' => '37.386013;-122.082932'], + * ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['d@e.f', 'g@h.i']] + * ] * @return array an array of contacts which are arrays of key-value-pairs * @since 5.0.0 */ public function search($pattern, $searchProperties, $options) { $results = $this->backend->search($this->getKey(), $pattern, $searchProperties); + $withTypes = \array_key_exists('types', $options) && $options['types'] === true; + $vCards = []; foreach ($results as $result) { - $vCards[] = $this->vCard2Array($result['uri'], $this->readCard($result['carddata'])); + $vCards[] = $this->vCard2Array($result['uri'], $this->readCard($result['carddata']), $withTypes); } return $vCards; @@ -220,7 +230,7 @@ class AddressBookImpl implements IAddressBook { * @param VCard $vCard * @return array */ - protected function vCard2Array($uri, VCard $vCard) { + protected function vCard2Array($uri, VCard $vCard, $withTypes = false) { $result = [ 'URI' => $uri, ]; @@ -255,15 +265,28 @@ class AddressBookImpl implements IAddressBook { $result[$property->name] = []; } - $result[$property->name][] = $property->getValue(); + $type = $this->getTypeFromProperty($property); + if ($withTypes) { + $result[$property->name][] = [ + 'type' => $type, + 'value' => $property->getValue() + ]; + } else { + $result[$property->name][] = $property->getValue(); + } + } else { $result[$property->name] = $property->getValue(); } } - if ($this->addressBookInfo['principaluri'] === 'principals/system/system' && - $this->addressBookInfo['uri'] === 'system') { + if ( + $this->addressBookInfo['principaluri'] === 'principals/system/system' && ( + $this->addressBookInfo['uri'] === 'system' || + $this->addressBookInfo['{DAV:}displayname'] === $this->urlGenerator->getBaseUrl() + ) + ) { $result['isLocalSystemBook'] = true; } return $result; diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 14be956222..0d277c58bd 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -4,6 +4,10 @@ .share-autocomplete-item { display: flex; + + &.merged { + margin-left: 32px; + } .autocomplete-item-text { margin-left: 10px; margin-right: 10px; @@ -12,6 +16,27 @@ overflow: hidden; line-height: 32px; vertical-align: middle; + flex-grow: 1; + .ui-state-highlight { + border: none; + margin: 0; + } + } + &.with-description { + .autocomplete-item-text { + line-height: 100%; + } + } + .autocomplete-item-details { + display: block; + line-height: 130%; + font-size: 90%; + opacity: 0.7; + } + + .icon { + opacity: .7; + margin-right: 7px; } } @@ -204,8 +229,8 @@ } .ui-autocomplete { - /* limit dropdown height to 4 1/2 entries */ - max-height: calc(36px * 4.5);; + /* limit dropdown height to 6 1/2 entries */ + max-height: calc(36px * 6.5); overflow-y: auto; overflow-x: hidden; z-index: 1550 !important; diff --git a/core/css/icons.scss b/core/css/icons.scss index 5b96d1223a..99b1dc9c21 100644 --- a/core/css/icons.scss +++ b/core/css/icons.scss @@ -466,3 +466,7 @@ img, object, video, button, textarea, input, select, div[contenteditable='true'] @include icon-color('search', 'actions', $color-black, 1, true); } + +.icon-talk { + @include icon-color('app-dark', 'spreed', $color-black, 1); +} diff --git a/core/css/jquery-ui-fixes.scss b/core/css/jquery-ui-fixes.scss index e30beee44e..eab22e70d6 100644 --- a/core/css/jquery-ui-fixes.scss +++ b/core/css/jquery-ui-fixes.scss @@ -70,7 +70,8 @@ .ui-widget-header .ui-state-highlight { border: 1px solid var(--color-main-background); background: var(--color-main-background) none; - color: var(--color-text-lighter); + color: var(--color-text-light); + font-weight: 600; } .ui-state-highlight a, .ui-widget-content .ui-state-highlight a, @@ -171,9 +172,12 @@ &.ui-menu { padding: 0; .ui-menu-item a { + color: var(--color-text-lighter); + padding: 4px 4px 4px 14px; + &.ui-state-focus, &.ui-state-active { - font-weight: inherit; box-shadow: inset 4px 0 var(--color-primary); + color: var(--color-text); } } } diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 9c648357e6..082bf9571d 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -312,6 +312,41 @@ var suggestions = exactMatches.concat(users).concat(groups).concat(remotes).concat(remoteGroups).concat(emails).concat(circles).concat(rooms).concat(lookup); + function dynamicSort(property) { + return function (a,b) { + var aProperty = ''; + var bProperty = ''; + if (typeof a[property] !== 'undefined') { + aProperty = a[property]; + } + if (typeof b[property] !== 'undefined') { + bProperty = b[property]; + } + return (aProperty < bProperty) ? -1 : (aProperty > bProperty) ? 1 : 0; + } + } + + /** + * Sort share entries by uuid to properly group them + */ + var grouped = suggestions.sort(dynamicSort('uuid')); + + var previousUuid = null; + var groupedLength = grouped.length; + var result = []; + /** + * build the result array that only contains all contact entries from + * merged contacts, if the search term matches its contact name + */ + for (i = 0; i < groupedLength; i++) { + if (typeof grouped[i].uuid !== 'undefined' && grouped[i].uuid === previousUuid) { + grouped[i].merged = true; + } + if (searchTerm === grouped[i].name || typeof grouped[i].merged === 'undefined') { + result.push(grouped[i]); + } + previousUuid = grouped[i].uuid; + } var moreResultsAvailable = ( oc_config['sharing.maxAutocompleteResults'] > 0 @@ -328,7 +363,7 @@ ) ); - deferred.resolve(suggestions, exactMatches, moreResultsAvailable); + deferred.resolve(result, exactMatches, moreResultsAvailable); } else { deferred.reject(result.ocs.meta.message); } @@ -441,33 +476,72 @@ }, autocompleteRenderItem: function(ul, item) { - + var icon = 'icon-user'; var text = item.label; + if (typeof item.name !== 'undefined') { + text = item.name; + } if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) { - text = t('core', '{sharee} (group)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-contacts-dark'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) { - text = t('core', '{sharee} (remote)', {sharee: text}, undefined, {escape: false}); + icon = 'icon-shared'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE_GROUP) { text = t('core', '{sharee} (remote group)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-shared'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_EMAIL) { - text = t('core', '{sharee} (email)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-mail'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) { text = t('core', '{sharee} ({type}, {owner})', {sharee: text, type: item.value.circleInfo, owner: item.value.circleOwner}, undefined, {escape: false}); + icon = 'icon-circle'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_ROOM) { - text = t('core', '{sharee} (conversation)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-talk'; + } + var description = ''; + var getTranslatedType = function(type) { + switch (type) { + case 'HOME': + return t('core', 'Home'); + case 'WORK': + return t('core', 'Home'); + case 'OTHER': + return t('core', 'Other'); + default: + return type; + } + }; + if (typeof item.type !== 'undefined' && item.type !== null) { + description = getTranslatedType(item.type); } var insert = $("
"); - var avatar = $("
").appendTo(insert); - if (item.value.shareType === OC.Share.SHARE_TYPE_USER || item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) { - avatar.avatar(item.value.shareWith, 32, undefined, undefined, undefined, item.label); + if (item.merged) { + insert.addClass('merged'); + text = item.value.shareWith; } else { - avatar.imageplaceholder(text, undefined, 32); + var avatar = $("
").appendTo(insert); + if (item.value.shareType === OC.Share.SHARE_TYPE_USER || item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) { + avatar.avatar(item.value.shareWith, 32, undefined, undefined, undefined, item.label); + } else { + if (typeof item.uuid === 'undefined') { + item.uuid = text; + } + avatar.imageplaceholder(item.uuid, text, 32); + } + description = item.value.shareWith; + } + if (description !== '') { + insert.addClass('with-description'); } $("
") - .text(text) + .html( + text.replace( + new RegExp(this.term, "gi"), + "$&") + + '' + description + '' + ) .appendTo(insert); insert.attr('title', item.value.shareWith); + insert.append(''); insert = $("") .append(insert); return $("
  • ") @@ -479,6 +553,20 @@ _onSelectRecipient: function(e, s) { var self = this; + if (e.keyCode == 9) { + e.preventDefault(); + if (typeof s.item.name !== 'undefined') { + e.target.value = s.item.name; + } else { + e.target.value = s.item.label; + } + setTimeout(function() { + $(e.target).attr('disabled', false) + .autocomplete('search', $(e.target).val()); + }, 0); + return false; + } + e.preventDefault(); // Ensure that the keydown handler for the input field is not // called; otherwise it would try to add the recipient again, which diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 101d6845ec..6faa5d5d12 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -84,11 +84,17 @@ class MailPlugin implements ISearchPlugin { foreach ($addressBookContacts as $contact) { if (isset($contact['EMAIL'])) { $emailAddresses = $contact['EMAIL']; - if (!is_array($emailAddresses)) { + if (\is_string($emailAddresses)) { $emailAddresses = [$emailAddresses]; } - foreach ($emailAddresses as $emailAddress) { + foreach ($emailAddresses as $type => $emailAddress) { $displayName = $emailAddress; + $emailAddressType = null; + if (\is_array($emailAddress)) { + $emailAddressData = $emailAddress; + $emailAddress = $emailAddressData['value']; + $emailAddressType = $emailAddressData['type']; + } if (isset($contact['FN'])) { $displayName = $contact['FN'] . ' (' . $emailAddress . ')'; } @@ -121,6 +127,8 @@ class MailPlugin implements ISearchPlugin { if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { $singleResult = [[ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], 'value' => [ 'shareType' => Share::SHARE_TYPE_USER, 'shareWith' => $cloud->getUser(), @@ -142,6 +150,8 @@ class MailPlugin implements ISearchPlugin { if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { $userResults['wide'][] = [ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], 'value' => [ 'shareType' => Share::SHARE_TYPE_USER, 'shareWith' => $cloud->getUser(), @@ -160,6 +170,9 @@ class MailPlugin implements ISearchPlugin { } $result['exact'][] = [ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $emailAddressType ?? '', 'value' => [ 'shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => $emailAddress, @@ -168,6 +181,9 @@ class MailPlugin implements ISearchPlugin { } else { $result['wide'][] = [ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $emailAddressType ?? '', 'value' => [ 'shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => $emailAddress, @@ -194,6 +210,7 @@ class MailPlugin implements ISearchPlugin { if (!$searchResult->hasExactIdMatch($emailType) && filter_var($search, FILTER_VALIDATE_EMAIL)) { $result['exact'][] = [ 'label' => $search, + 'uuid' => $search, 'value' => [ 'shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => $search, diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php index e0f5298f83..d877346b15 100644 --- a/lib/private/Collaboration/Collaborators/RemotePlugin.php +++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php @@ -30,6 +30,8 @@ use OCP\Collaboration\Collaborators\SearchResultType; use OCP\Contacts\IManager; use OCP\Federation\ICloudIdManager; use OCP\IConfig; +use OCP\IUserManager; +use OCP\IUserSession; use OCP\Share; class RemotePlugin implements ISearchPlugin { @@ -41,12 +43,20 @@ class RemotePlugin implements ISearchPlugin { private $cloudIdManager; /** @var IConfig */ private $config; + /** @var IUserManager */ + private $userManager; + /** @var string */ + private $userId = ''; - public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config) { + public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) { $this->contactsManager = $contactsManager; $this->cloudIdManager = $cloudIdManager; $this->config = $config; - + $this->userManager = $userManager; + $user = $userSession->getUser(); + if ($user !== null) { + $this->userId = $user->getUID(); + } $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; } @@ -63,23 +73,47 @@ class RemotePlugin implements ISearchPlugin { } if (isset($contact['CLOUD'])) { $cloudIds = $contact['CLOUD']; - if (!is_array($cloudIds)) { + if (is_string($cloudIds)) { $cloudIds = [$cloudIds]; } $lowerSearch = strtolower($search); foreach ($cloudIds as $cloudId) { + $cloudIdType = ''; + if (\is_array($cloudId)) { + $cloudIdData = $cloudId; + $cloudId = $cloudIdData['value']; + $cloudIdType = $cloudIdData['type']; + } try { - list(, $serverUrl) = $this->splitUserRemote($cloudId); + list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId); } catch (\InvalidArgumentException $e) { continue; } + $localUser = $this->userManager->get($remoteUser); + /** + * Add local share if remote cloud id matches a local user ones + */ + if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId() ) { + $result['wide'][] = [ + 'label' => $contact['FN'], + 'uuid' => $contact['UID'], + 'value' => [ + 'shareType' => Share::SHARE_TYPE_USER, + 'shareWith' => $remoteUser + ] + ]; + } + if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) { if (strtolower($cloudId) === $lowerSearch) { $searchResult->markExactIdMatch($resultType); } $result['exact'][] = [ 'label' => $contact['FN'] . " ($cloudId)", + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $cloudIdType, 'value' => [ 'shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => $cloudId, @@ -89,6 +123,9 @@ class RemotePlugin implements ISearchPlugin { } else { $result['wide'][] = [ 'label' => $contact['FN'] . " ($cloudId)", + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $cloudIdType, 'value' => [ 'shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => $cloudId, @@ -106,14 +143,24 @@ class RemotePlugin implements ISearchPlugin { $result['wide'] = array_slice($result['wide'], $offset, $limit); } + /** + * Add generic share with remote item for valid cloud ids that are not users of the local instance + */ if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) { - $result['exact'][] = [ - 'label' => $search, - 'value' => [ - 'shareType' => Share::SHARE_TYPE_REMOTE, - 'shareWith' => $search, - ], - ]; + try { + list($remoteUser, $serverUrl) = $this->splitUserRemote($search); + $localUser = $this->userManager->get($remoteUser); + if ($localUser === null || $search !== $localUser->getCloudId()) { + $result['exact'][] = [ + 'label' => $search, + 'value' => [ + 'shareType' => Share::SHARE_TYPE_REMOTE, + 'shareWith' => $search, + ], + ]; + } + } catch (\InvalidArgumentException $e) { + } } $searchResult->addResultSet($resultType, $result['wide'], $result['exact']); diff --git a/lib/public/IAddressBook.php b/lib/public/IAddressBook.php index 67c34c9e8c..4739e6f0c5 100644 --- a/lib/public/IAddressBook.php +++ b/lib/public/IAddressBook.php @@ -55,16 +55,18 @@ namespace OCP { /** * @param string $pattern which should match within the $searchProperties * @param array $searchProperties defines the properties within the query pattern should match - * @param array $options - for future use. One should always have options! + * @param array $options Options to define the output format + * - types boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array + * example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => 'g@h.i']] * @return array an array of contacts which are arrays of key-value-pairs + * example result: + * [ + * ['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c', 'GEO' => '37.386013;-122.082932'], + * ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['d@e.f', 'g@h.i']] + * ] * @since 5.0.0 */ public function search($pattern, $searchProperties, $options); - // // dummy results - // return array( - // array('id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c', 'GEO' => '37.386013;-122.082932'), - // array('id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => array('d@e.f', 'g@h.i')), - // ); /** * @param array $properties this array if key-value-pairs defines a contact diff --git a/tests/lib/Collaboration/Collaborators/MailPluginTest.php b/tests/lib/Collaboration/Collaborators/MailPluginTest.php index 775941bd44..a9d0244d38 100644 --- a/tests/lib/Collaboration/Collaborators/MailPluginTest.php +++ b/tests/lib/Collaboration/Collaborators/MailPluginTest.php @@ -120,16 +120,20 @@ class MailPluginTest extends TestCase { public function dataGetEmail() { return [ + // data set 0 ['test', [], true, ['emails' => [], 'exact' => ['emails' => []]], false, false], + // data set 1 ['test', [], false, ['emails' => [], 'exact' => ['emails' => []]], false, false], + // data set 2 [ 'test@remote.com', [], true, - ['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], + ['emails' => [], 'exact' => ['emails' => [['uuid' => 'test@remote.com', 'label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], false, false, ], + // data set 3 [ // no valid email address 'test@remote', [], @@ -138,26 +142,31 @@ class MailPluginTest extends TestCase { false, false, ], + // data set 4 [ 'test@remote.com', [], false, - ['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], + ['emails' => [], 'exact' => ['emails' => [['uuid' => 'test@remote.com', 'label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], false, false, ], + // data set 5 [ 'test', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -165,22 +174,26 @@ class MailPluginTest extends TestCase { ], ], true, - ['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => ['emails' => []]], + ['emails' => [['uuid' => 'uid1', 'name' => 'User @ Localhost', 'type' => '', 'label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => ['emails' => []]], false, false, ], + // data set 6 [ 'test', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -192,18 +205,22 @@ class MailPluginTest extends TestCase { false, false, ], + // data set 7 [ 'test@remote.com', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -211,22 +228,26 @@ class MailPluginTest extends TestCase { ], ], true, - ['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], + ['emails' => [['uuid' => 'uid1', 'name' => 'User @ Localhost', 'type' => '', 'label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => ['emails' => [['label' => 'test@remote.com', 'uuid' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], false, false, ], + // data set 8 [ 'test@remote.com', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -234,22 +255,26 @@ class MailPluginTest extends TestCase { ], ], false, - ['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], + ['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'uuid' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]], false, false, ], + // data set 9 [ 'username@localhost', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -257,22 +282,26 @@ class MailPluginTest extends TestCase { ], ], true, - ['emails' => [], 'exact' => ['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]]]], + ['emails' => [], 'exact' => ['emails' => [['name' => 'User @ Localhost', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]]]], true, false, ], + // data set 10 [ 'username@localhost', [ [ + 'UID' => 'uid1', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -280,23 +309,27 @@ class MailPluginTest extends TestCase { ], ], false, - ['emails' => [], 'exact' => ['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]]]], + ['emails' => [], 'exact' => ['emails' => [['name' => 'User @ Localhost', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]]]], true, false, ], + // data set 11 // contact with space [ 'user name@localhost', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User Name @ Localhost', 'EMAIL' => [ 'user name@localhost', @@ -304,23 +337,27 @@ class MailPluginTest extends TestCase { ], ], false, - ['emails' => [], 'exact' => ['emails' => [['label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'user name@localhost']]]]], + ['emails' => [], 'exact' => ['emails' => [['name' => 'User Name @ Localhost', 'uuid' => 'uid1', 'type' => '', 'label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'user name@localhost']]]]], true, false, ], + // data set 12 // remote with space, no contact [ 'user space@remote.com', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'EMAIL' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'EMAIL' => [ 'username@localhost', @@ -332,11 +369,13 @@ class MailPluginTest extends TestCase { false, false, ], + // data set 13 // Local user found by email [ 'test@example.com', [ [ + 'UID' => 'uid1', 'FN' => 'User', 'EMAIL' => ['test@example.com'], 'CLOUD' => ['test@localhost'], @@ -344,15 +383,17 @@ class MailPluginTest extends TestCase { ] ], false, - ['users' => [], 'exact' => ['users' => [['label' => 'User (test@example.com)','value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test'],]]]], + ['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User (test@example.com)','value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test'],]]]], true, false, ], + // data set 14 // Current local user found by email => no result [ 'test@example.com', [ [ + 'UID' => 'uid1', 'FN' => 'User', 'EMAIL' => ['test@example.com'], 'CLOUD' => ['current@localhost'], @@ -364,29 +405,34 @@ class MailPluginTest extends TestCase { false, false, ], + // data set 15 // Pagination and "more results" for user matches byyyyyyy emails [ 'test@example', [ [ + 'UID' => 'uid1', 'FN' => 'User1', 'EMAIL' => ['test@example.com'], 'CLOUD' => ['test1@localhost'], 'isLocalSystemBook' => true, ], [ + 'UID' => 'uid2', 'FN' => 'User2', 'EMAIL' => ['test@example.de'], 'CLOUD' => ['test2@localhost'], 'isLocalSystemBook' => true, ], [ + 'UID' => 'uid3', 'FN' => 'User3', 'EMAIL' => ['test@example.org'], 'CLOUD' => ['test3@localhost'], 'isLocalSystemBook' => true, ], [ + 'UID' => 'uid4', 'FN' => 'User4', 'EMAIL' => ['test@example.net'], 'CLOUD' => ['test4@localhost'], @@ -395,32 +441,37 @@ class MailPluginTest extends TestCase { ], true, ['users' => [ - ['label' => 'User1 (test@example.com)', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], - ['label' => 'User2 (test@example.de)', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], + ['uuid' => 'uid1', 'name' => 'User1', 'label' => 'User1 (test@example.com)', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']], + ['uuid' => 'uid2', 'name' => 'User2', 'label' => 'User2 (test@example.de)', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']], ], 'emails' => [], 'exact' => ['users' => [], 'emails' => []]], false, true, ], + // data set 16 // Pagination and "more results" for normal emails [ 'test@example', [ [ + 'UID' => 'uid1', 'FN' => 'User1', 'EMAIL' => ['test@example.com'], 'CLOUD' => ['test1@localhost'], ], [ + 'UID' => 'uid2', 'FN' => 'User2', 'EMAIL' => ['test@example.de'], 'CLOUD' => ['test2@localhost'], ], [ + 'UID' => 'uid3', 'FN' => 'User3', 'EMAIL' => ['test@example.org'], 'CLOUD' => ['test3@localhost'], ], [ + 'UID' => 'uid4', 'FN' => 'User4', 'EMAIL' => ['test@example.net'], 'CLOUD' => ['test4@localhost'], @@ -428,12 +479,45 @@ class MailPluginTest extends TestCase { ], true, ['emails' => [ - ['label' => 'User1 (test@example.com)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@example.com']], - ['label' => 'User2 (test@example.de)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@example.de']], + ['uuid' => 'uid1', 'name' => 'User1', 'type' => '', 'label' => 'User1 (test@example.com)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@example.com']], + ['uuid' => 'uid2', 'name' => 'User2', 'type' => '', 'label' => 'User2 (test@example.de)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@example.de']], ], 'exact' => ['emails' => []]], false, true, ], + // data set 17 + // multiple email addresses with type + [ + 'User Name', + [ + [ + 'UID' => 'uid3', + 'FN' => 'User3', + ], + [ + 'UID' => 'uid2', + 'FN' => 'User2', + 'EMAIL' => [ + ], + ], + [ + 'UID' => 'uid1', + 'FN' => 'User Name', + 'EMAIL' => [ + ['type' => 'HOME', 'value' => 'username@localhost'], + ['type' => 'WORK', 'value' => 'username@other'], + ], + ], + ], + false, + ['emails' => [ + ], 'exact' => ['emails' => [ + ['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'HOME', 'label' => 'User Name (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']], + ['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'WORK', 'label' => 'User Name (username@other)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@other']] + ]]], + false, + false, + ], ]; } @@ -513,7 +597,7 @@ class MailPluginTest extends TestCase { 'UID' => 'User' ] ], - ['users' => [['label' => 'User (test@example.com)','value' => ['shareType' => 0, 'shareWith' => 'test'],]], 'emails' => [], 'exact' => ['emails' => [], 'users' => []]], + ['users' => [['label' => 'User (test@example.com)', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => 0, 'shareWith' => 'test'],]], 'emails' => [], 'exact' => ['emails' => [], 'users' => []]], false, false, [ @@ -553,7 +637,7 @@ class MailPluginTest extends TestCase { 'UID' => 'User' ] ], - ['emails' => [], 'exact' => ['emails' => [['label' => 'test@example.com', 'value' => ['shareType' => 4,'shareWith' => 'test@example.com']]]]], + ['emails' => [], 'exact' => ['emails' => [['label' => 'test@example.com', 'uuid' => 'test@example.com', 'value' => ['shareType' => 4,'shareWith' => 'test@example.com']]]]], false, false, [ diff --git a/tests/lib/Collaboration/Collaborators/RemotePluginTest.php b/tests/lib/Collaboration/Collaborators/RemotePluginTest.php index aa009a7134..aff6818576 100644 --- a/tests/lib/Collaboration/Collaborators/RemotePluginTest.php +++ b/tests/lib/Collaboration/Collaborators/RemotePluginTest.php @@ -31,10 +31,17 @@ use OCP\Collaboration\Collaborators\SearchResultType; use OCP\Contacts\IManager; use OCP\Federation\ICloudIdManager; use OCP\IConfig; +use OCP\IUser; +use OCP\IUserManager; +use OCP\IUserSession; use OCP\Share; use Test\TestCase; class RemotePluginTest extends TestCase { + + /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $userManager; + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ protected $config; @@ -53,6 +60,7 @@ class RemotePluginTest extends TestCase { public function setUp() { parent::setUp(); + $this->userManager = $this->createMock(IUserManager::class); $this->config = $this->createMock(IConfig::class); $this->contactsManager = $this->createMock(IManager::class); $this->cloudIdManager = new CloudIdManager(); @@ -60,7 +68,15 @@ class RemotePluginTest extends TestCase { } public function instantiatePlugin() { - $this->plugin = new RemotePlugin($this->contactsManager, $this->cloudIdManager, $this->config); + $user = $this->createMock(IUser::class); + $user->expects($this->any()) + ->method('getUID') + ->willReturn('admin'); + $userSession = $this->createMock(IUserSession::class); + $userSession->expects($this->any()) + ->method('getUser') + ->willReturn($user); + $this->plugin = new RemotePlugin($this->contactsManager, $this->cloudIdManager, $this->config, $this->userManager, $userSession); } /** @@ -152,14 +168,17 @@ class RemotePluginTest extends TestCase { 'test', [ [ + 'UID' => 'uid', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost', @@ -167,7 +186,7 @@ class RemotePluginTest extends TestCase { ], ], true, - ['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => []]], + ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => []]], false, true, ], @@ -175,14 +194,17 @@ class RemotePluginTest extends TestCase { 'test', [ [ + 'UID' => 'uid', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost', @@ -198,14 +220,17 @@ class RemotePluginTest extends TestCase { 'test@remote', [ [ + 'UID' => 'uid', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost', @@ -213,7 +238,7 @@ class RemotePluginTest extends TestCase { ], ], true, - ['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]]]], + ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid', 'type' => '', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]]]], false, true, ], @@ -221,14 +246,17 @@ class RemotePluginTest extends TestCase { 'test@remote', [ [ + 'UID' => 'uid', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost', @@ -244,14 +272,17 @@ class RemotePluginTest extends TestCase { 'username@localhost', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => '2', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost', @@ -259,7 +290,7 @@ class RemotePluginTest extends TestCase { ], ], true, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]], + ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]], true, true, ], @@ -267,14 +298,17 @@ class RemotePluginTest extends TestCase { 'username@localhost', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost', @@ -282,7 +316,7 @@ class RemotePluginTest extends TestCase { ], ], false, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]], + ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User @ Localhost', 'label' => 'User @ Localhost (username@localhost)', 'uuid' => 'uid1', 'type' => '', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]], true, true, ], @@ -291,14 +325,17 @@ class RemotePluginTest extends TestCase { 'user name@localhost', [ [ + 'UID' => 'uid1', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid3', 'FN' => 'User Name @ Localhost', 'CLOUD' => [ 'user name@localhost', @@ -306,7 +343,7 @@ class RemotePluginTest extends TestCase { ], ], false, - ['remotes' => [], 'exact' => ['remotes' => [['label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost']]]]], + ['remotes' => [], 'exact' => ['remotes' => [['name' => 'User Name @ Localhost', 'label' => 'User Name @ Localhost (user name@localhost)', 'uuid' => 'uid3', 'type' => '', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost']]]]], true, true, ], @@ -315,14 +352,17 @@ class RemotePluginTest extends TestCase { 'user space@remote', [ [ + 'UID' => 'uid3', 'FN' => 'User3 @ Localhost', ], [ + 'UID' => 'uid2', 'FN' => 'User2 @ Localhost', 'CLOUD' => [ ], ], [ + 'UID' => 'uid1', 'FN' => 'User @ Localhost', 'CLOUD' => [ 'username@localhost',