diff --git a/apps/files_sharing/lib/Controller/ShareesAPIController.php b/apps/files_sharing/lib/Controller/ShareesAPIController.php index 40a9b272bc..e4b5b0ce19 100644 --- a/apps/files_sharing/lib/Controller/ShareesAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareesAPIController.php @@ -24,7 +24,7 @@ */ namespace OCA\Files_Sharing\Controller; -use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCSController; use OCP\Contacts\IManager; @@ -409,10 +409,22 @@ class ShareesAPIController extends OCSController { * @param int $perPage * @param int|int[] $shareType * @param bool $lookup - * @return Http\DataResponse + * @return DataResponse * @throws OCSBadRequestException */ public function search($search = '', $itemType = null, $page = 1, $perPage = 200, $shareType = null, $lookup = true) { + + // only search for string larger than a given threshold + $threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0); + if (strlen($search) < $threshold) { + return new DataResponse($this->result); + } + + // never return more than the max. number of results configured in the config.php + $maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0); + if ($maxResults > 0) { + $perPage = min($perPage, $maxResults); + } if ($perPage <= 0) { throw new OCSBadRequestException('Invalid perPage argument'); } @@ -481,7 +493,7 @@ class ShareesAPIController extends OCSController { * @param int $page * @param int $perPage * @param bool $lookup - * @return Http\DataResponse + * @return DataResponse * @throws OCSBadRequestException */ protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage, $lookup) { @@ -533,7 +545,7 @@ class ShareesAPIController extends OCSController { $this->result['exact']['emails'] = $mailResults['exact']; } - $response = new Http\DataResponse($this->result); + $response = new DataResponse($this->result); if (sizeof($this->reachedEndFor) < 3) { $response->addHeader('Link', $this->getPaginationLink($page, [ diff --git a/config/config.sample.php b/config/config.sample.php index 2a1387cecd..3ad8ffc832 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -188,7 +188,7 @@ $CONFIG = array( /** * Lifetime of the remember login cookie, which is set when the user clicks - * the ``remember`` checkbox on the login screen. + * the ``remember`` checkbox on the login screen. * * Defaults to ``60*60*24*15`` seconds (15 days) */ @@ -497,20 +497,20 @@ $CONFIG = array( * * Available values: * - * * ``auto`` - * default setting. keeps files and folders in the trash bin for 30 days - * and automatically deletes anytime after that if space is needed (note: + * * ``auto`` + * default setting. keeps files and folders in the trash bin for 30 days + * and automatically deletes anytime after that if space is needed (note: * files may not be deleted if space is not needed). - * * ``D, auto`` - * keeps files and folders in the trash bin for D+ days, delete anytime if + * * ``D, auto`` + * keeps files and folders in the trash bin for D+ days, delete anytime if * space needed (note: files may not be deleted if space is not needed) - * * ``auto, D`` - * delete all files in the trash bin that are older than D days + * * ``auto, D`` + * delete all files in the trash bin that are older than D days * automatically, delete other files anytime if space needed - * * ``D1, D2`` - * keep files and folders in the trash bin for at least D1 days and + * * ``D1, D2`` + * keep files and folders in the trash bin for at least D1 days and * delete when exceeds D2 days - * * ``disabled`` + * * ``disabled`` * trash bin auto clean disabled, files and folders will be kept forever * * Defaults to ``auto`` @@ -539,19 +539,19 @@ $CONFIG = array( * * Available values: * - * * ``auto`` - * default setting. Automatically expire versions according to expire + * * ``auto`` + * default setting. Automatically expire versions according to expire * rules. Please refer to :doc:`../configuration_files/file_versioning` for * more information. - * * ``D, auto`` - * keep versions at least for D days, apply expire rules to all versions + * * ``D, auto`` + * keep versions at least for D days, apply expire rules to all versions * that are older than D days - * * ``auto, D`` - * delete all versions that are older than D days automatically, delete + * * ``auto, D`` + * delete all versions that are older than D days automatically, delete * other versions according to expire rules - * * ``D1, D2`` + * * ``D1, D2`` * keep versions for at least D1 days and delete when exceeds D2 days - * * ``disabled`` + * * ``disabled`` * versions auto clean disabled, versions will be kept forever * * Defaults to ``auto`` @@ -1185,6 +1185,17 @@ $CONFIG = array( */ 'sharing.managerFactory' => '\OC\Share20\ProviderFactory', +/** + * Define max number of results returned by the user search for auto-completion + * Default is unlimited (value set to 0). + */ +'sharing.maxAutocompleteResults' => 0, + +/** + * Define the minimum length of the search string before we start auto-completion + * Default is no limit (value set to 0) + */ +'sharing.minSearchStringLength' => 0, /** diff --git a/core/css/share.scss b/core/css/share.scss index 8852ad2748..6d98dc7494 100644 --- a/core/css/share.scss +++ b/core/css/share.scss @@ -78,6 +78,11 @@ } } +.ui-autocomplete .autocomplete-note { + padding: 5px 10px; + color: rgba(0, 0, 0, .3); +} + #shareWithList { list-style-type: none; padding: 8px; diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 60cd97fb57..a63960da2b 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -130,18 +130,46 @@ }, autocompleteHandler: function (search, response) { - var view = this; - var $loading = this.$el.find('.shareWithLoading'); + var $shareWithField = $('.shareWithField'), + view = this, + $loading = this.$el.find('.shareWithLoading'), + $remoteShareInfo = this.$el.find('.shareWithRemoteInfo'); + + var count = oc_config['sharing.minSearchStringLength']; + if (search.term.trim().length < count) { + var title = n('core', + 'At least {count} character is needed for autocompletion', + 'At least {count} characters are needed for autocompletion', + count, + { count: count } + ); + $shareWithField.addClass('error') + .attr('data-original-title', title) + .tooltip('hide') + .tooltip({ + placement: 'bottom', + trigger: 'manual' + }) + .tooltip('fixTitle') + .tooltip('show'); + response(); + return; + } + $loading.removeClass('hidden'); $loading.addClass('inlineblock'); - var $remoteShareInfo = this.$el.find('.shareWithRemoteInfo'); $remoteShareInfo.addClass('hidden'); + + $shareWithField.removeClass('error') + .tooltip('hide'); + + var perPage = 200; $.get( OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees', { format: 'json', search: search.term.trim(), - perPage: 200, + perPage: perPage, itemType: view.model.get('itemType') }, function (result) { @@ -232,16 +260,27 @@ var suggestions = users.concat(groups).concat(remotes).concat(emails).concat(lookup); if (suggestions.length > 0) { - $('.shareWithField').removeClass('error') - .tooltip('hide') + $shareWithField .autocomplete("option", "autoFocus", true); + response(suggestions); + + // show a notice that the list is truncated + // this is the case if one of the search results is at least as long as the max result config option + if(oc_config['sharing.maxAutocompleteResults'] > 0 && + Math.min(perPage, oc_config['sharing.maxAutocompleteResults']) + <= Math.max(users.length, groups.length, remotes.length, emails.length, lookup.length)) { + + var message = t('core', 'This list is maybe truncated - please refine your search term to see more results.'); + $('.ui-autocomplete').append('
  • ' + message + '
  • '); + } + } else { - var title = t('core', 'No users or groups found for {search}', {search: $('.shareWithField').val()}); + var title = t('core', 'No users or groups found for {search}', {search: $shareWithField.val()}); if (!view.configModel.get('allowGroupSharing')) { title = t('core', 'No users found for {search}', {search: $('.shareWithField').val()}); } - $('.shareWithField').addClass('error') + $shareWithField.addClass('error') .attr('data-original-title', title) .tooltip('hide') .tooltip({ diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php index 1c241989fd..6bf08dcdad 100644 --- a/lib/private/Template/JSConfigHelper.php +++ b/lib/private/Template/JSConfigHelper.php @@ -206,7 +206,9 @@ class JSConfigHelper { 'versionstring' => \OC_Util::getVersionString(), 'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value 'lost_password_link'=> $this->config->getSystemValue('lost_password_link', null), - 'modRewriteWorking' => (\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true'), + 'modRewriteWorking' => ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true'), + 'sharing.maxAutocompleteResults' => intval($this->config->getSystemValue('sharing.maxAutocompleteResults', 0)), + 'sharing.minSearchStringLength' => intval($this->config->getSystemValue('sharing.minSearchStringLength', 0)), ]), "oc_appconfig" => json_encode([ 'core' => [