diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-11-01 19:33:50 +0300 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-11-01 19:33:58 +0300 |
commit | 98f30c2dab24f0ab80015ef7849a7d8875651f6f (patch) | |
tree | 9de386977ed99c6627410de53d0cfdfaccf4616c | |
parent | abed75e5cbd200169a236f3b586553e5d9ed0452 (diff) | |
parent | 7246f2ace50e41f68433cd89755413b512fa7909 (diff) |
Merge branch 'addressbook-uid-check-migration' of https://github.com/nextcloud/server into addressbook-uid-check-migration
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
265 files changed, 7485 insertions, 1029 deletions
diff --git a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php index 6f303acba33..3ff3ed0c569 100644 --- a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php +++ b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php @@ -170,7 +170,7 @@ class IMipPlugin extends SabreIMipPlugin { $vevent = $iTipMessage->message->VEVENT; $attendee = $this->getCurrentAttendee($iTipMessage); - $defaultLang = $this->config->getUserValue($this->userId, 'core', 'lang', $this->l10nFactory->findLanguage()); + $defaultLang = $this->l10nFactory->findLanguage(); $lang = $this->getAttendeeLangOrDefault($defaultLang, $attendee); $l10n = $this->l10nFactory->get('dav', $lang); diff --git a/apps/dav/lib/CardDAV/AddressBookImpl.php b/apps/dav/lib/CardDAV/AddressBookImpl.php index 5034b16ed2f..1aedd5d5643 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/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index 8ef0e0baf56..80a3fe2f11f 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -1134,8 +1134,8 @@ class CardDavBackend implements BackendInterface, SyncSupport { * Extract UID from vcard * * @param string $cardData the vcard raw data - * @return string the uid or empty if none - * @throws BadRequest + * @return string the uid + * @throws BadRequest if no UID is available */ private function getUID($cardData) { $vCard = Reader::read($cardData); diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php index 9e927ff85e5..57c072fda47 100644 --- a/apps/dav/lib/Connector/Sabre/File.php +++ b/apps/dav/lib/Connector/Sabre/File.php @@ -164,14 +164,19 @@ class File extends Node implements IFile { $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE); } - $target = $partStorage->fopen($internalPartPath, 'wb'); - if ($target === false) { - \OC::$server->getLogger()->error('\OC\Files\Filesystem::fopen() failed', ['app' => 'webdav']); - // because we have no clue about the cause we can only throw back a 500/Internal Server Error - throw new Exception('Could not write file contents'); + if ($partStorage->instanceOfStorage(Storage\IWriteStreamStorage::class)) { + $count = $partStorage->writeStream($internalPartPath, $data); + $result = $count > 0; + } else { + $target = $partStorage->fopen($internalPartPath, 'wb'); + if ($target === false) { + \OC::$server->getLogger()->error('\OC\Files\Filesystem::fopen() failed', ['app' => 'webdav']); + // because we have no clue about the cause we can only throw back a 500/Internal Server Error + throw new Exception('Could not write file contents'); + } + list($count, $result) = \OC_Helper::streamCopy($data, $target); + fclose($target); } - list($count, $result) = \OC_Helper::streamCopy($data, $target); - fclose($target); if ($result === false) { $expected = -1; @@ -185,7 +190,7 @@ class File extends Node implements IFile { // double check if the file was fully received // compare expected and actual size if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { - $expected = (int) $_SERVER['CONTENT_LENGTH']; + $expected = (int)$_SERVER['CONTENT_LENGTH']; if ($count !== $expected) { throw new BadRequest('expected filesize ' . $expected . ' got ' . $count); } @@ -219,7 +224,7 @@ class File extends Node implements IFile { $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath); $fileExists = $storage->file_exists($internalPath); if ($renameOkay === false || $fileExists === false) { - \OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: ' . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']); + \OC::$server->getLogger()->error('renaming part file to final file failed $renameOkay: ' . ($renameOkay ? 'true' : 'false') . ', $fileExists: ' . ($fileExists ? 'true' : 'false') . ')', ['app' => 'webdav']); throw new Exception('Could not rename part file to final file'); } } catch (ForbiddenException $ex) { @@ -246,7 +251,7 @@ class File extends Node implements IFile { $this->header('X-OC-MTime: accepted'); } } - + if ($view) { $this->emitPostHooks($exists); } @@ -443,7 +448,7 @@ class File extends Node implements IFile { //detect aborted upload if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = (int) $_SERVER['CONTENT_LENGTH']; + $expected = (int)$_SERVER['CONTENT_LENGTH']; if ($bytesWritten !== $expected) { $chunk_handler->remove($info['index']); throw new BadRequest( diff --git a/apps/dav/tests/unit/Connector/Sabre/FileTest.php b/apps/dav/tests/unit/Connector/Sabre/FileTest.php index 5e7a6374206..edb61edc6ed 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FileTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FileTest.php @@ -164,7 +164,7 @@ class FileTest extends \Test\TestCase { public function testSimplePutFails($thrownException, $expectedException, $checkPreviousClass = true) { // setup $storage = $this->getMockBuilder(Local::class) - ->setMethods(['fopen']) + ->setMethods(['writeStream']) ->setConstructorArgs([['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]) ->getMock(); \OC\Files\Filesystem::mount($storage, [], $this->user . '/'); @@ -182,11 +182,11 @@ class FileTest extends \Test\TestCase { if ($thrownException !== null) { $storage->expects($this->once()) - ->method('fopen') + ->method('writeStream') ->will($this->throwException($thrownException)); } else { $storage->expects($this->once()) - ->method('fopen') + ->method('writeStream') ->will($this->returnValue(false)); } diff --git a/apps/files/css/detailsView.scss b/apps/files/css/detailsView.scss index f64a3702850..71062648c97 100644 --- a/apps/files/css/detailsView.scss +++ b/apps/files/css/detailsView.scss @@ -15,7 +15,13 @@ #app-sidebar .mainFileInfoView .permalink { padding: 6px 10px; - vertical-align: text-top; + vertical-align: top; + opacity: .6; + + &:hover, + &:focus { + opacity: 1; + } } #app-sidebar .mainFileInfoView .permalink-field>input { clear: both; @@ -87,7 +93,7 @@ } #app-sidebar .fileName h3 { - width: calc(100% - 36px); /* 36px is the with of the copy link icon */ + width: calc(100% - 42px); /* 36px is the with of the copy link icon, but this breaks so we add some more to be sure */ display: inline-block; padding: 5px 0; margin: -5px 0; diff --git a/apps/files/css/files.scss b/apps/files/css/files.scss index 4e0bc9c0160..d6f9bd6131e 100644 --- a/apps/files/css/files.scss +++ b/apps/files/css/files.scss @@ -8,7 +8,12 @@ } /* FILE MENU */ -.actions { padding:5px; height:32px; display: inline-block; float: left; } +.actions { + padding: 5px; + height: 100%; + display: inline-block; + float: left; +} .actions input, .actions button, .actions .button { margin:0; float:left; } .actions .button a { color: #555; } .actions .button a:hover, @@ -316,6 +321,7 @@ table td.filename .thumbnail { background-size: 32px; margin-left: 9px; margin-top: 9px; + border-radius: var(--border-radius); cursor: pointer; position: absolute; z-index: 4; @@ -658,8 +664,14 @@ table.dragshadow td.size { top: 100%; margin-top: 4px; min-width: 100px; - margin-left: 7px; + margin-left: 22px; /* Align left edge below center of + button … */ + transform: translateX(-50%); /* … then center it below button */ z-index: 1001; + + /* Center triangle */ + &::after { + left: calc(50% - 8px) !important; + } } #filestable .filename .action .icon, diff --git a/apps/files/js/detailsview.js b/apps/files/js/detailsview.js index cd602961c0a..bac2a5ebd21 100644 --- a/apps/files/js/detailsview.js +++ b/apps/files/js/detailsview.js @@ -174,6 +174,9 @@ // hide other tabs $tabsContainer.find('.tab').addClass('hidden'); + $tabsContainer.attr('class', 'tabsContainer'); + $tabsContainer.addClass(tabView.getTabsContainerExtraClasses()); + // tab already rendered ? if (!$tabEl.length) { // render tab diff --git a/apps/files/js/detailtabview.js b/apps/files/js/detailtabview.js index a66cedbc15d..1e046f30246 100644 --- a/apps/files/js/detailtabview.js +++ b/apps/files/js/detailtabview.js @@ -41,6 +41,21 @@ }, /** + * Returns the extra CSS classes used by the tabs container when this + * tab is the selected one. + * + * In general you should not extend this method, as tabs should not + * modify the classes of its container; this is reserved as a last + * resort for very specific cases in which there is no other way to get + * the proper style or behaviour. + * + * @return {String} space-separated CSS classes + */ + getTabsContainerExtraClasses: function() { + return ''; + }, + + /** * Returns the tab label * * @return {String} label diff --git a/apps/files/l10n/cs.js b/apps/files/l10n/cs.js index cbd6c72d572..96b93d361e7 100644 --- a/apps/files/l10n/cs.js +++ b/apps/files/l10n/cs.js @@ -142,6 +142,7 @@ OC.L10N.register( "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Použijte tuto adresu pro <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">přístup k vašim souborům přes WebDAV</a>", "Cancel upload" : "Zrušit nahrávání", + "Toggle grid view" : "Přepnout zobrazení mřížky", "No files in here" : "Žádné soubory", "Upload some content or sync with your devices!" : "Nahrajte nějaký obsah nebo synchronizujte se svými přístroji!", "No entries found in this folder" : "V této složce nebylo nic nalezeno", diff --git a/apps/files/l10n/cs.json b/apps/files/l10n/cs.json index a8f82c5c5d7..cb01165503d 100644 --- a/apps/files/l10n/cs.json +++ b/apps/files/l10n/cs.json @@ -140,6 +140,7 @@ "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Použijte tuto adresu pro <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">přístup k vašim souborům přes WebDAV</a>", "Cancel upload" : "Zrušit nahrávání", + "Toggle grid view" : "Přepnout zobrazení mřížky", "No files in here" : "Žádné soubory", "Upload some content or sync with your devices!" : "Nahrajte nějaký obsah nebo synchronizujte se svými přístroji!", "No entries found in this folder" : "V této složce nebylo nic nalezeno", diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js index d3f738dcf8a..4406882cd21 100644 --- a/apps/files_external/js/app.js +++ b/apps/files_external/js/app.js @@ -8,16 +8,16 @@ * */ -if (!OCA.External) { +if (!OCA.Files_External) { /** * @namespace */ - OCA.External = {}; + OCA.Files_External = {}; } /** * @namespace */ -OCA.External.App = { +OCA.Files_External.App = { fileList: null, @@ -26,7 +26,7 @@ OCA.External.App = { return this.fileList; } - this.fileList = new OCA.External.FileList( + this.fileList = new OCA.Files_External.FileList( $el, { fileActions: this._createFileActions() @@ -67,10 +67,10 @@ OCA.External.App = { $(document).ready(function() { $('#app-content-extstoragemounts').on('show', function(e) { - OCA.External.App.initList($(e.target)); + OCA.Files_External.App.initList($(e.target)); }); $('#app-content-extstoragemounts').on('hide', function() { - OCA.External.App.removeList(); + OCA.Files_External.App.removeList(); }); /* Status Manager */ @@ -82,27 +82,27 @@ $(document).ready(function() { if (e.dir === '/') { var mount_point = e.previousDir.split('/', 2)[1]; // Every time that we return to / root folder from a mountpoint, mount_point status is rechecked - OCA.External.StatusManager.getMountPointList(function() { - OCA.External.StatusManager.recheckConnectivityForMount([mount_point], true); + OCA.Files_External.StatusManager.getMountPointList(function() { + OCA.Files_External.StatusManager.recheckConnectivityForMount([mount_point], true); }); } }) .on('fileActionsReady', function(e){ if ($.isArray(e.$files)) { - if (OCA.External.StatusManager.mountStatus === null || - OCA.External.StatusManager.mountPointList === null || - _.size(OCA.External.StatusManager.mountStatus) !== _.size(OCA.External.StatusManager.mountPointList)) { + if (OCA.Files_External.StatusManager.mountStatus === null || + OCA.Files_External.StatusManager.mountPointList === null || + _.size(OCA.Files_External.StatusManager.mountStatus) !== _.size(OCA.Files_External.StatusManager.mountPointList)) { // Will be the very first check when the files view will be loaded - OCA.External.StatusManager.launchFullConnectivityCheckOneByOne(); + OCA.Files_External.StatusManager.launchFullConnectivityCheckOneByOne(); } else { // When we change between general files view and external files view - OCA.External.StatusManager.getMountPointList(function(){ + OCA.Files_External.StatusManager.getMountPointList(function(){ var fileNames = []; $.each(e.$files, function(key, value){ fileNames.push(value.attr('data-file')); }); // Recheck if launched but work from cache - OCA.External.StatusManager.recheckConnectivityForMount(fileNames, false); + OCA.Files_External.StatusManager.recheckConnectivityForMount(fileNames, false); }); } } diff --git a/apps/files_external/js/mountsfilelist.js b/apps/files_external/js/mountsfilelist.js index 90b90e38745..034c29c05c2 100644 --- a/apps/files_external/js/mountsfilelist.js +++ b/apps/files_external/js/mountsfilelist.js @@ -10,7 +10,7 @@ (function() { /** - * @class OCA.External.FileList + * @class OCA.Files_External.FileList * @augments OCA.Files.FileList * * @classdesc External storage file list. @@ -27,7 +27,7 @@ }; FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, - /** @lends OCA.External.FileList.prototype */ { + /** @lends OCA.Files_External.FileList.prototype */ { appName: 'External storages', _allowSelection: false, @@ -43,7 +43,7 @@ }, /** - * @param {OCA.External.MountPointInfo} fileData + * @param {OCA.Files_External.MountPointInfo} fileData */ _createRow: function(fileData) { // TODO: hook earlier and render the whole row here @@ -138,12 +138,12 @@ /** * Mount point info attributes. * - * @typedef {Object} OCA.External.MountPointInfo + * @typedef {Object} OCA.Files_External.MountPointInfo * * @property {String} name mount point name * @property {String} scope mount point scope "personal" or "system" * @property {String} backend external storage backend name */ - OCA.External.FileList = FileList; + OCA.Files_External.FileList = FileList; })(); diff --git a/apps/files_external/js/oauth1.js b/apps/files_external/js/oauth1.js index 79248a3e3b2..56e674b213b 100644 --- a/apps/files_external/js/oauth1.js +++ b/apps/files_external/js/oauth1.js @@ -4,7 +4,7 @@ $(document).ready(function() { $tr.find('.configuration input.auth-param').attr('disabled', 'disabled').addClass('disabled-success'); } - OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { + OCA.Files_External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { if (authMechanism === 'oauth1::oauth1') { var config = $tr.find('.configuration'); config.append($(document.createElement('input')) @@ -34,7 +34,7 @@ $(document).ready(function() { $(token).val(result.access_token); $(token_secret).val(result.access_token_secret); $(configured).val('true'); - OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) { + OCA.Files_External.Settings.mountConfig.saveStorageConfig($tr, function(status) { if (status) { displayGranted($tr); } @@ -64,7 +64,7 @@ $(document).ready(function() { $(configured).val('false'); $(token).val(result.data.request_token); $(token_secret).val(result.data.request_token_secret); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function() { + OCA.Files_External.Settings.mountConfig.saveStorageConfig(tr, function() { window.location = result.data.url; }); } else { diff --git a/apps/files_external/js/oauth2.js b/apps/files_external/js/oauth2.js index 13b5162694e..fb7160d6684 100644 --- a/apps/files_external/js/oauth2.js +++ b/apps/files_external/js/oauth2.js @@ -4,7 +4,7 @@ $(document).ready(function() { $tr.find('.configuration input.auth-param').attr('disabled', 'disabled').addClass('disabled-success'); } - OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { + OCA.Files_External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { if (authMechanism === 'oauth2::oauth2') { var config = $tr.find('.configuration'); config.append($(document.createElement('input')) @@ -43,7 +43,7 @@ $(document).ready(function() { if (result && result.status == 'success') { $(token).val(result.data.token); $(configured).val('true'); - OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) { + OCA.Files_External.Settings.mountConfig.saveStorageConfig($tr, function(status) { if (status) { displayGranted($tr); } @@ -80,7 +80,7 @@ $(document).ready(function() { if (result && result.status == 'success') { $(configured).val('false'); $(token).val('false'); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function(status) { + OCA.Files_External.Settings.mountConfig.saveStorageConfig(tr, function(status) { window.location = result.data.url; }); } else { diff --git a/apps/files_external/js/public_key.js b/apps/files_external/js/public_key.js index 6856c7d021f..9b9ca6038c8 100644 --- a/apps/files_external/js/public_key.js +++ b/apps/files_external/js/public_key.js @@ -1,6 +1,6 @@ $(document).ready(function() { - OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { + OCA.Files_External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { if (scheme === 'publickey' && authMechanism === 'publickey::rsa') { var config = $tr.find('.configuration'); if ($(config).find('[name="public_key_generate"]').length === 0) { @@ -53,7 +53,7 @@ $(document).ready(function() { if (result && result.status === 'success') { $(config).find('[data-parameter="public_key"]').val(result.data.public_key).keyup(); $(config).find('[data-parameter="private_key"]').val(result.data.private_key); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function() { + OCA.Files_External.Settings.mountConfig.saveStorageConfig(tr, function() { // Nothing to do }); } else { diff --git a/apps/files_external/js/rollingqueue.js b/apps/files_external/js/rollingqueue.js index 53e11cb1219..df3797ada89 100644 --- a/apps/files_external/js/rollingqueue.js +++ b/apps/files_external/js/rollingqueue.js @@ -124,14 +124,14 @@ var RollingQueue = function (functionList, queueWindow, callback) { }; }; -if (!OCA.External) { - OCA.External = {}; +if (!OCA.Files_External) { + OCA.Files_External = {}; } -if (!OCA.External.StatusManager) { - OCA.External.StatusManager = {}; +if (!OCA.Files_External.StatusManager) { + OCA.Files_External.StatusManager = {}; } -OCA.External.StatusManager.RollingQueue = RollingQueue; +OCA.Files_External.StatusManager.RollingQueue = RollingQueue; })(); diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 2d495281527..adf3f766202 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -163,7 +163,7 @@ function addSelect2 ($elements, userListLimit) { } /** - * @class OCA.External.Settings.StorageConfig + * @class OCA.Files_External.Settings.StorageConfig * * @classdesc External storage config */ @@ -185,7 +185,7 @@ StorageConfig.Visibility = { DEFAULT: 3 }; /** - * @memberof OCA.External.Settings + * @memberof OCA.Files_External.Settings */ StorageConfig.prototype = { _url: null, @@ -348,8 +348,8 @@ StorageConfig.prototype = { }; /** - * @class OCA.External.Settings.GlobalStorageConfig - * @augments OCA.External.Settings.StorageConfig + * @class OCA.Files_External.Settings.GlobalStorageConfig + * @augments OCA.Files_External.Settings.StorageConfig * * @classdesc Global external storage config */ @@ -359,10 +359,10 @@ var GlobalStorageConfig = function(id) { this.applicableGroups = []; }; /** - * @memberOf OCA.External.Settings + * @memberOf OCA.Files_External.Settings */ GlobalStorageConfig.prototype = _.extend({}, StorageConfig.prototype, - /** @lends OCA.External.Settings.GlobalStorageConfig.prototype */ { + /** @lends OCA.Files_External.Settings.GlobalStorageConfig.prototype */ { _url: 'apps/files_external/globalstorages', /** @@ -402,8 +402,8 @@ GlobalStorageConfig.prototype = _.extend({}, StorageConfig.prototype, }); /** - * @class OCA.External.Settings.UserStorageConfig - * @augments OCA.External.Settings.StorageConfig + * @class OCA.Files_External.Settings.UserStorageConfig + * @augments OCA.Files_External.Settings.StorageConfig * * @classdesc User external storage config */ @@ -411,13 +411,13 @@ var UserStorageConfig = function(id) { this.id = id; }; UserStorageConfig.prototype = _.extend({}, StorageConfig.prototype, - /** @lends OCA.External.Settings.UserStorageConfig.prototype */ { + /** @lends OCA.Files_External.Settings.UserStorageConfig.prototype */ { _url: 'apps/files_external/userstorages' }); /** - * @class OCA.External.Settings.UserGlobalStorageConfig - * @augments OCA.External.Settings.StorageConfig + * @class OCA.Files_External.Settings.UserGlobalStorageConfig + * @augments OCA.Files_External.Settings.StorageConfig * * @classdesc User external storage config */ @@ -425,13 +425,13 @@ var UserGlobalStorageConfig = function (id) { this.id = id; }; UserGlobalStorageConfig.prototype = _.extend({}, StorageConfig.prototype, - /** @lends OCA.External.Settings.UserStorageConfig.prototype */ { + /** @lends OCA.Files_External.Settings.UserStorageConfig.prototype */ { _url: 'apps/files_external/userglobalstorages' }); /** - * @class OCA.External.Settings.MountOptionsDropdown + * @class OCA.Files_External.Settings.MountOptionsDropdown * * @classdesc Dropdown for mount options * @@ -440,7 +440,7 @@ UserGlobalStorageConfig.prototype = _.extend({}, StorageConfig.prototype, var MountOptionsDropdown = function() { }; /** - * @memberof OCA.External.Settings + * @memberof OCA.Files_External.Settings */ MountOptionsDropdown.prototype = { /** @@ -462,7 +462,7 @@ MountOptionsDropdown.prototype = { MountOptionsDropdown._last.hide(); } - var $el = $(OCA.External.Templates.mountOptionsDropDown({ + var $el = $(OCA.Files_External.Templates.mountOptionsDropDown({ mountOptionsEncodingLabel: t('files_external', 'Compatibility with Mac NFD encoding (slow)'), mountOptionsEncryptLabel: t('files_external', 'Enable encryption'), mountOptionsPreviewsLabel: t('files_external', 'Enable previews'), @@ -549,7 +549,7 @@ MountOptionsDropdown.prototype = { }; /** - * @class OCA.External.Settings.MountConfigListView + * @class OCA.Files_External.Settings.MountConfigListView * * @classdesc Mount configuration list view * @@ -574,7 +574,7 @@ MountConfigListView.ParameterTypes = { }; /** - * @memberOf OCA.External.Settings + * @memberOf OCA.Files_External.Settings */ MountConfigListView.prototype = _.extend({ @@ -633,9 +633,9 @@ MountConfigListView.prototype = _.extend({ this.$el = $el; this._isPersonal = ($el.data('admin') !== true); if (this._isPersonal) { - this._storageConfigClass = OCA.External.Settings.UserStorageConfig; + this._storageConfigClass = OCA.Files_External.Settings.UserStorageConfig; } else { - this._storageConfigClass = OCA.External.Settings.GlobalStorageConfig; + this._storageConfigClass = OCA.Files_External.Settings.GlobalStorageConfig; } if (options && !_.isUndefined(options.userListLimit)) { @@ -1008,7 +1008,7 @@ MountConfigListView.prototype = _.extend({ * Gets the storage model from the given row * * @param $tr row element - * @return {OCA.External.StorageConfig} storage model instance + * @return {OCA.Files_External.StorageConfig} storage model instance */ getStorageConfig: function($tr) { var storageId = $tr.data('id'); @@ -1367,13 +1367,13 @@ $(document).ready(function() { }); // global instance - OCA.External.Settings.mountConfig = mountConfigListView; + OCA.Files_External.Settings.mountConfig = mountConfigListView; /** * Legacy * * @namespace - * @deprecated use OCA.External.Settings.mountConfig instead + * @deprecated use OCA.Files_External.Settings.mountConfig instead */ OC.MountConfig = { saveStorage: _.bind(mountConfigListView.saveStorageConfig, mountConfigListView) @@ -1382,14 +1382,14 @@ $(document).ready(function() { // export -OCA.External = OCA.External || {}; +OCA.Files_External = OCA.Files_External || {}; /** * @namespace */ -OCA.External.Settings = OCA.External.Settings || {}; +OCA.Files_External.Settings = OCA.Files_External.Settings || {}; -OCA.External.Settings.GlobalStorageConfig = GlobalStorageConfig; -OCA.External.Settings.UserStorageConfig = UserStorageConfig; -OCA.External.Settings.MountConfigListView = MountConfigListView; +OCA.Files_External.Settings.GlobalStorageConfig = GlobalStorageConfig; +OCA.Files_External.Settings.UserStorageConfig = UserStorageConfig; +OCA.Files_External.Settings.MountConfigListView = MountConfigListView; })(); diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index b8b5e1a9364..b4e89bd6232 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -14,15 +14,15 @@ /** @global Handlebars */ -if (!OCA.External) { - OCA.External = {}; +if (!OCA.Files_External) { + OCA.Files_External = {}; } -if (!OCA.External.StatusManager) { - OCA.External.StatusManager = {}; +if (!OCA.Files_External.StatusManager) { + OCA.Files_External.StatusManager = {}; } -OCA.External.StatusManager = { +OCA.Files_External.StatusManager = { mountStatus: null, mountPointList: null, @@ -209,18 +209,18 @@ OCA.External.StatusManager = { var mountPoint = mountData.mount_point; if (mountStatus.status > 0) { - var trElement = FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(mountPoint)); + var trElement = FileList.findFileEl(OCA.Files_External.StatusManager.Utils.jqSelEscape(mountPoint)); - var route = OCA.External.StatusManager.Utils.getIconRoute(trElement) + '-error'; + var route = OCA.Files_External.StatusManager.Utils.getIconRoute(trElement) + '-error'; - if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { - OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), route); + if (OCA.Files_External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.Files_External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.Files_External.StatusManager.manageMountPointError, OCA.Files_External.StatusManager), route); } return false; } else { - if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { - OCA.External.StatusManager.Utils.restoreFolder(mountPoint); - OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + if (OCA.Files_External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.Files_External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.Files_External.StatusManager.Utils.toggleLink(mountPoint, true, true); } return true; } @@ -235,7 +235,7 @@ OCA.External.StatusManager = { processMountList: function (mountList) { var elementList = null; $.each(mountList, function (name, value) { - var trElement = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point)); + var trElement = $('#fileList tr[data-file=\"' + OCA.Files_External.StatusManager.Utils.jqSelEscape(value.mount_point) + '\"]'); //FileList.findFileEl(OCA.Files_External.StatusManager.Utils.jqSelEscape(value.mount_point)); trElement.attr('data-external-backend', value.backend); if (elementList) { elementList = elementList.add(trElement); @@ -245,14 +245,14 @@ OCA.External.StatusManager = { }); if (elementList instanceof $) { - if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + if (OCA.Files_External.StatusManager.Utils.isCorrectViewAndRootFolder()) { // Put their custom icon - OCA.External.StatusManager.Utils.changeFolderIcon(elementList); + OCA.Files_External.StatusManager.Utils.changeFolderIcon(elementList); // Save default view - OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); + OCA.Files_External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); // Disable row until check status elementList.addClass('externalDisabledRow'); - OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); + OCA.Files_External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); } } }, @@ -289,7 +289,7 @@ OCA.External.StatusManager = { ajaxQueue.push(queueElement); }); - var rolQueue = new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4, function () { + var rolQueue = new OCA.Files_External.StatusManager.RollingQueue(ajaxQueue, 4, function () { if (!self.notificationHasShown) { var showNotification = false; $.each(self.mountStatus, function (key, value) { @@ -335,7 +335,7 @@ OCA.External.StatusManager = { }; ajaxQueue.push(queueElement); }); - new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue(); + new OCA.Files_External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue(); }, @@ -392,7 +392,7 @@ OCA.External.StatusManager = { * @param mountData */ showCredentialsDialog: function (mountPoint, mountData) { - var dialog = $(OCA.External.Templates.credentialsDialog({ + var dialog = $(OCA.Files_External.Templates.credentialsDialog({ credentials_text: t('files_external', 'Please enter the credentials for the {mount} mount', { 'mount': mountPoint }), @@ -422,7 +422,7 @@ OCA.External.StatusManager = { OC.Notification.show(t('files_external', 'Credentials saved'), {type: 'error'}); dialog.ocdialog('close'); /* Trigger status check again */ - OCA.External.StatusManager.recheckConnectivityForMount([OC.basename(data.mountPoint)], true); + OCA.Files_External.StatusManager.recheckConnectivityForMount([OC.basename(data.mountPoint)], true); }, error: function () { $('.oc-dialog-close').show(); @@ -461,11 +461,11 @@ OCA.External.StatusManager = { } }; -OCA.External.StatusManager.Utils = { +OCA.Files_External.StatusManager.Utils = { showIconError: function (folder, clickAction, errorImageUrl) { var imageUrl = "url(" + errorImageUrl + ")"; - var trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); + var trFolder = $('#fileList tr[data-file=\"' + OCA.Files_External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.Files_External.StatusManager.Utils.jqSelEscape(folder)); this.changeFolderIcon(folder, imageUrl); this.toggleLink(folder, false, clickAction); trFolder.addClass('externalErroredRow'); @@ -479,7 +479,7 @@ OCA.External.StatusManager.Utils = { if (folder instanceof $) { trFolder = folder; } else { - trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); //$('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); + trFolder = $('#fileList tr[data-file=\"' + OCA.Files_External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); //FileList.findFileEl(OCA.Files_External.StatusManager.Utils.jqSelEscape(folder)); //$('#fileList tr[data-file=\"' + OCA.Files_External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); } trFolder.each(function () { var thisElement = $(this); @@ -505,8 +505,8 @@ OCA.External.StatusManager.Utils = { if (folder instanceof $) { trFolder = folder; } else { - // can't use here FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(folder)); return incorrect instance of filelist - trFolder = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); + // can't use here FileList.findFileEl(OCA.Files_External.StatusManager.Utils.jqSelEscape(folder)); return incorrect instance of filelist + trFolder = $('#fileList tr[data-file=\"' + OCA.Files_External.StatusManager.Utils.jqSelEscape(folder) + '\"]'); } trFolder.removeClass('externalErroredRow').removeClass('externalDisabledRow'); var tdChilds = trFolder.find("td.filename div.thumbnail"); @@ -526,14 +526,14 @@ OCA.External.StatusManager.Utils = { if (filename instanceof $) { //trElementList $.each(filename, function (index) { - route = OCA.External.StatusManager.Utils.getIconRoute($(this)); + route = OCA.Files_External.StatusManager.Utils.getIconRoute($(this)); $(this).attr("data-icon", route); $(this).find('td.filename div.thumbnail').css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline'); }); } else { file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td.filename div.thumbnail"); var parentTr = file.parents('tr:first'); - route = OCA.External.StatusManager.Utils.getIconRoute(parentTr); + route = OCA.Files_External.StatusManager.Utils.getIconRoute(parentTr); parentTr.attr("data-icon", route); file.css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline'); } diff --git a/apps/files_external/js/templates.js b/apps/files_external/js/templates.js index 067b3f5f5d7..cf1522334c5 100644 --- a/apps/files_external/js/templates.js +++ b/apps/files_external/js/templates.js @@ -1,5 +1,5 @@ (function() { - var template = Handlebars.template, templates = OCA.External.Templates = OCA.External.Templates || {}; + var template = Handlebars.template, templates = OCA.Files_External.Templates = OCA.Files_External.Templates || {}; templates['credentialsDialog'] = template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; diff --git a/apps/files_external/tests/appSpec.js b/apps/files_external/tests/appSpec.js index 43902d1c1d0..a834d96e2c0 100644 --- a/apps/files_external/tests/appSpec.js +++ b/apps/files_external/tests/appSpec.js @@ -19,8 +19,8 @@ * */ -describe('OCA.External.App tests', function() { - var App = OCA.External.App; +describe('OCA.Files_External.App tests', function() { + var App = OCA.Files_External.App; var fileList; beforeEach(function() { diff --git a/apps/files_external/tests/js/mountsfilelistSpec.js b/apps/files_external/tests/js/mountsfilelistSpec.js index feea68cf346..fe2fd8dec84 100644 --- a/apps/files_external/tests/js/mountsfilelistSpec.js +++ b/apps/files_external/tests/js/mountsfilelistSpec.js @@ -8,7 +8,7 @@ * */ -describe('OCA.External.FileList tests', function() { +describe('OCA.Files_External.FileList tests', function() { var testFiles, alertStub, notificationStub, fileList; beforeEach(function() { @@ -62,7 +62,7 @@ describe('OCA.External.FileList tests', function() { var ocsResponse; beforeEach(function() { - fileList = new OCA.External.FileList( + fileList = new OCA.Files_External.FileList( $('#app-content-container') ); diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js index 57ad4550993..e004871650c 100644 --- a/apps/files_external/tests/js/settingsSpec.js +++ b/apps/files_external/tests/js/settingsSpec.js @@ -8,7 +8,7 @@ * */ -describe('OCA.External.Settings tests', function() { +describe('OCA.Files_External.Settings tests', function() { var clock; var select2Stub; var select2ApplicableUsers; @@ -156,7 +156,7 @@ describe('OCA.External.Settings tests', function() { beforeEach(function() { var $el = $('#externalStorage'); - view = new OCA.External.Settings.MountConfigListView($el, {encryptionEnabled: false}); + view = new OCA.Files_External.Settings.MountConfigListView($el, {encryptionEnabled: false}); }); afterEach(function() { view = null; diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 14be9562228..0d277c58bd7 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/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index ff19c35e2b5..a935189491e 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -252,6 +252,7 @@ class ShareAPIController extends OCSController { $result['mail_send'] = $share->getMailSend() ? 1 : 0; + $result['hide_download'] = $share->getHideDownload() ? 1 : 0; return $result; } @@ -745,6 +746,7 @@ class ShareAPIController extends OCSController { * @param string $publicUpload * @param string $expireDate * @param string $note + * @param string $hideDownload * @return DataResponse * @throws LockedException * @throws NotFoundException @@ -759,7 +761,8 @@ class ShareAPIController extends OCSController { string $sendPasswordByTalk = null, string $publicUpload = null, string $expireDate = null, - string $note = null + string $note = null, + string $hideDownload = null ): DataResponse { try { $share = $this->getShareById($id); @@ -773,7 +776,7 @@ class ShareAPIController extends OCSController { throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); } - if ($permissions === null && $password === null && $sendPasswordByTalk === null && $publicUpload === null && $expireDate === null && $note === null) { + if ($permissions === null && $password === null && $sendPasswordByTalk === null && $publicUpload === null && $expireDate === null && $note === null && $hideDownload === null) { throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given')); } @@ -786,6 +789,13 @@ class ShareAPIController extends OCSController { */ if ($share->getShareType() === Share::SHARE_TYPE_LINK) { + // Update hide download state + if ($hideDownload === 'true') { + $share->setHideDownload(true); + } else if ($hideDownload === 'false') { + $share->setHideDownload(false); + } + $newPermissions = null; if ($publicUpload === 'true') { $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; diff --git a/apps/files_sharing/lib/Controller/ShareController.php b/apps/files_sharing/lib/Controller/ShareController.php index 1e3cbb51028..1a92000a5f6 100644 --- a/apps/files_sharing/lib/Controller/ShareController.php +++ b/apps/files_sharing/lib/Controller/ShareController.php @@ -321,6 +321,7 @@ class ShareController extends AuthPublicShareController { $shareTmpl['dir'] = ''; $shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize(); $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize()); + $shareTmpl['hideDownload'] = $share->getHideDownload(); // Show file list $hideFileList = false; @@ -444,12 +445,14 @@ class ShareController extends AuthPublicShareController { $response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl); $response->setHeaderTitle($shareTmpl['filename']); $response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['displayName']])); - $response->setHeaderActions([ - new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0), - new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']), - new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']), - new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['displayName'], $shareTmpl['filename']), - ]); + if (!$share->getHideDownload()) { + $response->setHeaderActions([ + new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0), + new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']), + new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']), + new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['displayName'], $shareTmpl['filename']), + ]); + } $response->setContentSecurityPolicy($csp); diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index da80f8d1377..4487e63f2de 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -11,13 +11,16 @@ <input type="hidden" id="filesApp" name="filesApp" value="1"> <input type="hidden" id="isPublic" name="isPublic" value="1"> <input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir"> -<input type="hidden" name="downloadURL" value="<?php p($_['downloadURL']) ?>" id="downloadURL"> +<?php if (!$_['hideDownload']): ?> + <input type="hidden" name="downloadURL" value="<?php p($_['downloadURL']) ?>" id="downloadURL"> +<?php endif; ?> <input type="hidden" name="previewURL" value="<?php p($_['previewURL']) ?>" id="previewURL"> <input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken"> <input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename"> <input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype"> <input type="hidden" name="previewSupported" value="<?php p($_['previewSupported'] ? 'true' : 'false'); ?>" id="previewSupported"> <input type="hidden" name="mimetypeIcon" value="<?php p(\OC::$server->getMimeTypeDetector()->mimeTypeIcon($_['mimetype'])); ?>" id="mimetypeIcon"> +<input type="hidden" name="hideDownload" value="<?php p($_['hideDownload'] ? 'true' : 'false'); ?>" id="hideDownload"> <?php $upload_max_filesize = OC::$server->getIniWrapper()->getBytes('upload_max_filesize'); $post_max_size = OC::$server->getIniWrapper()->getBytes('post_max_size'); @@ -58,7 +61,7 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size); <!-- Preview frame is filled via JS to support SVG images for modern browsers --> <div id="imgframe"></div> <?php endif; ?> - <?php if ($_['previewURL'] === $_['downloadURL']): ?> + <?php if ($_['previewURL'] === $_['downloadURL'] && !$_['hideDownload']): ?> <div class="directDownload"> <a href="<?php p($_['downloadURL']); ?>" id="downloadFile" class="button"> <span class="icon icon-download"></span> @@ -97,4 +100,4 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size); data-url="<?php p(\OC::$server->getURLGenerator()->linkTo('files', 'ajax/upload.php')); ?>" /> </div> <?php endif; ?> -</div>
\ No newline at end of file +</div> diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 15c4071bc46..bd263de3f62 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -353,6 +353,7 @@ class ShareAPIControllerTest extends TestCase { 'note' => 'personal note', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myMimeType', + 'hide_download' => 0, ]; $data[] = [$share, $expected]; @@ -397,6 +398,7 @@ class ShareAPIControllerTest extends TestCase { 'note' => 'personal note', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myFolderMimeType', + 'hide_download' => 0, ]; $data[] = [$share, $expected]; @@ -445,6 +447,7 @@ class ShareAPIControllerTest extends TestCase { 'note' => 'personal note', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myFolderMimeType', + 'hide_download' => 0, ]; $data[] = [$share, $expected]; @@ -2175,6 +2178,7 @@ class ShareAPIControllerTest extends TestCase { 'note' => 'personal note', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, [], false ]; // User backend up @@ -2204,6 +2208,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'recipientDN', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, [ ['owner', $owner], ['initiator', $initiator], @@ -2249,6 +2254,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'recipient', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2292,6 +2298,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'recipientGroupDisplayName', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2333,6 +2340,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'recipientGroup2', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2377,6 +2385,7 @@ class ShareAPIControllerTest extends TestCase { 'mail_send' => 0, 'url' => 'myLink', 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2418,6 +2427,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'foobar', 'mail_send' => 0, 'mimetype' => 'myFolderMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2462,6 +2472,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_avatar' => 'path/to/the/avatar', 'mail_send' => 0, 'mimetype' => 'myFolderMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2504,6 +2515,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_avatar' => '', 'mail_send' => 0, 'mimetype' => 'myFolderMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2546,6 +2558,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_avatar' => '', 'mail_send' => 0, 'mimetype' => 'myFolderMimeType', + 'hide_download' => 0, ], $share, [], false ]; @@ -2603,7 +2616,8 @@ class ShareAPIControllerTest extends TestCase { 'mail_send' => 0, 'mimetype' => 'myFolderMimeType', 'password' => 'password', - 'send_password_by_talk' => false + 'send_password_by_talk' => false, + 'hide_download' => 0, ], $share, [], false ]; @@ -2647,7 +2661,8 @@ class ShareAPIControllerTest extends TestCase { 'mail_send' => 0, 'mimetype' => 'myFolderMimeType', 'password' => 'password', - 'send_password_by_talk' => true + 'send_password_by_talk' => true, + 'hide_download' => 0, ], $share, [], false ]; @@ -2787,6 +2802,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => '', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, false, [] ]; @@ -2828,6 +2844,7 @@ class ShareAPIControllerTest extends TestCase { 'share_with_displayname' => 'recipientRoomName', 'mail_send' => 0, 'mimetype' => 'myMimeType', + 'hide_download' => 0, ], $share, true, [ 'share_with_displayname' => 'recipientRoomName' ] diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php index a01560d0288..c5306cbc0ce 100644 --- a/apps/files_sharing/tests/Controller/ShareControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php @@ -287,7 +287,8 @@ class ShareControllerTest extends \Test\TestCase { 'shareUrl' => null, 'previewImage' => null, 'previewURL' => 'downloadURL', - 'note' => $note + 'note' => $note, + 'hideDownload' => false ); $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); @@ -306,6 +307,120 @@ class ShareControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } + public function testShowShareHideDownload() { + $note = 'personal note'; + + $this->shareController->setToken('token'); + + $owner = $this->getMockBuilder(IUser::class)->getMock(); + $owner->method('getDisplayName')->willReturn('ownerDisplay'); + $owner->method('getUID')->willReturn('ownerUID'); + + $file = $this->getMockBuilder('OCP\Files\File')->getMock(); + $file->method('getName')->willReturn('file1.txt'); + $file->method('getMimetype')->willReturn('text/plain'); + $file->method('getSize')->willReturn(33); + $file->method('isReadable')->willReturn(true); + $file->method('isShareable')->willReturn(true); + + $share = \OC::$server->getShareManager()->newShare(); + $share->setId(42); + $share->setPassword('password') + ->setShareOwner('ownerUID') + ->setNode($file) + ->setNote($note) + ->setTarget('/file1.txt') + ->setHideDownload(true); + + $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); + $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); + + // Even if downloads are disabled the "downloadURL" parameter is + // provided to the template, as it is needed to preview audio and GIF + // files. + $this->urlGenerator->expects($this->at(0)) + ->method('linkToRouteAbsolute') + ->with('files_sharing.sharecontroller.downloadShare', ['token' => 'token']) + ->willReturn('downloadURL'); + + $this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true); + + $this->config->method('getSystemValue') + ->willReturnMap( + [ + ['max_filesize_animated_gifs_public_sharing', 10, 10], + ['enable_previews', true, true], + ['preview_max_x', 1024, 1024], + ['preview_max_y', 1024, 1024], + ] + ); + $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); + $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); + + $this->shareManager + ->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('core', 'shareapi_public_link_disclaimertext', null) + ->willReturn('My disclaimer text'); + + $this->userManager->method('get')->with('ownerUID')->willReturn($owner); + + $this->eventDispatcher->expects($this->once()) + ->method('dispatch') + ->with('OCA\Files_Sharing::loadAdditionalScripts'); + + $this->l10n->expects($this->any()) + ->method('t') + ->will($this->returnCallback(function($text, $parameters) { + return vsprintf($text, $parameters); + })); + + $response = $this->shareController->showShare(); + $sharedTmplParams = array( + 'displayName' => 'ownerDisplay', + 'owner' => 'ownerUID', + 'filename' => 'file1.txt', + 'directory_path' => '/file1.txt', + 'mimetype' => 'text/plain', + 'dirToken' => 'token', + 'sharingToken' => 'token', + 'server2serversharing' => true, + 'protected' => 'true', + 'dir' => '', + 'downloadURL' => 'downloadURL', + 'fileSize' => '33 B', + 'nonHumanFileSize' => 33, + 'maxSizeAnimateGif' => 10, + 'previewSupported' => true, + 'previewEnabled' => true, + 'previewMaxX' => 1024, + 'previewMaxY' => 1024, + 'hideFileList' => false, + 'shareOwner' => 'ownerDisplay', + 'disclaimer' => 'My disclaimer text', + 'shareUrl' => null, + 'previewImage' => null, + 'previewURL' => 'downloadURL', + 'note' => $note, + 'hideDownload' => true + ); + + $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $csp->addAllowedFrameDomain('\'self\''); + $expectedResponse = new PublicTemplateResponse($this->appName, 'public', $sharedTmplParams); + $expectedResponse->setContentSecurityPolicy($csp); + $expectedResponse->setHeaderTitle($sharedTmplParams['filename']); + $expectedResponse->setHeaderDetails('shared by ' . $sharedTmplParams['displayName']); + $expectedResponse->setHeaderActions([]); + + $this->assertEquals($expectedResponse, $response); + } + /** * @expectedException \OCP\Files\NotFoundException */ diff --git a/apps/files_versions/appinfo/info.xml b/apps/files_versions/appinfo/info.xml index d2f873edb07..6d1b3085f80 100644 --- a/apps/files_versions/appinfo/info.xml +++ b/apps/files_versions/appinfo/info.xml @@ -41,4 +41,8 @@ <collection>OCA\Files_Versions\Sabre\RootCollection</collection> </collections> </sabre> + + <versions> + <backend for="OCP\Files\Storage\IStorage">OCA\Files_Versions\Versions\LegacyVersionsBackend</backend> + </versions> </info> diff --git a/apps/files_versions/composer/composer/autoload_classmap.php b/apps/files_versions/composer/composer/autoload_classmap.php index 4bb112b4f11..1283e533914 100644 --- a/apps/files_versions/composer/composer/autoload_classmap.php +++ b/apps/files_versions/composer/composer/autoload_classmap.php @@ -23,4 +23,11 @@ return array( 'OCA\\Files_Versions\\Sabre\\VersionHome' => $baseDir . '/../lib/Sabre/VersionHome.php', 'OCA\\Files_Versions\\Sabre\\VersionRoot' => $baseDir . '/../lib/Sabre/VersionRoot.php', 'OCA\\Files_Versions\\Storage' => $baseDir . '/../lib/Storage.php', + 'OCA\\Files_Versions\\Versions\\BackendNotFoundException' => $baseDir . '/../lib/Versions/BackendNotFoundException.php', + 'OCA\\Files_Versions\\Versions\\IVersion' => $baseDir . '/../lib/Versions/IVersion.php', + 'OCA\\Files_Versions\\Versions\\IVersionBackend' => $baseDir . '/../lib/Versions/IVersionBackend.php', + 'OCA\\Files_Versions\\Versions\\IVersionManager' => $baseDir . '/../lib/Versions/IVersionManager.php', + 'OCA\\Files_Versions\\Versions\\LegacyVersionsBackend' => $baseDir . '/../lib/Versions/LegacyVersionsBackend.php', + 'OCA\\Files_Versions\\Versions\\Version' => $baseDir . '/../lib/Versions/Version.php', + 'OCA\\Files_Versions\\Versions\\VersionManager' => $baseDir . '/../lib/Versions/VersionManager.php', ); diff --git a/apps/files_versions/composer/composer/autoload_static.php b/apps/files_versions/composer/composer/autoload_static.php index 29bc592b41c..6a6b753c2e5 100644 --- a/apps/files_versions/composer/composer/autoload_static.php +++ b/apps/files_versions/composer/composer/autoload_static.php @@ -38,6 +38,13 @@ class ComposerStaticInitFiles_Versions 'OCA\\Files_Versions\\Sabre\\VersionHome' => __DIR__ . '/..' . '/../lib/Sabre/VersionHome.php', 'OCA\\Files_Versions\\Sabre\\VersionRoot' => __DIR__ . '/..' . '/../lib/Sabre/VersionRoot.php', 'OCA\\Files_Versions\\Storage' => __DIR__ . '/..' . '/../lib/Storage.php', + 'OCA\\Files_Versions\\Versions\\BackendNotFoundException' => __DIR__ . '/..' . '/../lib/Versions/BackendNotFoundException.php', + 'OCA\\Files_Versions\\Versions\\IVersion' => __DIR__ . '/..' . '/../lib/Versions/IVersion.php', + 'OCA\\Files_Versions\\Versions\\IVersionBackend' => __DIR__ . '/..' . '/../lib/Versions/IVersionBackend.php', + 'OCA\\Files_Versions\\Versions\\IVersionManager' => __DIR__ . '/..' . '/../lib/Versions/IVersionManager.php', + 'OCA\\Files_Versions\\Versions\\LegacyVersionsBackend' => __DIR__ . '/..' . '/../lib/Versions/LegacyVersionsBackend.php', + 'OCA\\Files_Versions\\Versions\\Version' => __DIR__ . '/..' . '/../lib/Versions/Version.php', + 'OCA\\Files_Versions\\Versions\\VersionManager' => __DIR__ . '/..' . '/../lib/Versions/VersionManager.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/apps/files_versions/js/versionstabview.js b/apps/files_versions/js/versionstabview.js index 61309a30d50..213ee1ae83c 100644 --- a/apps/files_versions/js/versionstabview.js +++ b/apps/files_versions/js/versionstabview.js @@ -38,6 +38,10 @@ return t('files_versions', 'Versions'); }, + getIcon: function() { + return 'icon-history'; + }, + nextPage: function() { if (this._loading) { return; diff --git a/apps/files_versions/lib/AppInfo/Application.php b/apps/files_versions/lib/AppInfo/Application.php index 340b5ab5cbd..935556221fa 100644 --- a/apps/files_versions/lib/AppInfo/Application.php +++ b/apps/files_versions/lib/AppInfo/Application.php @@ -24,9 +24,10 @@ namespace OCA\Files_Versions\AppInfo; use OCA\DAV\Connector\Sabre\Principal; +use OCA\Files_Versions\Versions\IVersionManager; +use OCA\Files_Versions\Versions\VersionManager; use OCP\AppFramework\App; -use OCA\Files_Versions\Expiration; -use OCP\AppFramework\Utility\ITimeFactory; +use OCP\AppFramework\IAppContainer; use OCA\Files_Versions\Capabilities; class Application extends App { @@ -43,14 +44,45 @@ class Application extends App { /* * Register $principalBackend for the DAV collection */ - $container->registerService('principalBackend', function () { + $container->registerService('principalBackend', function (IAppContainer $c) { + $server = $c->getServer(); return new Principal( - \OC::$server->getUserManager(), - \OC::$server->getGroupManager(), - \OC::$server->getShareManager(), - \OC::$server->getUserSession(), - \OC::$server->getConfig() + $server->getUserManager(), + $server->getGroupManager(), + $server->getShareManager(), + $server->getUserSession(), + $server->getConfig() ); }); + + $container->registerService(IVersionManager::class, function(IAppContainer $c) { + return new VersionManager(); + }); + + $this->registerVersionBackends(); + } + + public function registerVersionBackends() { + $server = $this->getContainer()->getServer(); + $logger = $server->getLogger(); + $appManager = $server->getAppManager(); + /** @var IVersionManager $versionManager */ + $versionManager = $this->getContainer()->getServer()->query(IVersionManager::class); + foreach($appManager->getInstalledApps() as $app) { + $appInfo = $appManager->getAppInfo($app); + if (isset($appInfo['versions'])) { + $backends = $appInfo['versions']; + foreach($backends as $backend) { + $class = $backend['@value']; + $for = $backend['@attributes']['for']; + try { + $backendObject = $server->query($class); + $versionManager->registerBackend($for, $backendObject); + } catch (\Exception $e) { + $logger->logException($e); + } + } + } + } } } diff --git a/apps/files_versions/lib/Controller/PreviewController.php b/apps/files_versions/lib/Controller/PreviewController.php index b8bf464fb3f..f41250a8971 100644 --- a/apps/files_versions/lib/Controller/PreviewController.php +++ b/apps/files_versions/lib/Controller/PreviewController.php @@ -21,45 +21,53 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_Versions\Controller; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\FileDisplayResponse; -use OCP\Files\File; -use OCP\Files\Folder; use OCP\Files\IMimeTypeDetector; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\IPreview; use OCP\IRequest; +use OCP\IUserSession; class PreviewController extends Controller { /** @var IRootFolder */ private $rootFolder; - /** @var string */ - private $userId; + /** @var IUserSession */ + private $userSession; /** @var IMimeTypeDetector */ private $mimeTypeDetector; + /** @var IVersionManager */ + private $versionManager; + /** @var IPreview */ private $previewManager; - public function __construct($appName, - IRequest $request, - IRootFolder $rootFolder, - $userId, - IMimeTypeDetector $mimeTypeDetector, - IPreview $previewManager) { + public function __construct( + $appName, + IRequest $request, + IRootFolder $rootFolder, + IUserSession $userSession, + IMimeTypeDetector $mimeTypeDetector, + IVersionManager $versionManager, + IPreview $previewManager + ) { parent::__construct($appName, $request); $this->rootFolder = $rootFolder; - $this->userId = $userId; + $this->userSession = $userSession; $this->mimeTypeDetector = $mimeTypeDetector; + $this->versionManager = $versionManager; $this->previewManager = $previewManager; } @@ -79,20 +87,17 @@ class PreviewController extends Controller { $y = 44, $version = '' ) { - if($file === '' || $version === '' || $x === 0 || $y === 0) { + if ($file === '' || $version === '' || $x === 0 || $y === 0) { return new DataResponse([], Http::STATUS_BAD_REQUEST); } try { - $userFolder = $this->rootFolder->getUserFolder($this->userId); - /** @var Folder $versionFolder */ - $versionFolder = $userFolder->getParent()->get('files_versions'); - $mimeType = $this->mimeTypeDetector->detectPath($file); - $file = $versionFolder->get($file.'.v'.$version); - - /** @var File $file */ - $f = $this->previewManager->getPreview($file, $x, $y, true, IPreview::MODE_FILL, $mimeType); - return new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]); + $user = $this->userSession->getUser(); + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $file = $userFolder->get($file); + $versionFile = $this->versionManager->getVersionFile($user, $file, (int)$version); + $preview = $this->previewManager->getPreview($versionFile, $x, $y, true, IPreview::MODE_FILL, $versionFile->getMimetype()); + return new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => $preview->getMimeType()]); } catch (NotFoundException $e) { return new DataResponse([], Http::STATUS_NOT_FOUND); } catch (\InvalidArgumentException $e) { diff --git a/apps/files_versions/lib/Sabre/RestoreFolder.php b/apps/files_versions/lib/Sabre/RestoreFolder.php index c398d02692b..c8504646bad 100644 --- a/apps/files_versions/lib/Sabre/RestoreFolder.php +++ b/apps/files_versions/lib/Sabre/RestoreFolder.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace OCA\Files_Versions\Sabre; +use OCP\IUser; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\ICollection; use Sabre\DAV\IMoveTarget; @@ -31,14 +32,6 @@ use Sabre\DAV\INode; class RestoreFolder implements ICollection, IMoveTarget { - - /** @var string */ - protected $userId; - - public function __construct(string $userId) { - $this->userId = $userId; - } - public function createFile($name, $data = null) { throw new Forbidden(); } @@ -80,7 +73,8 @@ class RestoreFolder implements ICollection, IMoveTarget { return false; } - return $sourceNode->rollBack(); + $sourceNode->rollBack(); + return true; } } diff --git a/apps/files_versions/lib/Sabre/RootCollection.php b/apps/files_versions/lib/Sabre/RootCollection.php index ca5979573b5..504c3362505 100644 --- a/apps/files_versions/lib/Sabre/RootCollection.php +++ b/apps/files_versions/lib/Sabre/RootCollection.php @@ -20,10 +20,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_Versions\Sabre; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\Files\IRootFolder; use OCP\IConfig; +use OCP\IUserManager; use Sabre\DAV\INode; use Sabre\DAVACL\AbstractPrincipalCollection; use Sabre\DAVACL\PrincipalBackend; @@ -33,12 +36,24 @@ class RootCollection extends AbstractPrincipalCollection { /** @var IRootFolder */ private $rootFolder; - public function __construct(PrincipalBackend\BackendInterface $principalBackend, - IRootFolder $rootFolder, - IConfig $config) { + /** @var IUserManager */ + private $userManager; + + /** @var IVersionManager */ + private $versionManager; + + public function __construct( + PrincipalBackend\BackendInterface $principalBackend, + IRootFolder $rootFolder, + IConfig $config, + IUserManager $userManager, + IVersionManager $versionManager + ) { parent::__construct($principalBackend, 'principals/users'); $this->rootFolder = $rootFolder; + $this->userManager = $userManager; + $this->versionManager = $versionManager; $this->disableListing = !$config->getSystemValue('debug', false); } @@ -54,12 +69,12 @@ class RootCollection extends AbstractPrincipalCollection { * @return INode */ public function getChildForPrincipal(array $principalInfo) { - list(,$name) = \Sabre\Uri\split($principalInfo['uri']); + list(, $name) = \Sabre\Uri\split($principalInfo['uri']); $user = \OC::$server->getUserSession()->getUser(); if (is_null($user) || $name !== $user->getUID()) { throw new \Sabre\DAV\Exception\Forbidden(); } - return new VersionHome($principalInfo, $this->rootFolder); + return new VersionHome($principalInfo, $this->rootFolder, $this->userManager, $this->versionManager); } public function getName() { diff --git a/apps/files_versions/lib/Sabre/VersionCollection.php b/apps/files_versions/lib/Sabre/VersionCollection.php index 481a5f491c3..9a3a6a365f0 100644 --- a/apps/files_versions/lib/Sabre/VersionCollection.php +++ b/apps/files_versions/lib/Sabre/VersionCollection.php @@ -21,11 +21,15 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_Versions\Sabre; use OCA\Files_Versions\Storage; +use OCA\Files_Versions\Versions\IVersion; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\Files\File; use OCP\Files\Folder; +use OCP\IUser; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\ICollection; @@ -37,13 +41,17 @@ class VersionCollection implements ICollection { /** @var File */ private $file; - /** @var string */ - private $userId; + /** @var IUser */ + private $user; + + /** @var IVersionManager */ + private $versionManager; - public function __construct(Folder $userFolder, File $file, string $userId) { + public function __construct(Folder $userFolder, File $file, IUser $user, IVersionManager $versionManager) { $this->userFolder = $userFolder; $this->file = $file; - $this->userId = $userId; + $this->user = $user; + $this->versionManager = $versionManager; } public function createFile($name, $data = null) { @@ -68,10 +76,10 @@ class VersionCollection implements ICollection { } public function getChildren(): array { - $versions = Storage::getVersions($this->userId, $this->userFolder->getRelativePath($this->file->getPath())); + $versions = $this->versionManager->getVersionsForFile($this->user, $this->file); - return array_map(function (array $data) { - return new VersionFile($data, $this->userFolder->getParent()); + return array_map(function (IVersion $version) { + return new VersionFile($version, $this->versionManager); }, $versions); } diff --git a/apps/files_versions/lib/Sabre/VersionFile.php b/apps/files_versions/lib/Sabre/VersionFile.php index 347058448fc..2d630008d2a 100644 --- a/apps/files_versions/lib/Sabre/VersionFile.php +++ b/apps/files_versions/lib/Sabre/VersionFile.php @@ -21,26 +21,26 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_Versions\Sabre; -use OCA\Files_Versions\Storage; -use OCP\Files\File; -use OCP\Files\Folder; +use OCA\Files_Versions\Versions\IVersion; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\Files\NotFoundException; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\IFile; class VersionFile implements IFile { - /** @var array */ - private $data; + /** @var IVersion */ + private $version; - /** @var Folder */ - private $userRoot; + /** @var IVersionManager */ + private $versionManager; - public function __construct(array $data, Folder $userRoot) { - $this->data = $data; - $this->userRoot = $userRoot; + public function __construct(IVersion $version, IVersionManager $versionManager) { + $this->version = $version; + $this->versionManager = $versionManager; } public function put($data) { @@ -49,27 +49,22 @@ class VersionFile implements IFile { public function get() { try { - /** @var Folder $versions */ - $versions = $this->userRoot->get('files_versions'); - /** @var File $version */ - $version = $versions->get($this->data['path'].'.v'.$this->data['version']); + return $this->versionManager->read($this->version); } catch (NotFoundException $e) { throw new NotFound(); } - - return $version->fopen('rb'); } public function getContentType(): string { - return $this->data['mimetype']; + return $this->version->getMimeType(); } public function getETag(): string { - return $this->data['version']; + return (string)$this->version->getRevisionId(); } public function getSize(): int { - return $this->data['size']; + return $this->version->getSize(); } public function delete() { @@ -77,7 +72,7 @@ class VersionFile implements IFile { } public function getName(): string { - return $this->data['version']; + return (string)$this->version->getRevisionId(); } public function setName($name) { @@ -85,10 +80,10 @@ class VersionFile implements IFile { } public function getLastModified(): int { - return (int)$this->data['version']; + return $this->version->getTimestamp(); } - public function rollBack(): bool { - return Storage::rollback($this->data['path'], $this->data['version']); + public function rollBack() { + $this->versionManager->rollback($this->version); } } diff --git a/apps/files_versions/lib/Sabre/VersionHome.php b/apps/files_versions/lib/Sabre/VersionHome.php index 7a99d2376d4..7be5974bbbe 100644 --- a/apps/files_versions/lib/Sabre/VersionHome.php +++ b/apps/files_versions/lib/Sabre/VersionHome.php @@ -20,9 +20,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_Versions\Sabre; +use OC\User\NoUserException; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\Files\IRootFolder; +use OCP\IUserManager; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\ICollection; @@ -34,9 +38,25 @@ class VersionHome implements ICollection { /** @var IRootFolder */ private $rootFolder; - public function __construct(array $principalInfo, IRootFolder $rootFolder) { + /** @var IUserManager */ + private $userManager; + + /** @var IVersionManager */ + private $versionManager; + + public function __construct(array $principalInfo, IRootFolder $rootFolder, IUserManager $userManager, IVersionManager $versionManager) { $this->principalInfo = $principalInfo; $this->rootFolder = $rootFolder; + $this->userManager = $userManager; + $this->versionManager = $versionManager; + } + + private function getUser() { + list(, $name) = \Sabre\Uri\split($this->principalInfo['uri']); + $user = $this->userManager->get($name); + if (!$user) { + throw new NoUserException(); + } } public function delete() { @@ -44,8 +64,7 @@ class VersionHome implements ICollection { } public function getName(): string { - list(,$name) = \Sabre\Uri\split($this->principalInfo['uri']); - return $name; + return $this->getUser()->getUID(); } public function setName($name) { @@ -61,22 +80,22 @@ class VersionHome implements ICollection { } public function getChild($name) { - list(,$userId) = \Sabre\Uri\split($this->principalInfo['uri']); + $user = $this->getUser(); if ($name === 'versions') { - return new VersionRoot($userId, $this->rootFolder); + return new VersionRoot($user, $this->rootFolder, $this->versionManager); } if ($name === 'restore') { - return new RestoreFolder($userId); + return new RestoreFolder(); } } public function getChildren() { - list(,$userId) = \Sabre\Uri\split($this->principalInfo['uri']); + $user = $this->getUser(); return [ - new VersionRoot($userId, $this->rootFolder), - new RestoreFolder($userId), + new VersionRoot($user, $this->rootFolder, $this->versionManager), + new RestoreFolder(), ]; } diff --git a/apps/files_versions/lib/Sabre/VersionRoot.php b/apps/files_versions/lib/Sabre/VersionRoot.php index 743b1c6ef1b..1c689a4d87b 100644 --- a/apps/files_versions/lib/Sabre/VersionRoot.php +++ b/apps/files_versions/lib/Sabre/VersionRoot.php @@ -23,23 +23,29 @@ declare(strict_types=1); */ namespace OCA\Files_Versions\Sabre; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\Files\File; use OCP\Files\IRootFolder; +use OCP\IUser; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\ICollection; class VersionRoot implements ICollection { - /** @var string */ - private $userId; + /** @var IUser */ + private $user; /** @var IRootFolder */ private $rootFolder; - public function __construct(string $userId, IRootFolder $rootFolder) { - $this->userId = $userId; + /** @var IVersionManager */ + private $versionManager; + + public function __construct(IUser $user, IRootFolder $rootFolder, IVersionManager $versionManager) { + $this->user = $user; $this->rootFolder = $rootFolder; + $this->versionManager = $versionManager; } public function delete() { @@ -63,7 +69,7 @@ class VersionRoot implements ICollection { } public function getChild($name) { - $userFolder = $this->rootFolder->getUserFolder($this->userId); + $userFolder = $this->rootFolder->getUserFolder($this->user->getUID()); $fileId = (int)$name; $nodes = $userFolder->getById($fileId); @@ -78,7 +84,7 @@ class VersionRoot implements ICollection { throw new NotFound(); } - return new VersionCollection($userFolder, $node, $this->userId); + return new VersionCollection($userFolder, $node, $this->user, $this->versionManager); } public function getChildren(): array { diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php index 401544cc5d7..e2e4888cbce 100644 --- a/apps/files_versions/lib/Storage.php +++ b/apps/files_versions/lib/Storage.php @@ -48,6 +48,7 @@ use OC\Files\View; use OCA\Files_Versions\AppInfo\Application; use OCA\Files_Versions\Command\Expire; use OCA\Files_Versions\Events\CreateVersionEvent; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\Files\NotFoundException; use OCP\Lock\ILockingProvider; use OCP\User; @@ -178,10 +179,10 @@ class Storage { list($uid, $filename) = self::getUidAndFilename($filename); $files_view = new View('/'.$uid .'/files'); - $users_view = new View('/'.$uid); $eventDispatcher = \OC::$server->getEventDispatcher(); - $id = $files_view->getFileInfo($filename)->getId(); + $fileInfo = $files_view->getFileInfo($filename); + $id = $fileInfo->getId(); $nodes = \OC::$server->getRootFolder()->getById($id); foreach ($nodes as $node) { $event = new CreateVersionEvent($node); @@ -192,20 +193,16 @@ class Storage { } // no use making versions for empty files - if ($files_view->filesize($filename) === 0) { + if ($fileInfo->getSize() === 0) { return false; } - // create all parent folders - self::createMissingDirectories($filename, $users_view); - - self::scheduleExpire($uid, $filename); + /** @var IVersionManager $versionManager */ + $versionManager = \OC::$server->query(IVersionManager::class); + $userManager = \OC::$server->getUserManager(); + $user = $userManager->get($uid); - // store a new version of a file - $mtime = $users_view->filemtime('files/' . $filename); - $users_view->copy('files/' . $filename, 'files_versions/' . $filename . '.v' . $mtime); - // call getFileInfo to enforce a file cache entry for the new version - $users_view->getFileInfo('files_versions/' . $filename . '.v' . $mtime); + $versionManager->createVersion($user, $fileInfo); } @@ -695,7 +692,7 @@ class Storage { * @param string $uid owner of the file * @param string $fileName file/folder for which to schedule expiration */ - private static function scheduleExpire($uid, $fileName) { + public static function scheduleExpire($uid, $fileName) { // let the admin disable auto expire $expiration = self::getExpiration(); if ($expiration->isEnabled()) { @@ -833,7 +830,7 @@ class Storage { * "files" folder * @param View $view view on data/user/ */ - private static function createMissingDirectories($filename, $view) { + public static function createMissingDirectories($filename, $view) { $dirname = Filesystem::normalizePath(dirname($filename)); $dirParts = explode('/', $dirname); $dir = "/files_versions"; diff --git a/apps/files_versions/lib/Versions/BackendNotFoundException.php b/apps/files_versions/lib/Versions/BackendNotFoundException.php new file mode 100644 index 00000000000..09985a716b9 --- /dev/null +++ b/apps/files_versions/lib/Versions/BackendNotFoundException.php @@ -0,0 +1,26 @@ +<?php +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +class BackendNotFoundException extends \Exception { + +} diff --git a/apps/files_versions/lib/Versions/IVersion.php b/apps/files_versions/lib/Versions/IVersion.php new file mode 100644 index 00000000000..b6fc95814d8 --- /dev/null +++ b/apps/files_versions/lib/Versions/IVersion.php @@ -0,0 +1,99 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +use OCP\Files\FileInfo; +use OCP\IUser; + +/** + * @since 15.0.0 + */ +interface IVersion { + /** + * @return IVersionBackend + * @since 15.0.0 + */ + public function getBackend(): IVersionBackend; + + /** + * Get the file info of the source file + * + * @return FileInfo + * @since 15.0.0 + */ + public function getSourceFile(): FileInfo; + + /** + * Get the id of the revision for the file + * + * @return int + * @since 15.0.0 + */ + public function getRevisionId(): int; + + /** + * Get the timestamp this version was created + * + * @return int + * @since 15.0.0 + */ + public function getTimestamp(): int; + + /** + * Get the size of this version + * + * @return int + * @since 15.0.0 + */ + public function getSize(): int; + + /** + * Get the name of the source file at the time of making this version + * + * @return string + * @since 15.0.0 + */ + public function getSourceFileName(): string; + + /** + * Get the mimetype of this version + * + * @return string + * @since 15.0.0 + */ + public function getMimeType(): string; + + /** + * Get the path of this version + * + * @return string + * @since 15.0.0 + */ + public function getVersionPath(): string; + + /** + * @return IUser + * @since 15.0.0 + */ + public function getUser(): IUser; +} diff --git a/apps/files_versions/lib/Versions/IVersionBackend.php b/apps/files_versions/lib/Versions/IVersionBackend.php new file mode 100644 index 00000000000..616d535f7fd --- /dev/null +++ b/apps/files_versions/lib/Versions/IVersionBackend.php @@ -0,0 +1,81 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +use OCP\Files\File; +use OCP\Files\FileInfo; +use OCP\Files\NotFoundException; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\IUser; + +/** + * @since 15.0.0 + */ +interface IVersionBackend { + /** + * Get all versions for a file + * + * @param IUser $user + * @param FileInfo $file + * @return IVersion[] + * @since 15.0.0 + */ + public function getVersionsForFile(IUser $user, FileInfo $file): array; + + /** + * Create a new version for a file + * + * @param IUser $user + * @param FileInfo $file + * @since 15.0.0 + */ + public function createVersion(IUser $user, FileInfo $file); + + /** + * Restore this version + * + * @param IVersion $version + * @since 15.0.0 + */ + public function rollback(IVersion $version); + + /** + * Open the file for reading + * + * @param IVersion $version + * @return resource + * @throws NotFoundException + * @since 15.0.0 + */ + public function read(IVersion $version); + + /** + * Get the preview for a specific version of a file + * + * @param IUser $user + * @param FileInfo $sourceFile + * @param int $revision + * @return ISimpleFile + * @since 15.0.0 + */ + public function getVersionFile(IUser $user, FileInfo $sourceFile, int $revision): File; +} diff --git a/apps/files_versions/lib/Versions/IVersionManager.php b/apps/files_versions/lib/Versions/IVersionManager.php new file mode 100644 index 00000000000..748b649b1a2 --- /dev/null +++ b/apps/files_versions/lib/Versions/IVersionManager.php @@ -0,0 +1,36 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +/** + * @since 15.0.0 + */ +interface IVersionManager extends IVersionBackend { + /** + * Register a new backend + * + * @param string $storageType + * @param IVersionBackend $backend + * @since 15.0.0 + */ + public function registerBackend(string $storageType, IVersionBackend $backend); +} diff --git a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php new file mode 100644 index 00000000000..7293aca641e --- /dev/null +++ b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php @@ -0,0 +1,105 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +use OC\Files\View; +use OCA\Files_Versions\Storage; +use OCP\Files\File; +use OCP\Files\FileInfo; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\IUser; + +class LegacyVersionsBackend implements IVersionBackend { + /** @var IRootFolder */ + private $rootFolder; + + public function __construct(IRootFolder $rootFolder) { + $this->rootFolder = $rootFolder; + } + + public function getVersionsForFile(IUser $user, FileInfo $file): array { + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $versions = Storage::getVersions($user->getUID(), $userFolder->getRelativePath($file->getPath())); + + return array_map(function (array $data) use ($file, $user) { + return new Version( + (int)$data['version'], + (int)$data['version'], + $data['name'], + (int)$data['size'], + $data['mimetype'], + $data['path'], + $file, + $this, + $user + ); + }, $versions); + } + + public function createVersion(IUser $user, FileInfo $file) { + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $relativePath = $userFolder->getRelativePath($file->getPath()); + $userView = new View('/' . $user->getUID()); + // create all parent folders + Storage::createMissingDirectories($relativePath, $userView); + + Storage::scheduleExpire($user->getUID(), $relativePath); + + // store a new version of a file + $userView->copy('files/' . $relativePath, 'files_versions/' . $relativePath . '.v' . $file->getMtime()); + // ensure the file is scanned + $userView->getFileInfo('files_versions/' . $relativePath . '.v' . $file->getMtime()); + } + + public function rollback(IVersion $version) { + return Storage::rollback($version->getVersionPath(), $version->getRevisionId()); + } + + private function getVersionFolder(IUser $user): Folder { + $userRoot = $this->rootFolder->getUserFolder($user->getUID()) + ->getParent(); + try { + /** @var Folder $folder */ + $folder = $userRoot->get('files_versions'); + return $folder; + } catch (NotFoundException $e) { + return $userRoot->newFolder('files_versions'); + } + } + + public function read(IVersion $version) { + $versions = $this->getVersionFolder($version->getUser()); + /** @var File $file */ + $file = $versions->get($version->getVersionPath() . '.v' . $version->getRevisionId()); + return $file->fopen('r'); + } + + public function getVersionFile(IUser $user, FileInfo $sourceFile, int $revision): File { + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $versionFolder = $this->getVersionFolder($user); + /** @var File $file */ + $file = $versionFolder->get($userFolder->getRelativePath($sourceFile->getPath()) . '.v' . $revision); + return $file; + } +} diff --git a/apps/files_versions/lib/Versions/Version.php b/apps/files_versions/lib/Versions/Version.php new file mode 100644 index 00000000000..5988234db61 --- /dev/null +++ b/apps/files_versions/lib/Versions/Version.php @@ -0,0 +1,113 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +use OCP\Files\FileInfo; +use OCP\IUser; + +class Version implements IVersion { + /** @var int */ + private $timestamp; + + /** @var int */ + private $revisionId; + + /** @var string */ + private $name; + + /** @var int */ + private $size; + + /** @var string */ + private $mimetype; + + /** @var string */ + private $path; + + /** @var FileInfo */ + private $sourceFileInfo; + + /** @var IVersionBackend */ + private $backend; + + /** @var IUser */ + private $user; + + public function __construct( + int $timestamp, + int $revisionId, + string $name, + int $size, + string $mimetype, + string $path, + FileInfo $sourceFileInfo, + IVersionBackend $backend, + IUser $user + ) { + $this->timestamp = $timestamp; + $this->revisionId = $revisionId; + $this->name = $name; + $this->size = $size; + $this->mimetype = $mimetype; + $this->path = $path; + $this->sourceFileInfo = $sourceFileInfo; + $this->backend = $backend; + $this->user = $user; + } + + public function getBackend(): IVersionBackend { + return $this->backend; + } + + public function getSourceFile(): FileInfo { + return $this->sourceFileInfo; + } + + public function getRevisionId(): int { + return $this->revisionId; + } + + public function getTimestamp(): int { + return $this->timestamp; + } + + public function getSize(): int { + return $this->size; + } + + public function getSourceFileName(): string { + return $this->name; + } + + public function getMimeType(): string { + return $this->mimetype; + } + + public function getVersionPath(): string { + return $this->path; + } + + public function getUser(): IUser { + return $this->user; + } +} diff --git a/apps/files_versions/lib/Versions/VersionManager.php b/apps/files_versions/lib/Versions/VersionManager.php new file mode 100644 index 00000000000..757b6002710 --- /dev/null +++ b/apps/files_versions/lib/Versions/VersionManager.php @@ -0,0 +1,93 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files_Versions\Versions; + +use OCP\Files\File; +use OCP\Files\FileInfo; +use OCP\Files\Storage\IStorage; +use OCP\IUser; + +class VersionManager implements IVersionManager { + /** @var IVersionBackend[] */ + private $backends = []; + + public function registerBackend(string $storageType, IVersionBackend $backend) { + $this->backends[$storageType] = $backend; + } + + /** + * @return IVersionBackend[] + */ + private function getBackends(): array { + return $this->backends; + } + + /** + * @param IStorage $storage + * @return IVersionBackend + * @throws BackendNotFoundException + */ + public function getBackendForStorage(IStorage $storage): IVersionBackend { + $fullType = get_class($storage); + $backends = $this->getBackends(); + $foundType = array_reduce(array_keys($backends), function ($type, $registeredType) use ($storage) { + if ( + $storage->instanceOfStorage($registeredType) && + ($type === '' || is_subclass_of($registeredType, $type)) + ) { + return $registeredType; + } else { + return $type; + } + }, ''); + if ($foundType === '') { + throw new BackendNotFoundException("Version backend for $fullType not found"); + } else { + return $backends[$foundType]; + } + } + + public function getVersionsForFile(IUser $user, FileInfo $file): array { + $backend = $this->getBackendForStorage($file->getStorage()); + return $backend->getVersionsForFile($user, $file); + } + + public function createVersion(IUser $user, FileInfo $file) { + $backend = $this->getBackendForStorage($file->getStorage()); + $backend->createVersion($user, $file); + } + + public function rollback(IVersion $version) { + $backend = $version->getBackend(); + return $backend->rollback($version); + } + + public function read(IVersion $version) { + $backend = $version->getBackend(); + return $backend->read($version); + } + + public function getVersionFile(IUser $user, FileInfo $sourceFile, int $revision): File { + $backend = $this->getBackendForStorage($sourceFile->getStorage()); + return $backend->getVersionFile($user, $sourceFile, $revision); + } +} diff --git a/apps/files_versions/tests/Controller/PreviewControllerTest.php b/apps/files_versions/tests/Controller/PreviewControllerTest.php index 384f43cf495..7c248b36349 100644 --- a/apps/files_versions/tests/Controller/PreviewControllerTest.php +++ b/apps/files_versions/tests/Controller/PreviewControllerTest.php @@ -20,9 +20,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_Versions\Tests\Controller; +use OC\User\User; use OCA\Files_Versions\Controller\PreviewController; +use OCA\Files_Versions\Versions\IVersionManager; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\FileDisplayResponse; @@ -34,6 +37,8 @@ use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; use OCP\IPreview; use OCP\IRequest; +use OCP\IUser; +use OCP\IUserSession; use Test\TestCase; class PreviewControllerTest extends TestCase { @@ -50,23 +55,39 @@ class PreviewControllerTest extends TestCase { /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */ private $previewManager; - /** @var PreviewController */ + /** @var PreviewController|\PHPUnit_Framework_MockObject_MockObject */ private $controller; + /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ + private $userSession; + + /** @var IVersionManager|\PHPUnit_Framework_MockObject_MockObject */ + private $versionManager; + public function setUp() { parent::setUp(); $this->rootFolder = $this->createMock(IRootFolder::class); $this->userId = 'user'; + $user = $this->createMock(IUser::class); + $user->expects($this->any()) + ->method('getUID') + ->willReturn($this->userId); $this->mimeTypeDetector = $this->createMock(IMimeTypeDetector::class); $this->previewManager = $this->createMock(IPreview::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->userSession->expects($this->any()) + ->method('getUser') + ->willReturn($user); + $this->versionManager = $this->createMock(IVersionManager::class); $this->controller = new PreviewController( 'files_versions', $this->createMock(IRequest::class), $this->rootFolder, - $this->userId, + $this->userSession, $this->mimeTypeDetector, + $this->versionManager, $this->previewManager ); } @@ -102,24 +123,23 @@ class PreviewControllerTest extends TestCase { public function testValidPreview() { $userFolder = $this->createMock(Folder::class); $userRoot = $this->createMock(Folder::class); - $versions = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->userId) ->willReturn($userFolder); $userFolder->method('getParent') ->willReturn($userRoot); - $userRoot->method('get') - ->with('files_versions') - ->willReturn($versions); - $this->mimeTypeDetector->method('detectPath') - ->with($this->equalTo('file')) - ->willReturn('myMime'); + $sourceFile = $this->createMock(File::class); + $userFolder->method('get') + ->with('file') + ->willReturn($sourceFile); $file = $this->createMock(File::class); - $versions->method('get') - ->with($this->equalTo('file.v42')) + $file->method('getMimetype') + ->willReturn('myMime'); + + $this->versionManager->method('getVersionFile') ->willReturn($file); $preview = $this->createMock(ISimpleFile::class); @@ -138,24 +158,23 @@ class PreviewControllerTest extends TestCase { public function testVersionNotFound() { $userFolder = $this->createMock(Folder::class); $userRoot = $this->createMock(Folder::class); - $versions = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->userId) ->willReturn($userFolder); $userFolder->method('getParent') ->willReturn($userRoot); - $userRoot->method('get') - ->with('files_versions') - ->willReturn($versions); + + $sourceFile = $this->createMock(File::class); + $userFolder->method('get') + ->with('file') + ->willReturn($sourceFile); $this->mimeTypeDetector->method('detectPath') ->with($this->equalTo('file')) ->willReturn('myMime'); - $file = $this->createMock(File::class); - $versions->method('get') - ->with($this->equalTo('file.v42')) + $this->versionManager->method('getVersionFile') ->willThrowException(new NotFoundException()); $res = $this->controller->getPreview('file', 10, 10, '42'); diff --git a/apps/oauth2/lib/Controller/OauthApiController.php b/apps/oauth2/lib/Controller/OauthApiController.php index 2083741fa0c..73fed3654d5 100644 --- a/apps/oauth2/lib/Controller/OauthApiController.php +++ b/apps/oauth2/lib/Controller/OauthApiController.php @@ -22,8 +22,9 @@ namespace OCA\OAuth2\Controller; use OC\Authentication\Exceptions\InvalidTokenException; -use OC\Authentication\Token\ExpiredTokenException; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Token\IProvider as TokenProvider; +use OC\Security\Bruteforce\Throttler; use OCA\OAuth2\Db\AccessTokenMapper; use OCA\OAuth2\Db\ClientMapper; use OCA\OAuth2\Exceptions\AccessTokenNotFoundException; @@ -49,6 +50,8 @@ class OauthApiController extends Controller { private $secureRandom; /** @var ITimeFactory */ private $time; + /** @var Throttler */ + private $throttler; /** * @param string $appName @@ -59,6 +62,7 @@ class OauthApiController extends Controller { * @param TokenProvider $tokenProvider * @param ISecureRandom $secureRandom * @param ITimeFactory $time + * @param Throttler $throttler */ public function __construct($appName, IRequest $request, @@ -67,7 +71,8 @@ class OauthApiController extends Controller { ClientMapper $clientMapper, TokenProvider $tokenProvider, ISecureRandom $secureRandom, - ITimeFactory $time) { + ITimeFactory $time, + Throttler $throttler) { parent::__construct($appName, $request); $this->crypto = $crypto; $this->accessTokenMapper = $accessTokenMapper; @@ -75,6 +80,7 @@ class OauthApiController extends Controller { $this->tokenProvider = $tokenProvider; $this->secureRandom = $secureRandom; $this->time = $time; + $this->throttler = $throttler; } /** @@ -164,6 +170,8 @@ class OauthApiController extends Controller { $accessToken->setEncryptedToken($this->crypto->encrypt($newToken, $newCode)); $this->accessTokenMapper->update($accessToken); + $this->throttler->resetDelay($this->request->getRemoteAddress(), 'login', ['user' => $appToken->getUID()]); + return new JSONResponse( [ 'access_token' => $newToken, diff --git a/apps/oauth2/tests/Controller/OauthApiControllerTest.php b/apps/oauth2/tests/Controller/OauthApiControllerTest.php index 10748485971..f5a8138fa2d 100644 --- a/apps/oauth2/tests/Controller/OauthApiControllerTest.php +++ b/apps/oauth2/tests/Controller/OauthApiControllerTest.php @@ -22,11 +22,10 @@ namespace OCA\OAuth2\Tests\Controller; use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Token\DefaultToken; -use OC\Authentication\Token\DefaultTokenMapper; -use OC\Authentication\Token\ExpiredTokenException; use OC\Authentication\Token\IProvider as TokenProvider; -use OC\Authentication\Token\IToken; +use OC\Security\Bruteforce\Throttler; use OCA\OAuth2\Controller\OauthApiController; use OCA\OAuth2\Db\AccessToken; use OCA\OAuth2\Db\AccessTokenMapper; @@ -57,6 +56,8 @@ class OauthApiControllerTest extends TestCase { private $secureRandom; /** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */ private $time; + /** @var Throttler|\PHPUnit_Framework_MockObject_MockObject */ + private $throttler; /** @var OauthApiController */ private $oauthApiController; @@ -70,6 +71,7 @@ class OauthApiControllerTest extends TestCase { $this->tokenProvider = $this->createMock(TokenProvider::class); $this->secureRandom = $this->createMock(ISecureRandom::class); $this->time = $this->createMock(ITimeFactory::class); + $this->throttler = $this->createMock(Throttler::class); $this->oauthApiController = new OauthApiController( 'oauth2', @@ -79,7 +81,8 @@ class OauthApiControllerTest extends TestCase { $this->clientMapper, $this->tokenProvider, $this->secureRandom, - $this->time + $this->time, + $this->throttler ); } @@ -286,6 +289,17 @@ class OauthApiControllerTest extends TestCase { 'user_id' => 'userId', ]); + $this->request->method('getRemoteAddress') + ->willReturn('1.2.3.4'); + + $this->throttler->expects($this->once()) + ->method('resetDelay') + ->with( + '1.2.3.4', + 'login', + ['user' => 'userId'] + ); + $this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret')); } @@ -370,6 +384,17 @@ class OauthApiControllerTest extends TestCase { $this->request->server['PHP_AUTH_USER'] = 'clientId'; $this->request->server['PHP_AUTH_PW'] = 'clientSecret'; + $this->request->method('getRemoteAddress') + ->willReturn('1.2.3.4'); + + $this->throttler->expects($this->once()) + ->method('resetDelay') + ->with( + '1.2.3.4', + 'login', + ['user' => 'userId'] + ); + $this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', null, null)); } @@ -451,6 +476,17 @@ class OauthApiControllerTest extends TestCase { 'user_id' => 'userId', ]); + $this->request->method('getRemoteAddress') + ->willReturn('1.2.3.4'); + + $this->throttler->expects($this->once()) + ->method('resetDelay') + ->with( + '1.2.3.4', + 'login', + ['user' => 'userId'] + ); + $this->assertEquals($expected, $this->oauthApiController->getToken('refresh_token', null, 'validrefresh', 'clientId', 'clientSecret')); } } diff --git a/apps/sharebymail/tests/CapabilitiesTest.php b/apps/sharebymail/tests/CapabilitiesTest.php new file mode 100644 index 00000000000..b1545994199 --- /dev/null +++ b/apps/sharebymail/tests/CapabilitiesTest.php @@ -0,0 +1,51 @@ +<?php +/** + * @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\ShareByMail\Tests; + +use OCA\ShareByMail\Capabilities; +use Test\TestCase; + +class CapabilitiesTest extends TestCase { + /** @var Capabilities */ + private $capabilities; + + public function setUp() { + parent::setUp(); + + $this->capabilities = new Capabilities(); + } + + public function testGetCapabilities() { + $capabilities = [ + 'files_sharing' => + [ + 'sharebymail' => + [ + 'enabled' => true, + 'upload_files_drop' => ['enabled' => true], + 'password' => ['enabled' => true], + 'expire_date' => ['enabled' => true] + ] + ] + ]; + + $this->assertSame($capabilities, $this->capabilities->getCapabilities()); + } +} diff --git a/apps/systemtags/tests/Activity/SettingTest.php b/apps/systemtags/tests/Activity/SettingTest.php new file mode 100644 index 00000000000..40fcea750a6 --- /dev/null +++ b/apps/systemtags/tests/Activity/SettingTest.php @@ -0,0 +1,72 @@ +<?php +/** + * @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\SystemTags\Tests\Activity; + +use OCA\SystemTags\Activity\Setting; +use OCP\IL10N; +use Test\TestCase; + +class SettingTest extends TestCase { + /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ + private $l; + /** @var Setting */ + private $setting; + + public function setUp() { + parent::setUp(); + $this->l = $this->createMock(IL10N::class); + + $this->setting = new Setting($this->l); + } + + public function testGetIdentifier() { + $this->assertSame('systemtags', $this->setting->getIdentifier()); + } + + public function testGetName() { + $this->l + ->expects($this->once()) + ->method('t') + ->with('<strong>System tags</strong> for a file have been modified') + ->willReturn('<strong>System tags</strong> for a file have been modified'); + + $this->assertSame('<strong>System tags</strong> for a file have been modified', $this->setting->getName()); + } + + public function testGetPriority() { + $this->assertSame(50, $this->setting->getPriority()); + } + + public function testCanChangeStream() { + $this->assertSame(true, $this->setting->canChangeStream()); + } + + public function testIsDefaultEnabledStream() { + $this->assertSame(true, $this->setting->isDefaultEnabledStream()); + } + + public function testCanChangeMail() { + $this->assertSame(true, $this->setting->canChangeMail()); + } + + public function testIsDefaultEnabledMail() { + $this->assertSame(false, $this->setting->isDefaultEnabledMail()); + } +} diff --git a/apps/user_ldap/composer/composer/autoload_classmap.php b/apps/user_ldap/composer/composer/autoload_classmap.php index 98a1bbfa1b7..e25b7ee3126 100644 --- a/apps/user_ldap/composer/composer/autoload_classmap.php +++ b/apps/user_ldap/composer/composer/autoload_classmap.php @@ -56,7 +56,6 @@ return array( 'OCA\\User_LDAP\\Settings\\Section' => $baseDir . '/../lib/Settings/Section.php', 'OCA\\User_LDAP\\UserPluginManager' => $baseDir . '/../lib/UserPluginManager.php', 'OCA\\User_LDAP\\User\\DeletedUsersIndex' => $baseDir . '/../lib/User/DeletedUsersIndex.php', - 'OCA\\User_LDAP\\User\\IUserTools' => $baseDir . '/../lib/User/IUserTools.php', 'OCA\\User_LDAP\\User\\Manager' => $baseDir . '/../lib/User/Manager.php', 'OCA\\User_LDAP\\User\\OfflineUser' => $baseDir . '/../lib/User/OfflineUser.php', 'OCA\\User_LDAP\\User\\User' => $baseDir . '/../lib/User/User.php', diff --git a/apps/user_ldap/composer/composer/autoload_static.php b/apps/user_ldap/composer/composer/autoload_static.php index 83e49daf0f3..23819055be4 100644 --- a/apps/user_ldap/composer/composer/autoload_static.php +++ b/apps/user_ldap/composer/composer/autoload_static.php @@ -71,7 +71,6 @@ class ComposerStaticInitUser_LDAP 'OCA\\User_LDAP\\Settings\\Section' => __DIR__ . '/..' . '/../lib/Settings/Section.php', 'OCA\\User_LDAP\\UserPluginManager' => __DIR__ . '/..' . '/../lib/UserPluginManager.php', 'OCA\\User_LDAP\\User\\DeletedUsersIndex' => __DIR__ . '/..' . '/../lib/User/DeletedUsersIndex.php', - 'OCA\\User_LDAP\\User\\IUserTools' => __DIR__ . '/..' . '/../lib/User/IUserTools.php', 'OCA\\User_LDAP\\User\\Manager' => __DIR__ . '/..' . '/../lib/User/Manager.php', 'OCA\\User_LDAP\\User\\OfflineUser' => __DIR__ . '/..' . '/../lib/User/OfflineUser.php', 'OCA\\User_LDAP\\User\\User' => __DIR__ . '/..' . '/../lib/User/User.php', diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index d0d51ae8c85..fb2582e8266 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -46,7 +46,6 @@ namespace OCA\User_LDAP; use OC\HintException; use OC\Hooks\PublicEmitter; use OCA\User_LDAP\Exceptions\ConstraintViolationException; -use OCA\User_LDAP\User\IUserTools; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; use OCA\User_LDAP\Mapping\AbstractMapping; @@ -59,7 +58,7 @@ use OCP\IUserManager; * Class Access * @package OCA\User_LDAP */ -class Access extends LDAPUtility implements IUserTools { +class Access extends LDAPUtility { const UUID_ATTRIBUTES = ['entryuuid', 'nsuniqueid', 'objectguid', 'guid', 'ipauniqueid']; /** @var \OCA\User_LDAP\Connection */ diff --git a/apps/user_ldap/lib/User/IUserTools.php b/apps/user_ldap/lib/User/IUserTools.php deleted file mode 100644 index 4ba9cebb1a6..00000000000 --- a/apps/user_ldap/lib/User/IUserTools.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\User_LDAP\User; - -/** - * IUserTools - * - * defines methods that are required by User class for LDAP interaction - */ -interface IUserTools { - public function getConnection(); - - public function readAttribute($dn, $attr, $filter = 'objectClass=*'); - - public function stringResemblesDN($string); - - public function dn2username($dn, $ldapname = null); - - public function username2dn($name); -} diff --git a/apps/user_ldap/lib/User/Manager.php b/apps/user_ldap/lib/User/Manager.php index 9f2f3649777..13555f9e31b 100644 --- a/apps/user_ldap/lib/User/Manager.php +++ b/apps/user_ldap/lib/User/Manager.php @@ -45,7 +45,7 @@ use OCP\Notification\IManager as INotificationManager; * cache */ class Manager { - /** @var IUserTools */ + /** @var Access */ protected $access; /** @var IConfig */ @@ -110,11 +110,11 @@ class Manager { } /** - * @brief binds manager to an instance of IUserTools (implemented by - * Access). It needs to be assigned first before the manager can be used. - * @param IUserTools + * Binds manager to an instance of Access. + * It needs to be assigned first before the manager can be used. + * @param Access */ - public function setLdapAccess(IUserTools $access) { + public function setLdapAccess(Access $access) { $this->access = $access; } diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 02764a72eca..706424d3189 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -30,6 +30,7 @@ namespace OCA\User_LDAP\User; +use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\FilesystemHelper; use OCA\User_LDAP\LogWrapper; @@ -48,7 +49,7 @@ use OCP\Notification\IManager as INotificationManager; */ class User { /** - * @var IUserTools + * @var Access */ protected $access; /** @@ -110,8 +111,7 @@ class User { * @brief constructor, make sure the subclasses call this one! * @param string $username the internal username * @param string $dn the LDAP DN - * @param IUserTools $access an instance that implements IUserTools for - * LDAP interaction + * @param Access $access * @param IConfig $config * @param FilesystemHelper $fs * @param Image $image any empty instance @@ -120,7 +120,7 @@ class User { * @param IUserManager $userManager * @param INotificationManager $notificationManager */ - public function __construct($username, $dn, IUserTools $access, + public function __construct($username, $dn, Access $access, IConfig $config, FilesystemHelper $fs, Image $image, LogWrapper $log, IAvatarManager $avatarManager, IUserManager $userManager, INotificationManager $notificationManager) { @@ -414,14 +414,23 @@ class User { * * @param string $displayName * @param string $displayName2 - * @returns string the effective display name + * @return string the effective display name */ public function composeAndStoreDisplayName($displayName, $displayName2 = '') { $displayName2 = (string)$displayName2; if($displayName2 !== '') { $displayName .= ' (' . $displayName2 . ')'; } - $this->store('displayName', $displayName); + $oldName = $this->config->getUserValue($this->uid, 'user_ldap', 'displayName', null); + if ($oldName !== $displayName) { + $this->store('displayName', $displayName); + $user = $this->userManager->get($this->getUsername()); + if (!empty($oldName) && $user instanceof \OC\User\User) { + // if it was empty, it would be a new record, not a change emitting the trigger could + // potentially cause a UniqueConstraintViolationException, depending on some factors. + $user->triggerChange('displayName', $displayName); + } + } return $displayName; } diff --git a/apps/user_ldap/tests/User/ManagerTest.php b/apps/user_ldap/tests/User/ManagerTest.php index 104a70ff700..5c111abdc4e 100644 --- a/apps/user_ldap/tests/User/ManagerTest.php +++ b/apps/user_ldap/tests/User/ManagerTest.php @@ -28,11 +28,13 @@ namespace OCA\User_LDAP\Tests\User; +use OCA\User_LDAP\Access; +use OCA\User_LDAP\Connection; use OCA\User_LDAP\FilesystemHelper; use OCA\User_LDAP\ILDAPWrapper; use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\IUserTools; use OCA\User_LDAP\User\Manager; +use OCA\User_LDAP\User\User; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; @@ -48,200 +50,181 @@ use OCP\Notification\IManager as INotificationManager; * @package OCA\User_LDAP\Tests\User */ class ManagerTest extends \Test\TestCase { + /** @var Access|\PHPUnit_Framework_MockObject_MockObject */ + protected $access; - private function getTestInstances() { - $access = $this->createMock(IUserTools::class); - $config = $this->createMock(IConfig::class); - $filesys = $this->createMock(FilesystemHelper::class); - $log = $this->createMock(LogWrapper::class); - $avaMgr = $this->createMock(IAvatarManager::class); - $image = $this->createMock(Image::class); - $dbc = $this->createMock(IDBConnection::class); - $userMgr = $this->createMock(IUserManager::class); - $notiMgr = $this->createMock(INotificationManager::class); - - $connection = new \OCA\User_LDAP\Connection( - $lw = $this->createMock(ILDAPWrapper::class), - '', - null - ); + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $config; - $access->expects($this->any()) - ->method('getConnection') - ->will($this->returnValue($connection)); + /** @var FilesystemHelper|\PHPUnit_Framework_MockObject_MockObject */ + protected $fileSystemHelper; - return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr); - } + /** @var LogWrapper|\PHPUnit_Framework_MockObject_MockObject */ + protected $log; - public function testGetByDNExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + /** @var IAvatarManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $avatarManager; - $inputDN = 'cn=foo,dc=foobar,dc=bar'; - $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; + /** @var Image|\PHPUnit_Framework_MockObject_MockObject */ + protected $image; - $access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue(true)); + /** @var IDBConnection|\PHPUnit_Framework_MockObject_MockObject */ + protected $dbc; - $access->expects($this->once()) - ->method('dn2username') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue($uid)); + /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $ncUserManager; - $access->expects($this->never()) - ->method('username2dn'); + /** @var INotificationManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $notificationManager; - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); + /** @var ILDAPWrapper|\PHPUnit_Framework_MockObject_MockObject */ + protected $ldapWrapper; - // Now we fetch the user again. If this leads to a failing test, - // runtime caching the manager is broken. - $user = $manager->get($inputDN); - - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); - } + /** @var Connection */ + protected $connection; - public function testGetByEDirectoryDN() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + /** @var Manager */ + protected $manager; - $inputDN = 'uid=foo,o=foobar,c=bar'; - $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; + public function setUp() { + parent::setUp(); - $access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue(true)); - - $access->expects($this->once()) - ->method('dn2username') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue($uid)); + $this->access = $this->createMock(Access::class); + $this->config = $this->createMock(IConfig::class); + $this->fileSystemHelper = $this->createMock(FilesystemHelper::class); + $this->log = $this->createMock(LogWrapper::class); + $this->avatarManager = $this->createMock(IAvatarManager::class); + $this->image = $this->createMock(Image::class); + $this->dbc = $this->createMock(IDBConnection::class); + $this->ncUserManager = $this->createMock(IUserManager::class); + $this->notificationManager = $this->createMock(INotificationManager::class); - $access->expects($this->never()) - ->method('username2dn'); + $this->ldapWrapper = $this->createMock(ILDAPWrapper::class); + $this->connection = new Connection($this->ldapWrapper, '', null); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); + $this->access->expects($this->any()) + ->method('getConnection') + ->will($this->returnValue($this->connection)); + + /** @noinspection PhpUnhandledExceptionInspection */ + $this->manager = new Manager( + $this->config, + $this->fileSystemHelper, + $this->log, + $this->avatarManager, + $this->image, + $this->dbc, + $this->ncUserManager, + $this->notificationManager + ); - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); + $this->manager->setLdapAccess($this->access); } - public function testGetByExoticDN() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + public function dnProvider() { + return [ + ['cn=foo,dc=foobar,dc=bar'], + ['uid=foo,o=foobar,c=bar'], + ['ab=cde,f=ghei,mno=pq'], + ]; + } - $inputDN = 'ab=cde,f=ghei,mno=pq'; + /** + * @dataProvider dnProvider + */ + public function testGetByDNExisting(string $inputDN) { $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('stringResemblesDN') ->with($this->equalTo($inputDN)) ->will($this->returnValue(true)); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2username') ->with($this->equalTo($inputDN)) ->will($this->returnValue($uid)); - - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('username2dn'); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->manager->get($inputDN); - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); + // Now we fetch the user again. If this leads to a failing test, + // runtime caching the manager is broken. + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($inputDN); + + $this->assertInstanceOf(User::class, $user); } public function testGetByDNNotExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - $inputDN = 'cn=gone,dc=foobar,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('stringResemblesDN') ->with($this->equalTo($inputDN)) ->will($this->returnValue(true)); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2username') ->with($this->equalTo($inputDN)) ->will($this->returnValue(false)); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->with($this->equalTo($inputDN)) ->will($this->returnValue(false)); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($inputDN); $this->assertNull($user); } public function testGetByUidExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - $dn = 'cn=foo,dc=foobar,dc=bar'; $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2username'); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->with($this->equalTo($uid)) ->will($this->returnValue($dn)); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('stringResemblesDN') ->with($this->equalTo($uid)) ->will($this->returnValue(false)); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($uid); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->manager->get($uid); // Now we fetch the user again. If this leads to a failing test, // runtime caching the manager is broken. - $user = $manager->get($uid); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($uid); - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); + $this->assertInstanceOf(User::class, $user); } public function testGetByUidNotExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - $uid = 'gone'; - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2username'); - - $access->expects($this->exactly(1)) + $this->access->expects($this->exactly(1)) ->method('username2dn') ->with($this->equalTo($uid)) ->will($this->returnValue(false)); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($uid); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($uid); $this->assertNull($user); } public function attributeRequestProvider() { return [ - [ false ], - [ true ], + [false], + [true], ]; } @@ -249,23 +232,16 @@ class ManagerTest extends \Test\TestCase { * @dataProvider attributeRequestProvider */ public function testGetAttributes($minimal) { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - - $connection = $access->getConnection(); - $connection->setConfiguration([ + $this->connection->setConfiguration([ 'ldapEmailAttribute' => 'mail', 'ldapUserAvatarRule' => 'default', 'ldapQuotaAttribute' => '', ]); - $attributes = $manager->getAttributes($minimal); + $attributes = $this->manager->getAttributes($minimal); $this->assertTrue(in_array('dn', $attributes)); - $this->assertTrue(in_array($access->getConnection()->ldapEmailAttribute, $attributes)); + $this->assertTrue(in_array($this->access->getConnection()->ldapEmailAttribute, $attributes)); $this->assertFalse(in_array('', $attributes)); $this->assertSame(!$minimal, in_array('jpegphoto', $attributes)); $this->assertSame(!$minimal, in_array('thumbnailphoto', $attributes)); diff --git a/apps/user_ldap/tests/User/UserTest.php b/apps/user_ldap/tests/User/UserTest.php index 837c72a3a31..6ff9defe47b 100644 --- a/apps/user_ldap/tests/User/UserTest.php +++ b/apps/user_ldap/tests/User/UserTest.php @@ -998,23 +998,58 @@ class UserTest extends \Test\TestCase { public function displayNameProvider() { return [ - ['Roland Deschain', '', 'Roland Deschain'], - ['Roland Deschain', null, 'Roland Deschain'], - ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)'], + ['Roland Deschain', '', 'Roland Deschain', false], + ['Roland Deschain', '', 'Roland Deschain', true], + ['Roland Deschain', null, 'Roland Deschain', false], + ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', false], + ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', true], ]; } /** * @dataProvider displayNameProvider */ - public function testComposeAndStoreDisplayName($part1, $part2, $expected) { + public function testComposeAndStoreDisplayName($part1, $part2, $expected, $expectTriggerChange) { $this->config->expects($this->once()) ->method('setUserValue'); + $oldName = $expectTriggerChange ? 'xxGunslingerxx' : null; + $this->config->expects($this->once()) + ->method('getUserValue') + ->with($this->user->getUsername(), 'user_ldap', 'displayName', null) + ->willReturn($oldName); + + $ncUserObj = $this->createMock(\OC\User\User::class); + if ($expectTriggerChange) { + $ncUserObj->expects($this->once()) + ->method('triggerChange') + ->with('displayName', $expected); + } else { + $ncUserObj->expects($this->never()) + ->method('triggerChange'); + } + $this->userManager->expects($this->once()) + ->method('get') + ->willReturn($ncUserObj); $displayName = $this->user->composeAndStoreDisplayName($part1, $part2); $this->assertSame($expected, $displayName); } + public function testComposeAndStoreDisplayNameNoOverwrite() { + $displayName = 'Randall Flagg'; + $this->config->expects($this->never()) + ->method('setUserValue'); + $this->config->expects($this->once()) + ->method('getUserValue') + ->willReturn($displayName); + + $this->userManager->expects($this->never()) + ->method('get'); // Implicit: no triggerChange can be called + + $composedDisplayName = $this->user->composeAndStoreDisplayName($displayName); + $this->assertSame($composedDisplayName, $displayName); + } + public function testHandlePasswordExpiryWarningDefaultPolicy() { $this->connection->expects($this->any()) ->method('__get') diff --git a/build/compile-handlebars-templates.sh b/build/compile-handlebars-templates.sh index 65ad4da12cf..b73b7d8f460 100755 --- a/build/compile-handlebars-templates.sh +++ b/build/compile-handlebars-templates.sh @@ -32,7 +32,7 @@ handlebars -n OCA.WorkflowEngine.Templates apps/workflowengine/js/templates -f a handlebars -n OCA.Sharing.Templates apps/files_sharing/js/templates -f apps/files_sharing/js/templates.js # Files external -handlebars -n OCA.External.Templates apps/files_external/js/templates -f apps/files_external/js/templates.js +handlebars -n OCA.Files_External.Templates apps/files_external/js/templates -f apps/files_external/js/templates.js if [[ $(git diff --name-only) ]]; then echo "Please submit your compiled handlebars templates" diff --git a/config/config.sample.php b/config/config.sample.php index 9a5648c95df..902bfa6e44d 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1499,11 +1499,26 @@ $CONFIG = array( /** * List of trusted proxy servers * - * If you configure these also consider setting `forwarded_for_headers` which - * otherwise defaults to `HTTP_X_FORWARDED_FOR` (the `X-Forwarded-For` header). + * You may set this to an array containing a combination of + * - IPv4 addresses, e.g. `192.168.2.123` + * - IPv4 ranges in CIDR notation, e.g. `192.168.2.0/24` + * - IPv6 addresses, e.g. `fd9e:21a7:a92c:2323::1` + * + * _(CIDR notation for IPv6 is currently work in progress and thus not + * available as of yet)_ + * + * When an incoming request's `REMOTE_ADDR` matches any of the IP addresses + * specified here, it is assumed to be a proxy instead of a client. Thus, the + * client IP will be read from the HTTP header specified in + * `forwarded_for_headers` instead of from `REMOTE_ADDR`. + * + * So if you configure `trusted_proxies`, also consider setting + * `forwarded_for_headers` which otherwise defaults to `HTTP_X_FORWARDED_FOR` + * (the `X-Forwarded-For` header). + * * Defaults to an empty array. */ -'trusted_proxies' => array('203.0.113.45', '198.51.100.128'), +'trusted_proxies' => array('203.0.113.45', '198.51.100.128', '192.168.2.0/24'), /** * Headers that should be trusted as client IP address in combination with @@ -1648,4 +1663,14 @@ $CONFIG = array( * If this is set to "false" it will not show the link. */ 'simpleSignUpLink.shown' => true, + +/** + * By default autocompletion is enabled for the login form on Nextcloud's login page. + * While this is enabled, browsers are allowed to "remember" login names and such. + * Some companies require it to be disabled to comply with their security policy. + * + * Simply set this property to "false", if you want to turn this feature off. + */ + +'login_form_autocomplete' => true, ); diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php index a9fb22f21b7..d34f243f15f 100644 --- a/core/Controller/LoginController.php +++ b/core/Controller/LoginController.php @@ -171,6 +171,14 @@ class LoginController extends Controller { $parameters['loginName'] = ''; $parameters['user_autofocus'] = true; } + + $autocomplete = $this->config->getSystemValue('login_form_autocomplete', true); + if ($autocomplete){ + $parameters['login_form_autocomplete'] = 'on'; + } else { + $parameters['login_form_autocomplete'] = 'off'; + } + if (!empty($redirect_url)) { $parameters['redirect_url'] = $redirect_url; } diff --git a/core/Migrations/Version15000Date20181015062942.php b/core/Migrations/Version15000Date20181015062942.php new file mode 100644 index 00000000000..e73b663d2fd --- /dev/null +++ b/core/Migrations/Version15000Date20181015062942.php @@ -0,0 +1,54 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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\Migrations; + +use Closure; +use Doctrine\DBAL\Types\Type; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +class Version15000Date20181015062942 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('share'); + $table->addColumn('hide_download', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + + return $schema; + } +} diff --git a/core/css/apps.scss b/core/css/apps.scss index 8b94d08ce2e..54372afa45a 100644 --- a/core/css/apps.scss +++ b/core/css/apps.scss @@ -781,27 +781,47 @@ kbd { /* TABS ------------------------------------------------------------ */ .tabHeaders { - display: inline-block; - margin: 15px; + display: flex; + margin-bottom: 16px; + .tabHeader { - float: left; - padding: 12px; + display: flex; + flex-direction: column; + flex-grow: 1; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; cursor: pointer; color: var(--color-text-lighter); margin-bottom: 1px; + padding: 5px; + + /* Use same amount as sidebar padding */ + &:first-child { + padding-left: 15px; + } + &:last-child { + padding-right: 15px; + } + .icon { display: inline-block; - width: 16px; + width: 100%; height: 16px; background-size: 16px; vertical-align: middle; margin-top: -2px; margin-right: 3px; opacity: .7; + cursor: pointer; } + a { color: var(--color-text-lighter); margin-bottom: 1px; + overflow: hidden; + text-overflow: ellipsis; } &.selected { font-weight: bold; diff --git a/core/css/css-variables.scss b/core/css/css-variables.scss index a2946672294..6df2e0a3428 100644 --- a/core/css/css-variables.scss +++ b/core/css/css-variables.scss @@ -39,4 +39,6 @@ --border-radius-pill: $border-radius-pill; --font-face: $font-face; + + --animation-quick: $animation-quick; } diff --git a/core/css/global.scss b/core/css/global.scss index 9511d4324fa..06dc3688a2b 100644 --- a/core/css/global.scss +++ b/core/css/global.scss @@ -25,12 +25,12 @@ } .hidden { - display: none; + display: none !important; /* Hiding should take precedence */ } .hidden-visually { position: absolute; - left:-10000px; + left: -10000px; top: auto; width: 1px; height: 1px; @@ -47,4 +47,4 @@ .inlineblock { display: inline-block; -}
\ No newline at end of file +} diff --git a/core/css/header.scss b/core/css/header.scss index f2527ca3a79..879734097ae 100644 --- a/core/css/header.scss +++ b/core/css/header.scss @@ -513,25 +513,90 @@ nav[role='navigation'] { height: 20px; } - /* app title popup */ + /* App title */ li span { - display: none; + opacity: 0; position: absolute; - overflow: visible; - background-color: var(--color-main-background); - white-space: nowrap; - border: none; - border-radius: var(--border-radius); - border-top-left-radius: 0; - border-top-right-radius: 0; - color: var(--color-text-lighter); - width: auto; - left: 50%; - top: 100%; - transform: translateX(-50%); - padding: 4px 10px; - filter: drop-shadow(0 1px 10px var(--color-box-shadow)); - z-index: 100; + color: var(--color-primary-text); + bottom: -5px; + width: 100%; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + } + + + /* Set up transitions for showing app titles on hover */ + li { + /* Prevent flicker effect because of low-hanging span element */ + overflow-y: hidden; + + /* App icon */ + svg, + .icon-more-white { + transition: transform var(--animation-quick) ease; + } + + /* App title */ + span { + transition: all var(--animation-quick) ease; + } + + /* Triangle */ + a::before { + transition: border var(--animation-quick) ease; + } + } + + /* Show all app titles on hovering app menu area */ + &:hover { + li { + /* Move up app icon */ + svg, + .icon-more-white { + transform: translateY(-7px); + } + + /* Show app title */ + span { + opacity: .6; + bottom: 2px; + z-index: -1; /* fix clickability issue - otherwise we need to move the span into the link */ + } + + /* Prominent app title for current and hovered/focused app */ + &:hover span, + &:focus span, + .active + span { + opacity: 1; + } + + /* Smaller triangle because of limited space */ + a::before { + border-width: 5px; + } + } + } + + /* Also show app title on focusing single entry (showing all on focus is only possible with CSS4 and parent selectors) */ + li a:focus { + /* Move up app icon */ + svg, + .icon-more-white, { + transform: translateY(-7px); + } + + /* Show app title */ + & + span, + span { + opacity: 1; + bottom: 2px; + } + + /* Smaller triangle because of limited space */ + &::before { + border-width: 5px; + } } /* show triangle below active app */ @@ -549,6 +614,7 @@ nav[role='navigation'] { bottom: 0; display: none; } + /* triangle focus feedback */ li a.active::before, li:hover a::before, @@ -560,7 +626,6 @@ nav[role='navigation'] { z-index: 99; } li:hover a::before, - li:hover a::before, li a.active:hover::before, li a:focus::before { z-index: 101; diff --git a/core/css/icons.scss b/core/css/icons.scss index 5b96d1223a7..99b1dc9c215 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/inputs.scss b/core/css/inputs.scss index 2611e1bb2f4..7d30f0386c9 100644 --- a/core/css/inputs.scss +++ b/core/css/inputs.scss @@ -163,6 +163,7 @@ input[type='reset'] { padding: 6px 12px; width: auto; min-height: 34px; + display: inline-block; cursor: pointer; box-sizing: border-box; background-color: var(--color-background-dark); diff --git a/core/css/jquery-ui-fixes.scss b/core/css/jquery-ui-fixes.scss index e30beee44e5..eab22e70d62 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/css/styles.scss b/core/css/styles.scss index 4b80b4f9626..f23f4c2dead 100644 --- a/core/css/styles.scss +++ b/core/css/styles.scss @@ -798,7 +798,7 @@ code { &.view-grid { $grid-size: 120px; $grid-pad: 10px; - $name-height: 20px; + $name-height: 30px; display: flex; flex-direction: column; @@ -818,20 +818,22 @@ code { flex-direction: column; width: $grid-size - 2 * $grid-pad; + td { border: none; padding: 0; + text-align: center; + border-radius: var(--border-radius); &.filename { padding: #{$grid-size - 2 * $grid-pad} 0 0 0; background-position: center top; background-size: contain; line-height: $name-height; - height: $name-height; } &.filesize { - line-height: $name-height; - text-align: left; + line-height: $name-height / 3; + width: 100%; } &.date { display: none; diff --git a/core/css/variables.scss b/core/css/variables.scss index dffd6403471..a827629479c 100644 --- a/core/css/variables.scss +++ b/core/css/variables.scss @@ -80,6 +80,7 @@ $border-radius-pill: 100px !default; $font-face: 'Nunito', 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif !default; +$animation-quick: 100ms; // various structure data $header-height: 50px; diff --git a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars index 412ed8efca0..baee3aa6630 100644 --- a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars +++ b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars @@ -11,6 +11,16 @@ <input id="linkText-{{cid}}" class="linkText" type="text" readonly="readonly" value="{{shareLinkURL}}" /> </span> </li> + {{#if showHideDownloadCheckbox}} + <li> + <span class="shareOption menuitem"> + <span class="icon-loading-small hidden"></span> + <input type="checkbox" name="hideDownload" id="sharingDialogHideDownload-{{cid}}" class="checkbox hideDownloadCheckbox" + {{#if hideDownload}}checked="checked"{{/if}} /> + <label for="sharingDialogHideDownload-{{cid}}">{{hideDownloadLabel}}</label> + </span> + </li> + {{/if}} {{#if publicUpload}} <li> <span class="shareOption menuitem"> diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js index aac4843c8e0..7603b058a96 100644 --- a/core/js/sharedialoglinkshareview.js +++ b/core/js/sharedialoglinkshareview.js @@ -47,6 +47,8 @@ 'change .linkCheckbox': 'onLinkCheckBoxChange', // open menu 'click .share-menu .icon-more': 'onToggleMenu', + // hide download + 'change .hideDownloadCheckbox': 'onHideDownloadChange', // password 'focusout input.linkPassText': 'onPasswordEntered', 'keyup input.linkPassText': 'onPasswordKeyUp', @@ -179,6 +181,20 @@ $el.select(); }, + onHideDownloadChange: function() { + var $checkbox = this.$('.hideDownloadCheckbox'); + $checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock'); + + var hideDownload = false; + if($checkbox.is(':checked')) { + hideDownload = true; + } + + this.model.saveLinkShare({ + hideDownload: hideDownload + }); + }, + onShowPasswordClick: function() { this.$el.find('.linkPass').slideToggle(OC.menuSpeed); this.$el.find('.linkPassMenu').toggleClass('hidden'); @@ -401,6 +417,9 @@ var passwordPlaceholderInitial = this.configModel.get('enforcePasswordForPublicLink') ? PASSWORD_PLACEHOLDER_MESSAGE : PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL; + var showHideDownloadCheckbox = !this.model.isFolder(); + var hideDownload = this.model.get('linkShare').hideDownload; + var publicEditable = !this.model.isFolder() && isLinkShare @@ -464,6 +483,9 @@ shareLinkURL: this.model.get('linkShare').link, urlLabel: t('core', 'Link'), + showHideDownloadCheckbox: showHideDownloadCheckbox, + hideDownload: hideDownload, + hideDownloadLabel: t('core', 'Hide download'), enablePasswordLabel: t('core', 'Password protect'), passwordLabel: t('core', 'Password'), passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE, diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index 93373a54435..94abf55a358 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -314,7 +314,9 @@ var $edit = _this.$('#canEdit-' + _this.cid + '-' + sharee.shareId); if($edit.length === 1) { $edit.prop('checked', sharee.editPermissionState === 'checked'); - $edit.prop('indeterminate', sharee.editPermissionState === 'indeterminate'); + if (sharee.isFolder) { + $edit.prop('indeterminate', sharee.editPermissionState === 'indeterminate'); + } } }); this.$('.popovermenu').on('afterHide', function() { diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 9c648357e61..082bf9571d7 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 = $("<div class='share-autocomplete-item'/>"); - var avatar = $("<div class='avatardiv'></div>").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 = $("<div class='avatardiv'></div>").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'); } $("<div class='autocomplete-item-text'></div>") - .text(text) + .html( + text.replace( + new RegExp(this.term, "gi"), + "<span class='ui-state-highlight'>$&</span>") + + '<span class="autocomplete-item-details">' + description + '</span>' + ) .appendTo(insert); insert.attr('title', item.value.shareWith); + insert.append('<span class="icon '+icon+'" title="' + text + '"></span>'); insert = $("<a>") .append(insert); return $("<li>") @@ -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/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index f4a3caf1370..84715ec87c1 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -18,6 +18,7 @@ * @typedef {object} OC.Share.Types.LinkShareInfo * @property {bool} isLinkShare * @property {string} token + * @property {bool} hideDownload * @property {string|null} password * @property {string} link * @property {number} permissions @@ -136,6 +137,7 @@ call = this.updateShare(shareId, attributes, options); } else { attributes = _.defaults(attributes, { + hideDownload: false, password: '', passwordChanged: false, permissions: OC.PERMISSION_READ, @@ -614,6 +616,12 @@ var hcp = this.hasCreatePermission(shareIndex); var hup = this.hasUpdatePermission(shareIndex); var hdp = this.hasDeletePermission(shareIndex); + if (this.isFile()) { + if (hcp || hup || hdp) { + return 'checked'; + } + return ''; + } if (!hcp && !hup && !hdp) { return ''; } @@ -866,6 +874,9 @@ isLinkShare: true, id: share.id, token: share.token, + // hide_download is returned as an int, so force it + // to a boolean + hideDownload: !!share.hide_download, password: share.share_with, link: link, permissions: share.permissions, diff --git a/core/js/sharetemplates.js b/core/js/sharetemplates.js index efdd3ff6606..0c1fee37455 100644 --- a/core/js/sharetemplates.js +++ b/core/js/sharetemplates.js @@ -61,6 +61,20 @@ templates['sharedialoglinkshareview'] = template({"1":function(container,depth0, templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + return " <li>\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"checkbox\" name=\"hideDownload\" id=\"sharingDialogHideDownload-" + + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + + "\" class=\"checkbox hideDownloadCheckbox\"\n " + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hideDownload : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " />\n <label for=\"sharingDialogHideDownload-" + + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + + "\">" + + alias4(((helper = (helper = helpers.hideDownloadLabel || (depth0 != null ? depth0.hideDownloadLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"hideDownloadLabel","hash":{},"data":data}) : helper))) + + "</label>\n </span>\n </li>\n"; +},"2":function(container,depth0,helpers,partials,data) { + return "checked=\"checked\""; +},"4":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + return " <li>\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"radio\" name=\"publicUpload\" value=\"" + alias4(((helper = (helper = helpers.publicUploadRValue || (depth0 != null ? depth0.publicUploadRValue : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicUploadRValue","hash":{},"data":data}) : helper))) + "\" id=\"sharingDialogAllowPublicUpload-r-" @@ -92,7 +106,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\">" + alias4(((helper = (helper = helpers.publicUploadWLabel || (depth0 != null ? depth0.publicUploadWLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicUploadWLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n"; -},"3":function(container,depth0,helpers,partials,data) { +},"6":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li id=\"allowPublicEditingWrapper\">\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"checkbox\" name=\"allowPublicEditing\" id=\"sharingDialogAllowPublicEditing-" @@ -104,41 +118,39 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\">" + alias4(((helper = (helper = helpers.publicEditingLabel || (depth0 != null ? depth0.publicEditingLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicEditingLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n"; -},"5":function(container,depth0,helpers,partials,data) { +},"8":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li>\n <span class=\"shareOption menuitem\">\n <input type=\"checkbox\" name=\"showPassword\" id=\"showPassword-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\" class=\"checkbox showPasswordCheckbox\"\n " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordEnforced : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordEnforced : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " value=\"1\" />\n <label for=\"showPassword-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\">" + alias4(((helper = (helper = helpers.enablePasswordLabel || (depth0 != null ? depth0.enablePasswordLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"enablePasswordLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n <li class=\"" - + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"unless","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " linkPassMenu\">\n <span class=\"shareOption menuitem icon-share-pass\">\n <input id=\"linkPassText-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\" class=\"linkPassText\" type=\"password\" placeholder=\"" + alias4(((helper = (helper = helpers.passwordPlaceholder || (depth0 != null ? depth0.passwordPlaceholder : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"passwordPlaceholder","hash":{},"data":data}) : helper))) + "\" autocomplete=\"new-password\" />\n <span class=\"icon icon-loading-small hidden\"></span>\n </span>\n </li>\n"; -},"6":function(container,depth0,helpers,partials,data) { - return "checked=\"checked\""; -},"8":function(container,depth0,helpers,partials,data) { +},"9":function(container,depth0,helpers,partials,data) { return "disabled=\"disabled\""; -},"10":function(container,depth0,helpers,partials,data) { +},"11":function(container,depth0,helpers,partials,data) { return "hidden"; -},"12":function(container,depth0,helpers,partials,data) { +},"13":function(container,depth0,helpers,partials,data) { var helper; return container.escapeExpression(((helper = (helper = helpers.expireDate || (depth0 != null ? depth0.expireDate : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"expireDate","hash":{},"data":data}) : helper))); -},"14":function(container,depth0,helpers,partials,data) { +},"15":function(container,depth0,helpers,partials,data) { var helper; return container.escapeExpression(((helper = (helper = helpers.defaultExpireDate || (depth0 != null ? depth0.defaultExpireDate : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"defaultExpireDate","hash":{},"data":data}) : helper))); -},"16":function(container,depth0,helpers,partials,data) { +},"17":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li>\n <a href=\"#\" class=\"shareOption menuitem pop-up\" data-url=\"" @@ -162,21 +174,22 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\" class=\"linkText\" type=\"text\" readonly=\"readonly\" value=\"" + alias4(((helper = (helper = helpers.shareLinkURL || (depth0 != null ? depth0.shareLinkURL : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareLinkURL","hash":{},"data":data}) : helper))) + "\" />\n </span>\n </li>\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicUpload : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicEditing : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPasswordCheckBox : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showHideDownloadCheckbox : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicUpload : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicEditing : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPasswordCheckBox : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " <li>\n <span class=\"shareOption menuitem\">\n <input id=\"expireDate-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\" type=\"checkbox\" name=\"expirationDate\" class=\"expireDate checkbox\"\n " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isExpirationEnforced : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isExpirationEnforced : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\" />\n <label for=\"expireDate-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\">" + alias4(((helper = (helper = helpers.expireDateLabel || (depth0 != null ? depth0.expireDateLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"expireDateLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n <li class=\"" - + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"unless","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\">\n <span class=\"menuitem icon-expiredate expirationDateContainer-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\">\n <label for=\"expirationDatePicker-" @@ -190,7 +203,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\" class=\"datepicker\" type=\"text\" placeholder=\"" + alias4(((helper = (helper = helpers.expirationDatePlaceholder || (depth0 != null ? depth0.expirationDatePlaceholder : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"expirationDatePlaceholder","hash":{},"data":data}) : helper))) + "\" value=\"" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.program(14, data, 0),"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(13, data, 0),"inverse":container.program(15, data, 0),"data":data})) != null ? stack1 : "") + "\" />\n </span>\n </li>\n <li>\n <a href=\"#\" class=\"share-add\">\n <span class=\"icon-loading-small hidden\"></span>\n <span class=\"icon icon-edit\"></span>\n <span>" + alias4(((helper = (helper = helpers.addNoteLabel || (depth0 != null ? depth0.addNoteLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"addNoteLabel","hash":{},"data":data}) : helper))) + "</span>\n <input type=\"button\" class=\"share-note-delete icon-delete\">\n </a>\n </li>\n <li class=\"share-note-form share-note-link hidden\">\n <span class=\"menuitem icon-note\">\n <textarea class=\"share-note\">" @@ -198,7 +211,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "</textarea>\n <input type=\"submit\" class=\"icon-confirm share-note-submit\" value=\"\" id=\"add-note-" + alias4(((helper = (helper = helpers.shareId || (depth0 != null ? depth0.shareId : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareId","hash":{},"data":data}) : helper))) + "\" />\n </span>\n </li>\n" - + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " </ul>\n</div>\n"; },"useData":true}); templates['sharedialoglinkshareview_popover_menu_pending'] = template({"1":function(container,depth0,helpers,partials,data) { diff --git a/core/js/tests/specs/sharedialoglinkshareview.js b/core/js/tests/specs/sharedialoglinkshareview.js index 9d07dcb479d..d8dec3968e3 100644 --- a/core/js/tests/specs/sharedialoglinkshareview.js +++ b/core/js/tests/specs/sharedialoglinkshareview.js @@ -72,6 +72,100 @@ describe('OC.Share.ShareDialogLinkShareView', function () { configModel.isShareWithLinkAllowed.restore(); }); + describe('hide download', function () { + + var $hideDownloadCheckbox; + var $workingIcon; + + beforeEach(function () { + // Needed to render the view + configModel.isShareWithLinkAllowed.returns(true); + + // Setting the share also triggers the rendering + shareModel.set({ + linkShare: { + isLinkShare: true, + } + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + $workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small'); + + sinon.stub(shareModel, 'saveLinkShare'); + + expect($workingIcon.hasClass('hidden')).toBeTruthy(); + }); + + afterEach(function () { + shareModel.saveLinkShare.restore(); + }); + + it('is shown if the share is a file', function() { + expect($hideDownloadCheckbox.length).toBeTruthy(); + }); + + it('is not shown if the share is a folder', function() { + shareModel.fileInfoModel.set('mimetype', 'httpd/unix-directory'); + + // Setting the item type also triggers the rendering + shareModel.set({ + itemType: 'folder' + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + + expect($hideDownloadCheckbox.length).toBeFalsy(); + }); + + it('checkbox is checked when the setting is enabled', function () { + shareModel.set({ + linkShare: { + isLinkShare: true, + hideDownload: true + } + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + + expect($hideDownloadCheckbox.is(':checked')).toEqual(true); + }); + + it('checkbox is not checked when the setting is disabled', function () { + expect($hideDownloadCheckbox.is(':checked')).toEqual(false); + }); + + it('enables the setting if clicked when unchecked', function () { + // Simulate the click by checking the checkbox and then triggering + // the "change" event. + $hideDownloadCheckbox.prop('checked', true); + $hideDownloadCheckbox.change(); + + expect($workingIcon.hasClass('hidden')).toBeFalsy(); + expect(shareModel.saveLinkShare.withArgs({ hideDownload: true }).calledOnce).toBeTruthy(); + }); + + it('disables the setting if clicked when checked', function () { + shareModel.set({ + linkShare: { + isLinkShare: true, + hideDownload: true + } + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + $workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small'); + + // Simulate the click by unchecking the checkbox and then triggering + // the "change" event. + $hideDownloadCheckbox.prop('checked', false); + $hideDownloadCheckbox.change(); + + expect($workingIcon.hasClass('hidden')).toBeFalsy(); + expect(shareModel.saveLinkShare.withArgs({ hideDownload: false }).calledOnce).toBeTruthy(); + }); + + }); + describe('onPasswordEntered', function () { var $passwordText; diff --git a/core/js/tests/specs/sharedialogshareelistview.js b/core/js/tests/specs/sharedialogshareelistview.js index 8e34225d199..e51fc2df72d 100644 --- a/core/js/tests/specs/sharedialogshareelistview.js +++ b/core/js/tests/specs/sharedialogshareelistview.js @@ -90,6 +90,37 @@ describe('OC.Share.ShareDialogShareeListView', function () { }); describe('Sets correct initial checkbox state', function () { + + it('marks edit box as unchecked for file shares without edit permissions', function () { + shareModel.set('shares', [{ + id: 100, + item_source: 123, + permissions: 1, + share_type: OC.Share.SHARE_TYPE_USER, + share_with: 'user1', + share_with_displayname: 'User One', + uid_owner: oc_current_user, + itemType: 'file' + }]); + listView.render(); + expect(listView.$el.find("input[name='edit']").is(':not(:checked)')).toEqual(true); + }); + + it('marks edit box as checked for file shares', function () { + shareModel.set('shares', [{ + id: 100, + item_source: 123, + permissions: 1 | OC.PERMISSION_UPDATE, + share_type: OC.Share.SHARE_TYPE_USER, + share_with: 'user1', + share_with_displayname: 'User One', + uid_owner: oc_current_user, + itemType: 'file' + }]); + listView.render(); + expect(listView.$el.find("input[name='edit']").is(':checked')).toEqual(true); + }); + it('marks edit box as indeterminate when only some permissions are given', function () { shareModel.set('shares', [{ id: 100, diff --git a/core/js/tests/specs/shareitemmodelSpec.js b/core/js/tests/specs/shareitemmodelSpec.js index 2e89b2e3cda..a2eabbf4ae4 100644 --- a/core/js/tests/specs/shareitemmodelSpec.js +++ b/core/js/tests/specs/shareitemmodelSpec.js @@ -168,7 +168,8 @@ describe('OC.Share.ShareItemModel', function() { stime: 1403884258, storage: 1, token: 'tehtoken', - uid_owner: 'root' + uid_owner: 'root', + hide_download: 1 } ])); @@ -186,6 +187,7 @@ describe('OC.Share.ShareItemModel', function() { var linkShare = model.get('linkShare'); expect(linkShare.isLinkShare).toEqual(true); + expect(linkShare.hideDownload).toEqual(true); // TODO: check more attributes }); @@ -289,7 +291,8 @@ describe('OC.Share.ShareItemModel', function() { stime: 1403884258, storage: 1, token: 'tehtoken', - uid_owner: 'root' + uid_owner: 'root', + hide_download: 0 }, { displayname_owner: 'root', expiration: '2015-10-15 00:00:00', @@ -307,7 +310,8 @@ describe('OC.Share.ShareItemModel', function() { stime: 1403884509, storage: 1, token: 'anothertoken', - uid_owner: 'root' + uid_owner: 'root', + hide_download: 1 }] )); OC.currentUser = 'root'; @@ -320,6 +324,7 @@ describe('OC.Share.ShareItemModel', function() { var linkShare = model.get('linkShare'); expect(linkShare.isLinkShare).toEqual(true); expect(linkShare.token).toEqual('tehtoken'); + expect(linkShare.hideDownload).toEqual(false); // TODO: check child too }); @@ -579,6 +584,7 @@ describe('OC.Share.ShareItemModel', function() { expect(addShareStub.calledOnce).toEqual(true); expect(addShareStub.firstCall.args[0]).toEqual({ + hideDownload: false, password: '', passwordChanged: false, permissions: OC.PERMISSION_READ, @@ -603,6 +609,7 @@ describe('OC.Share.ShareItemModel', function() { expect(addShareStub.calledOnce).toEqual(true); expect(addShareStub.firstCall.args[0]).toEqual({ + hideDownload: false, password: '', passwordChanged: false, permissions: OC.PERMISSION_READ, diff --git a/core/l10n/af.js b/core/l10n/af.js index f8088145682..0cb8191d595 100644 --- a/core/l10n/af.js +++ b/core/l10n/af.js @@ -141,9 +141,6 @@ OC.L10N.register( "No users found for {search}" : "Geen gebruiker gevind vir {search}", "An error occurred (\"{message}\"). Please try again" : "'n Fout het voorgekom (\"{message}\"). Probeer asseblief weer", "An error occurred. Please try again" : "'n Fout het voorgekom. Probeer asseblief weer", - "{sharee} (group)" : "{sharee} (groep)", - "{sharee} (remote)" : "{sharee} (afgeleë)", - "{sharee} (email)" : "{sharee} (e-pos)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Deel", "Name or email address..." : "Naam of e-posadres...", @@ -243,6 +240,9 @@ OC.L10N.register( "Error setting expiration date" : "Fout terwyl vervaldatum stel", "The public link will expire no later than {days} days after it is created" : "Die publieke skakel sal presies {days} na dit geskep is verval", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} gedeel via skakel", + "{sharee} (group)" : "{sharee} (groep)", + "{sharee} (remote)" : "{sharee} (afgeleë)", + "{sharee} (email)" : "{sharee} (e-pos)", "Share with other people by entering a user or group or an email address." : "Deel met ander deur 'n gebruiker, groep of e-posadres in te vul. ", "The specified document has not been found on the server." : "Die gekose dokument was nie op die bediener gevind nie.", "You can click here to return to %s." : "U kan hier klik om terug te keer na %s", diff --git a/core/l10n/af.json b/core/l10n/af.json index e835f8bf954..5dc57050819 100644 --- a/core/l10n/af.json +++ b/core/l10n/af.json @@ -139,9 +139,6 @@ "No users found for {search}" : "Geen gebruiker gevind vir {search}", "An error occurred (\"{message}\"). Please try again" : "'n Fout het voorgekom (\"{message}\"). Probeer asseblief weer", "An error occurred. Please try again" : "'n Fout het voorgekom. Probeer asseblief weer", - "{sharee} (group)" : "{sharee} (groep)", - "{sharee} (remote)" : "{sharee} (afgeleë)", - "{sharee} (email)" : "{sharee} (e-pos)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Deel", "Name or email address..." : "Naam of e-posadres...", @@ -241,6 +238,9 @@ "Error setting expiration date" : "Fout terwyl vervaldatum stel", "The public link will expire no later than {days} days after it is created" : "Die publieke skakel sal presies {days} na dit geskep is verval", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} gedeel via skakel", + "{sharee} (group)" : "{sharee} (groep)", + "{sharee} (remote)" : "{sharee} (afgeleë)", + "{sharee} (email)" : "{sharee} (e-pos)", "Share with other people by entering a user or group or an email address." : "Deel met ander deur 'n gebruiker, groep of e-posadres in te vul. ", "The specified document has not been found on the server." : "Die gekose dokument was nie op die bediener gevind nie.", "You can click here to return to %s." : "U kan hier klik om terug te keer na %s", diff --git a/core/l10n/ast.js b/core/l10n/ast.js index d40d4138279..0bd13b54ca5 100644 --- a/core/l10n/ast.js +++ b/core/l10n/ast.js @@ -130,8 +130,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Nun s'alcontraron usuarios o grupos pa {search}", "No users found for {search}" : "Nun s'alcontraron usuarios pa {search}", "An error occurred. Please try again" : "Asocedió un fallu. Volvi tentalo, por favor", - "{sharee} (group)" : "{sharee} (grupu)", - "{sharee} (email)" : "{sharee} (corréu)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nome o direición de corréu...", @@ -230,6 +228,8 @@ OC.L10N.register( "Error setting expiration date" : "Fallu afitando la fecha de caducidá", "The public link will expire no later than {days} days after it is created" : "L'enllaz públicu va caducar enantes de {days} díes dende la so creación", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} compartió per enllaz", + "{sharee} (group)" : "{sharee} (grupu)", + "{sharee} (email)" : "{sharee} (corréu)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparti con otra xente introduciendo un usuariu, grupu, ID de ñube federada o direición de corréu.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparti con otra xente introduciendo un usuariu, grupu o ID de ñube federada.", "Share with other people by entering a user or group or an email address." : "Comparti con otra xente introduciendo un usuariu, grupu o direición de corréu.", diff --git a/core/l10n/ast.json b/core/l10n/ast.json index 5019fcc9955..3ab9303f39a 100644 --- a/core/l10n/ast.json +++ b/core/l10n/ast.json @@ -128,8 +128,6 @@ "No users or groups found for {search}" : "Nun s'alcontraron usuarios o grupos pa {search}", "No users found for {search}" : "Nun s'alcontraron usuarios pa {search}", "An error occurred. Please try again" : "Asocedió un fallu. Volvi tentalo, por favor", - "{sharee} (group)" : "{sharee} (grupu)", - "{sharee} (email)" : "{sharee} (corréu)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nome o direición de corréu...", @@ -228,6 +226,8 @@ "Error setting expiration date" : "Fallu afitando la fecha de caducidá", "The public link will expire no later than {days} days after it is created" : "L'enllaz públicu va caducar enantes de {days} díes dende la so creación", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} compartió per enllaz", + "{sharee} (group)" : "{sharee} (grupu)", + "{sharee} (email)" : "{sharee} (corréu)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparti con otra xente introduciendo un usuariu, grupu, ID de ñube federada o direición de corréu.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparti con otra xente introduciendo un usuariu, grupu o ID de ñube federada.", "Share with other people by entering a user or group or an email address." : "Comparti con otra xente introduciendo un usuariu, grupu o direición de corréu.", diff --git a/core/l10n/bg.js b/core/l10n/bg.js index 08eea88b739..9781829bd69 100644 --- a/core/l10n/bg.js +++ b/core/l10n/bg.js @@ -151,12 +151,8 @@ OC.L10N.register( "No users or groups found for {search}" : "Няма потребители или групи за {search}", "No users found for {search}" : "Няма потребители за {search}", "An error occurred. Please try again" : "Възникна грешка. Моля, опитайте отново", - "{sharee} (group)" : "{sharee} (група)", - "{sharee} (remote)" : "{sharee} (отдалечен)", "{sharee} (remote group)" : "{sharee} (отдалечена група)", - "{sharee} (email)" : "{sharee} (имейл)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (разговор)", "Share" : "Споделяне", "Name or email address..." : "Име или имейл адрес...", "Name..." : "Име...", @@ -278,6 +274,9 @@ OC.L10N.register( "Error setting expiration date" : "Грешка при задаване на срок на валидност", "The public link will expire no later than {days} days after it is created" : "Общодостъпната връзка ще изтече не по-късно от {days} дни след създаването ѝ.", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} споделен с връзка", + "{sharee} (group)" : "{sharee} (група)", + "{sharee} (remote)" : "{sharee} (отдалечен)", + "{sharee} (email)" : "{sharee} (имейл)", "The specified document has not been found on the server." : "Избраният документ не е намерен на сървъра.", "You can click here to return to %s." : "Можете да натиснете тук, за да се върнете на %s.", "The server encountered an internal error and was unable to complete your request." : "Поради вътрешно сървърна грешка, сървърът не можа да изпълни заявката ви.", @@ -297,6 +296,7 @@ OC.L10N.register( "This page will refresh itself when the %s instance is available again." : "Страницата ще се зареди автоматично, когато %s е отново на линия.", "Thank you for your patience." : "Благодарим ви за търпението.", "You are about to grant %s access to your %s account." : "Ще разрешите на %s да ползва профила %s.", + "{sharee} (conversation)" : "{sharee} (разговор)", "Please log in before granting %s access to your %s account." : "Необходимо е да се впишете, преди да дадете достъп на %s до вашия %s профил." }, "nplurals=2; plural=(n != 1);"); diff --git a/core/l10n/bg.json b/core/l10n/bg.json index 7b2368f8d99..684028f0810 100644 --- a/core/l10n/bg.json +++ b/core/l10n/bg.json @@ -149,12 +149,8 @@ "No users or groups found for {search}" : "Няма потребители или групи за {search}", "No users found for {search}" : "Няма потребители за {search}", "An error occurred. Please try again" : "Възникна грешка. Моля, опитайте отново", - "{sharee} (group)" : "{sharee} (група)", - "{sharee} (remote)" : "{sharee} (отдалечен)", "{sharee} (remote group)" : "{sharee} (отдалечена група)", - "{sharee} (email)" : "{sharee} (имейл)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (разговор)", "Share" : "Споделяне", "Name or email address..." : "Име или имейл адрес...", "Name..." : "Име...", @@ -276,6 +272,9 @@ "Error setting expiration date" : "Грешка при задаване на срок на валидност", "The public link will expire no later than {days} days after it is created" : "Общодостъпната връзка ще изтече не по-късно от {days} дни след създаването ѝ.", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} споделен с връзка", + "{sharee} (group)" : "{sharee} (група)", + "{sharee} (remote)" : "{sharee} (отдалечен)", + "{sharee} (email)" : "{sharee} (имейл)", "The specified document has not been found on the server." : "Избраният документ не е намерен на сървъра.", "You can click here to return to %s." : "Можете да натиснете тук, за да се върнете на %s.", "The server encountered an internal error and was unable to complete your request." : "Поради вътрешно сървърна грешка, сървърът не можа да изпълни заявката ви.", @@ -295,6 +294,7 @@ "This page will refresh itself when the %s instance is available again." : "Страницата ще се зареди автоматично, когато %s е отново на линия.", "Thank you for your patience." : "Благодарим ви за търпението.", "You are about to grant %s access to your %s account." : "Ще разрешите на %s да ползва профила %s.", + "{sharee} (conversation)" : "{sharee} (разговор)", "Please log in before granting %s access to your %s account." : "Необходимо е да се впишете, преди да дадете достъп на %s до вашия %s профил." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/core/l10n/ca.js b/core/l10n/ca.js index e6ae31313df..0b409104a22 100644 --- a/core/l10n/ca.js +++ b/core/l10n/ca.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "No s'han trobat usuaris per {search}", "An error occurred (\"{message}\"). Please try again" : "S'ha produït un error (\"{message}\"). Si us plau, torni a intentar-ho", "An error occurred. Please try again" : "S'ha produït un error. Si us plau, torni a intentar-ho", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (remot)", "{sharee} (remote group)" : "{sharee} (grup remot)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", "Share" : "Comparteix", "Name or email address..." : "Nom o adreça electrònica...", "Name or federated cloud ID..." : "Nom o ID de Núvol Federat…", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Error en establir la data de venciment", "The public link will expire no later than {days} days after it is created" : "L'enllaç públic tindrà venciment abans de {days} dies després de crear-lo", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartit per enllaç", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (remot)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Compartir amb altres persones introduint un usuari o grup, un ID de núvol federat o una adreça d’email.", "Share with other people by entering a user or group or a federated cloud ID." : "Compartir amb altres persones introduint un usuari o grup o ID de núvol federat.", "Share with other people by entering a user or group or an email address." : "Compartir amb altres persones introduint un usuari o grup o una adreça d’email.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Estàs a punt d'autoritzar a %s a accedir al teu compte %s.", "Depending on your configuration, this button could also work to trust the domain:" : "Depenent de la teva configuració, aquest botó també podria funcionar per confiar en el domini:", "Copy URL" : "Copiar URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Si us plau entrar abans de donar %s accés al teu compte %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Més informació de com configurar això es pot trobar a la %sdocumentation%s." }, diff --git a/core/l10n/ca.json b/core/l10n/ca.json index c166f4648db..fe9056b6964 100644 --- a/core/l10n/ca.json +++ b/core/l10n/ca.json @@ -208,12 +208,8 @@ "No users found for {search}" : "No s'han trobat usuaris per {search}", "An error occurred (\"{message}\"). Please try again" : "S'ha produït un error (\"{message}\"). Si us plau, torni a intentar-ho", "An error occurred. Please try again" : "S'ha produït un error. Si us plau, torni a intentar-ho", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (remot)", "{sharee} (remote group)" : "{sharee} (grup remot)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", "Share" : "Comparteix", "Name or email address..." : "Nom o adreça electrònica...", "Name or federated cloud ID..." : "Nom o ID de Núvol Federat…", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Error en establir la data de venciment", "The public link will expire no later than {days} days after it is created" : "L'enllaç públic tindrà venciment abans de {days} dies després de crear-lo", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartit per enllaç", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (remot)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Compartir amb altres persones introduint un usuari o grup, un ID de núvol federat o una adreça d’email.", "Share with other people by entering a user or group or a federated cloud ID." : "Compartir amb altres persones introduint un usuari o grup o ID de núvol federat.", "Share with other people by entering a user or group or an email address." : "Compartir amb altres persones introduint un usuari o grup o una adreça d’email.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Estàs a punt d'autoritzar a %s a accedir al teu compte %s.", "Depending on your configuration, this button could also work to trust the domain:" : "Depenent de la teva configuració, aquest botó també podria funcionar per confiar en el domini:", "Copy URL" : "Copiar URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Si us plau entrar abans de donar %s accés al teu compte %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Més informació de com configurar això es pot trobar a la %sdocumentation%s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/cs.js b/core/l10n/cs.js index 8a0f26a4e22..37ab7ea022f 100644 --- a/core/l10n/cs.js +++ b/core/l10n/cs.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Nebyli nalezeni žádní uživatelé pro {search}", "An error occurred (\"{message}\"). Please try again" : "Došlo k chybě („{message}“). Zkuste to znovu", "An error occurred. Please try again" : "Došlo k chybě. Zkuste to znovu", - "{sharee} (group)" : "{sharee} (skupina)", - "{sharee} (remote)" : "{sharee} (na protějšku)", "{sharee} (remote group)" : "{sharee} (skupina na protějšku)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (konverzace)", "Share" : "Sdílet", "Name or email address..." : "Jméno nebo e-mailová adresa…", "Name or federated cloud ID..." : "Jméno nebo identifikátor v rámci sdruženého cloudu…", @@ -356,6 +352,7 @@ OC.L10N.register( "For help, see the <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">documentation</a>." : "Pro pomoc, nahlédněte do <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">dokumentace</a>.", "I know that if I continue doing the update via web UI has the risk, that the request runs into a timeout and could cause data loss, but I have a backup and know how to restore my instance in case of a failure." : "Beru na vědomí, že při aktualizaci skrze webové rozhraní hrozí nebezpečí vypršení požadavku, který může vyústit ve ztrátu dat. Mám pro takový případ zálohu a vím, jak ji v případě selhání obnovit.", "Upgrade via web on my own risk" : "Na vlastní nebezpečí aktualizovat skrze web", + "Maintenance mode" : "Režim údržby", "This %s instance is currently in maintenance mode, which may take a while." : "Tato instalace %s je právě ve stavu údržby a ta může chvíli trvat.", "Contact your system administrator if this message persists or appeared unexpectedly." : "Pokud se tato zpráva objevuje opakovaně nebo nečekaně, obraťte se správce systému.", "Updated \"%s\" to %s" : "Aktualizováno z „%s“ na %s", @@ -380,6 +377,9 @@ OC.L10N.register( "Error setting expiration date" : "Chyba při nastavení data skončení platnosti", "The public link will expire no later than {days} days after it is created" : "Veřejný odkaz vyprší nejpozději {days} dní od svého vytvoření", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} sdílí pomocí odkazu", + "{sharee} (group)" : "{sharee} (skupina)", + "{sharee} (remote)" : "{sharee} (na protějšku)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Sdílejte s dalšími lidmi zadáním uživatelského jména, skupiny, federovaného cloud ID, nebo e-mailové adresy.", "Share with other people by entering a user or group or a federated cloud ID." : "Sdílejte s dalšími lidmi zadáním uživatelského jména, skupiny, nebo sdruženého cloud ID.", "Share with other people by entering a user or group or an email address." : "Sdílejte s dalšími lidmi zadáním uživatelského jména, jména skupiny, nebo e-mailové adresy.", @@ -411,6 +411,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Chystáte se povolit %s přístup k vašemu %s účtu.", "Depending on your configuration, this button could also work to trust the domain:" : "V závislosti na vaší konfiguraci by pro označení domény za důvěryhodnou mohlo fungovat i toto tlačítko:", "Copy URL" : "Kopírovat URL", + "{sharee} (conversation)" : "{sharee} (konverzace)", "Please log in before granting %s access to your %s account." : "Přihlaste se před udělením %s přístupu k vašemu %s účtu.", "Further information how to configure this can be found in the %sdocumentation%s." : "Více informací o tom, jak toto nastavit, jsou k dispozici v%sdokumentaci%s." }, diff --git a/core/l10n/cs.json b/core/l10n/cs.json index 4a01f68d6da..edcc2917e54 100644 --- a/core/l10n/cs.json +++ b/core/l10n/cs.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Nebyli nalezeni žádní uživatelé pro {search}", "An error occurred (\"{message}\"). Please try again" : "Došlo k chybě („{message}“). Zkuste to znovu", "An error occurred. Please try again" : "Došlo k chybě. Zkuste to znovu", - "{sharee} (group)" : "{sharee} (skupina)", - "{sharee} (remote)" : "{sharee} (na protějšku)", "{sharee} (remote group)" : "{sharee} (skupina na protějšku)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (konverzace)", "Share" : "Sdílet", "Name or email address..." : "Jméno nebo e-mailová adresa…", "Name or federated cloud ID..." : "Jméno nebo identifikátor v rámci sdruženého cloudu…", @@ -354,6 +350,7 @@ "For help, see the <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">documentation</a>." : "Pro pomoc, nahlédněte do <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"%s\">dokumentace</a>.", "I know that if I continue doing the update via web UI has the risk, that the request runs into a timeout and could cause data loss, but I have a backup and know how to restore my instance in case of a failure." : "Beru na vědomí, že při aktualizaci skrze webové rozhraní hrozí nebezpečí vypršení požadavku, který může vyústit ve ztrátu dat. Mám pro takový případ zálohu a vím, jak ji v případě selhání obnovit.", "Upgrade via web on my own risk" : "Na vlastní nebezpečí aktualizovat skrze web", + "Maintenance mode" : "Režim údržby", "This %s instance is currently in maintenance mode, which may take a while." : "Tato instalace %s je právě ve stavu údržby a ta může chvíli trvat.", "Contact your system administrator if this message persists or appeared unexpectedly." : "Pokud se tato zpráva objevuje opakovaně nebo nečekaně, obraťte se správce systému.", "Updated \"%s\" to %s" : "Aktualizováno z „%s“ na %s", @@ -378,6 +375,9 @@ "Error setting expiration date" : "Chyba při nastavení data skončení platnosti", "The public link will expire no later than {days} days after it is created" : "Veřejný odkaz vyprší nejpozději {days} dní od svého vytvoření", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} sdílí pomocí odkazu", + "{sharee} (group)" : "{sharee} (skupina)", + "{sharee} (remote)" : "{sharee} (na protějšku)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Sdílejte s dalšími lidmi zadáním uživatelského jména, skupiny, federovaného cloud ID, nebo e-mailové adresy.", "Share with other people by entering a user or group or a federated cloud ID." : "Sdílejte s dalšími lidmi zadáním uživatelského jména, skupiny, nebo sdruženého cloud ID.", "Share with other people by entering a user or group or an email address." : "Sdílejte s dalšími lidmi zadáním uživatelského jména, jména skupiny, nebo e-mailové adresy.", @@ -409,6 +409,7 @@ "You are about to grant %s access to your %s account." : "Chystáte se povolit %s přístup k vašemu %s účtu.", "Depending on your configuration, this button could also work to trust the domain:" : "V závislosti na vaší konfiguraci by pro označení domény za důvěryhodnou mohlo fungovat i toto tlačítko:", "Copy URL" : "Kopírovat URL", + "{sharee} (conversation)" : "{sharee} (konverzace)", "Please log in before granting %s access to your %s account." : "Přihlaste se před udělením %s přístupu k vašemu %s účtu.", "Further information how to configure this can be found in the %sdocumentation%s." : "Více informací o tom, jak toto nastavit, jsou k dispozici v%sdokumentaci%s." },"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;" diff --git a/core/l10n/da.js b/core/l10n/da.js index cd0114ff748..f6d6d6a5400 100644 --- a/core/l10n/da.js +++ b/core/l10n/da.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "Ingen brugere fundet for {search}", "An error occurred (\"{message}\"). Please try again" : "Der opstor den fejl (\"{message}\"). Prøv igen", "An error occurred. Please try again" : "Der opstor den fejl. Prøv igen", - "{sharee} (group)" : "{sharee} (gruppe)", - "{sharee} (remote)" : "{sharee} (ekstern)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{share} ({type}, {owner})", "Share" : "Del", "Name or email address..." : "Navn eller e-mail adresse...", @@ -319,6 +316,9 @@ OC.L10N.register( "Error setting expiration date" : "Fejl under sætning af udløbsdato", "The public link will expire no later than {days} days after it is created" : "Det offentlige link udløber senest {days} dage efter det blev oprettet", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delt via link", + "{sharee} (group)" : "{sharee} (gruppe)", + "{sharee} (remote)" : "{sharee} (ekstern)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Del med andre ved at indtaste et brugernavn, en gruppe, et federated cloud id eller en e-mail adresse.", "Share with other people by entering a user or group or a federated cloud ID." : "Del med andre ved at indtaste et brugernavn, en gruppe eller et federated cloud id.", "Share with other people by entering a user or group or an email address." : "Del med andre ved at indtaste et brugernavn, en gruppe eller e-mail adresse.", diff --git a/core/l10n/da.json b/core/l10n/da.json index 26938bb5a20..b363b922f7e 100644 --- a/core/l10n/da.json +++ b/core/l10n/da.json @@ -168,9 +168,6 @@ "No users found for {search}" : "Ingen brugere fundet for {search}", "An error occurred (\"{message}\"). Please try again" : "Der opstor den fejl (\"{message}\"). Prøv igen", "An error occurred. Please try again" : "Der opstor den fejl. Prøv igen", - "{sharee} (group)" : "{sharee} (gruppe)", - "{sharee} (remote)" : "{sharee} (ekstern)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{share} ({type}, {owner})", "Share" : "Del", "Name or email address..." : "Navn eller e-mail adresse...", @@ -317,6 +314,9 @@ "Error setting expiration date" : "Fejl under sætning af udløbsdato", "The public link will expire no later than {days} days after it is created" : "Det offentlige link udløber senest {days} dage efter det blev oprettet", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delt via link", + "{sharee} (group)" : "{sharee} (gruppe)", + "{sharee} (remote)" : "{sharee} (ekstern)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Del med andre ved at indtaste et brugernavn, en gruppe, et federated cloud id eller en e-mail adresse.", "Share with other people by entering a user or group or a federated cloud ID." : "Del med andre ved at indtaste et brugernavn, en gruppe eller et federated cloud id.", "Share with other people by entering a user or group or an email address." : "Del med andre ved at indtaste et brugernavn, en gruppe eller e-mail adresse.", diff --git a/core/l10n/de.js b/core/l10n/de.js index 260bb9ef824..1be2a21a5c6 100644 --- a/core/l10n/de.js +++ b/core/l10n/de.js @@ -167,6 +167,7 @@ OC.L10N.register( "Share to {name}" : "Mit {name} teilen", "Copy link" : "Link kopieren", "Link" : "Link", + "Hide download" : "Download verbergen", "Password protect" : "Passwortschutz", "Allow editing" : "Bearbeitung erlauben", "Email link to person" : "Link per E-Mail verschicken", @@ -210,12 +211,10 @@ OC.L10N.register( "No users found for {search}" : "Keine Benutzer für {search} gefunden", "An error occurred (\"{message}\"). Please try again" : "Benötigt keine Übersetzung. Für iOS wird nur die formelle Übersetzung verwendet (de_DE). ", "An error occurred. Please try again" : "Es ist ein Fehler aufgetreten. Bitte versuche es noch einmal", - "{sharee} (group)" : "{sharee} (Gruppe)", - "{sharee} (remote)" : "{sharee} (remote)", "{sharee} (remote group)" : "{sharee} (externe Gruppe)", - "{sharee} (email)" : "{sharee} (E-Mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Start", + "Other" : "Andere", "Share" : "Teilen", "Name or email address..." : "Name oder E-Mail-Adresse…", "Name or federated cloud ID..." : "Name oder Federated-Cloud-ID…", @@ -382,6 +381,9 @@ OC.L10N.register( "Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums", "The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} mittels Link geteilt", + "{sharee} (group)" : "{sharee} (Gruppe)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (E-Mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Teile mit Anderen, indem Du einen Benutzer, eine Gruppe, eine Federated-Cloud-ID oder eine E-Mail-Adressen eingibst.", "Share with other people by entering a user or group or a federated cloud ID." : "Teile mit Anderen, indem Du einen Benutzer, eine Gruppe, oder eine Federated-Cloud-ID eingibst.", "Share with other people by entering a user or group or an email address." : "Teile mit Anderen, indem Du einen Benutzer, eine Gruppe, oder eine E-Mail-Adresse eingibst.", @@ -413,6 +415,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Du bist dabei, %s Zugriff auf Dein %s-Konto zu gewähren.", "Depending on your configuration, this button could also work to trust the domain:" : "Abhängig von Deiner Konfiguration kann diese Schaltfläche verwandt werden, um die Domain als vertrauenswürdig einzustufen:", "Copy URL" : "URL kopieren", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Bitte anmelden, bevor Du %s Zugriff auf Dein %s-Konto gewährst.", "Further information how to configure this can be found in the %sdocumentation%s." : "Weitere Informationen zur Konfiguration findest du in der %sDokumentation%s." }, diff --git a/core/l10n/de.json b/core/l10n/de.json index cf5b11bb679..f2063db8b24 100644 --- a/core/l10n/de.json +++ b/core/l10n/de.json @@ -165,6 +165,7 @@ "Share to {name}" : "Mit {name} teilen", "Copy link" : "Link kopieren", "Link" : "Link", + "Hide download" : "Download verbergen", "Password protect" : "Passwortschutz", "Allow editing" : "Bearbeitung erlauben", "Email link to person" : "Link per E-Mail verschicken", @@ -208,12 +209,10 @@ "No users found for {search}" : "Keine Benutzer für {search} gefunden", "An error occurred (\"{message}\"). Please try again" : "Benötigt keine Übersetzung. Für iOS wird nur die formelle Übersetzung verwendet (de_DE). ", "An error occurred. Please try again" : "Es ist ein Fehler aufgetreten. Bitte versuche es noch einmal", - "{sharee} (group)" : "{sharee} (Gruppe)", - "{sharee} (remote)" : "{sharee} (remote)", "{sharee} (remote group)" : "{sharee} (externe Gruppe)", - "{sharee} (email)" : "{sharee} (E-Mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Start", + "Other" : "Andere", "Share" : "Teilen", "Name or email address..." : "Name oder E-Mail-Adresse…", "Name or federated cloud ID..." : "Name oder Federated-Cloud-ID…", @@ -380,6 +379,9 @@ "Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums", "The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} mittels Link geteilt", + "{sharee} (group)" : "{sharee} (Gruppe)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (E-Mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Teile mit Anderen, indem Du einen Benutzer, eine Gruppe, eine Federated-Cloud-ID oder eine E-Mail-Adressen eingibst.", "Share with other people by entering a user or group or a federated cloud ID." : "Teile mit Anderen, indem Du einen Benutzer, eine Gruppe, oder eine Federated-Cloud-ID eingibst.", "Share with other people by entering a user or group or an email address." : "Teile mit Anderen, indem Du einen Benutzer, eine Gruppe, oder eine E-Mail-Adresse eingibst.", @@ -411,6 +413,7 @@ "You are about to grant %s access to your %s account." : "Du bist dabei, %s Zugriff auf Dein %s-Konto zu gewähren.", "Depending on your configuration, this button could also work to trust the domain:" : "Abhängig von Deiner Konfiguration kann diese Schaltfläche verwandt werden, um die Domain als vertrauenswürdig einzustufen:", "Copy URL" : "URL kopieren", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Bitte anmelden, bevor Du %s Zugriff auf Dein %s-Konto gewährst.", "Further information how to configure this can be found in the %sdocumentation%s." : "Weitere Informationen zur Konfiguration findest du in der %sDokumentation%s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/de_DE.js b/core/l10n/de_DE.js index 7a7b1b15739..bdcea5e0bb5 100644 --- a/core/l10n/de_DE.js +++ b/core/l10n/de_DE.js @@ -167,6 +167,7 @@ OC.L10N.register( "Share to {name}" : "Mit {name} teilen", "Copy link" : "Link kopieren", "Link" : "Link", + "Hide download" : "Download verbergen", "Password protect" : "Passwortschutz", "Allow editing" : "Bearbeitung erlauben", "Email link to person" : "Link per E-Mail verschicken", @@ -210,12 +211,10 @@ OC.L10N.register( "No users found for {search}" : "Keine Benutzer für {search} gefunden", "An error occurred (\"{message}\"). Please try again" : "Es ist ein Fehler aufgetreten (\"{message}\"). Bitte erneut versuchen.", "An error occurred. Please try again" : "Es ist ein Fehler aufgetreten. Bitte versuchen Sie es noch einmal", - "{sharee} (group)" : "{sharee} (Gruppe)", - "{sharee} (remote)" : "{sharee} (remote)", "{sharee} (remote group)" : "{sharee} (Externe Gruppe)", - "{sharee} (email)" : "{sharee} (E-Mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Start", + "Other" : "Andere", "Share" : "Teilen", "Name or email address..." : "Name oder E-Mail-Adresse…", "Name or federated cloud ID..." : "Name oder Federated-Cloud-ID…", @@ -382,6 +381,9 @@ OC.L10N.register( "Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums", "The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} mittels Link geteilt", + "{sharee} (group)" : "{sharee} (Gruppe)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (E-Mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Teilen mit Anderen, indem Sie einen Benutzer, eine Gruppe, eine Federated-Cloud-ID oder eine E-Mail-Adresse eingeben.", "Share with other people by entering a user or group or a federated cloud ID." : "Teilen mit Anderen, indem Sie einen Benutzer, eine Gruppe, oder eine Federated-Cloud-ID eingeben.", "Share with other people by entering a user or group or an email address." : "Teilen mit Anderen, indem Sie einen Benutzer, eine Gruppe, oder eine E-Mail-Adresse eingeben.", @@ -413,6 +415,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Sie sind dabei, %s Zugriff auf Ihr %s-Konto zu gewähren.", "Depending on your configuration, this button could also work to trust the domain:" : "Abhängig von Ihrer Konfiguration kann diese Schaltfläche verwandt werden, um die Domain als vertrauenswürdig einzustufen:", "Copy URL" : "URL kopieren", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Bitte anmelden, bevor Du %s Zugriff auf Dein %s-Konto gewährst.", "Further information how to configure this can be found in the %sdocumentation%s." : "Weitere Informationen zur Konfiguration finden Sie in der %sDokumentation%s." }, diff --git a/core/l10n/de_DE.json b/core/l10n/de_DE.json index dc1ed554487..7f844020d63 100644 --- a/core/l10n/de_DE.json +++ b/core/l10n/de_DE.json @@ -165,6 +165,7 @@ "Share to {name}" : "Mit {name} teilen", "Copy link" : "Link kopieren", "Link" : "Link", + "Hide download" : "Download verbergen", "Password protect" : "Passwortschutz", "Allow editing" : "Bearbeitung erlauben", "Email link to person" : "Link per E-Mail verschicken", @@ -208,12 +209,10 @@ "No users found for {search}" : "Keine Benutzer für {search} gefunden", "An error occurred (\"{message}\"). Please try again" : "Es ist ein Fehler aufgetreten (\"{message}\"). Bitte erneut versuchen.", "An error occurred. Please try again" : "Es ist ein Fehler aufgetreten. Bitte versuchen Sie es noch einmal", - "{sharee} (group)" : "{sharee} (Gruppe)", - "{sharee} (remote)" : "{sharee} (remote)", "{sharee} (remote group)" : "{sharee} (Externe Gruppe)", - "{sharee} (email)" : "{sharee} (E-Mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Start", + "Other" : "Andere", "Share" : "Teilen", "Name or email address..." : "Name oder E-Mail-Adresse…", "Name or federated cloud ID..." : "Name oder Federated-Cloud-ID…", @@ -380,6 +379,9 @@ "Error setting expiration date" : "Fehler beim Setzen des Ablaufdatums", "The public link will expire no later than {days} days after it is created" : "Der öffentliche Link wird spätestens {days} Tage nach seiner Erstellung ablaufen", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} mittels Link geteilt", + "{sharee} (group)" : "{sharee} (Gruppe)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (E-Mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Teilen mit Anderen, indem Sie einen Benutzer, eine Gruppe, eine Federated-Cloud-ID oder eine E-Mail-Adresse eingeben.", "Share with other people by entering a user or group or a federated cloud ID." : "Teilen mit Anderen, indem Sie einen Benutzer, eine Gruppe, oder eine Federated-Cloud-ID eingeben.", "Share with other people by entering a user or group or an email address." : "Teilen mit Anderen, indem Sie einen Benutzer, eine Gruppe, oder eine E-Mail-Adresse eingeben.", @@ -411,6 +413,7 @@ "You are about to grant %s access to your %s account." : "Sie sind dabei, %s Zugriff auf Ihr %s-Konto zu gewähren.", "Depending on your configuration, this button could also work to trust the domain:" : "Abhängig von Ihrer Konfiguration kann diese Schaltfläche verwandt werden, um die Domain als vertrauenswürdig einzustufen:", "Copy URL" : "URL kopieren", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Bitte anmelden, bevor Du %s Zugriff auf Dein %s-Konto gewährst.", "Further information how to configure this can be found in the %sdocumentation%s." : "Weitere Informationen zur Konfiguration finden Sie in der %sDokumentation%s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/el.js b/core/l10n/el.js index 490cace3f23..aae27a52af2 100644 --- a/core/l10n/el.js +++ b/core/l10n/el.js @@ -155,9 +155,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Δεν βρέθηκαν χρήστες ή ομάδες για την αναζήτηση {search}", "No users found for {search}" : "Δεν βρέθηκαν χρήστες για την αναζήτηση {search}", "An error occurred. Please try again" : "Παρουσιάστηκε σφάλμα. Παρακαλώ δοκιμάστε αργότερα", - "{sharee} (group)" : "{sharee} (ομάδα)", - "{sharee} (remote)" : "{sharee} (απομακρυσμένα)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Διαμοιρασμός", "Name or email address..." : "Όνομα ή διεύθυνση ηλεκτρονικού ταχυδρομείου...", @@ -281,6 +278,9 @@ OC.L10N.register( "Error setting expiration date" : "Σφάλμα κατά τον ορισμό ημερομηνίας λήξης", "The public link will expire no later than {days} days after it is created" : "Ο δημόσιος σύνδεσμος θα απενεργοποιηθεί το πολύ σε {days} ημέρες μετά την δημιουργία του", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} διαμοιράστηκε με σύνδεσμο", + "{sharee} (group)" : "{sharee} (ομάδα)", + "{sharee} (remote)" : "{sharee} (απομακρυσμένα)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Διαμοιραστείτε με άλλους εισάγοντας τον χρήστη ή την ομάδα, το ID του federated cloud ή μια διεύθυνση ηλεκτρονικού ταχυδρομείου.", "Share with other people by entering a user or group or a federated cloud ID." : "Διαμοιραστείτε με άλλους εισάγοντας τον χρήστη ή την ομάδα ή το ID του federated cloud.", "Share with other people by entering a user or group or an email address." : "Διαμοιραστείτε με άλλους εισάγοντας τον χρήστη ή την ομάδα ή μια διεύθυνση ηλεκτρονικού ταχυδρομείου.", diff --git a/core/l10n/el.json b/core/l10n/el.json index e70fff20a1e..08f2db92103 100644 --- a/core/l10n/el.json +++ b/core/l10n/el.json @@ -153,9 +153,6 @@ "No users or groups found for {search}" : "Δεν βρέθηκαν χρήστες ή ομάδες για την αναζήτηση {search}", "No users found for {search}" : "Δεν βρέθηκαν χρήστες για την αναζήτηση {search}", "An error occurred. Please try again" : "Παρουσιάστηκε σφάλμα. Παρακαλώ δοκιμάστε αργότερα", - "{sharee} (group)" : "{sharee} (ομάδα)", - "{sharee} (remote)" : "{sharee} (απομακρυσμένα)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Διαμοιρασμός", "Name or email address..." : "Όνομα ή διεύθυνση ηλεκτρονικού ταχυδρομείου...", @@ -279,6 +276,9 @@ "Error setting expiration date" : "Σφάλμα κατά τον ορισμό ημερομηνίας λήξης", "The public link will expire no later than {days} days after it is created" : "Ο δημόσιος σύνδεσμος θα απενεργοποιηθεί το πολύ σε {days} ημέρες μετά την δημιουργία του", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} διαμοιράστηκε με σύνδεσμο", + "{sharee} (group)" : "{sharee} (ομάδα)", + "{sharee} (remote)" : "{sharee} (απομακρυσμένα)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Διαμοιραστείτε με άλλους εισάγοντας τον χρήστη ή την ομάδα, το ID του federated cloud ή μια διεύθυνση ηλεκτρονικού ταχυδρομείου.", "Share with other people by entering a user or group or a federated cloud ID." : "Διαμοιραστείτε με άλλους εισάγοντας τον χρήστη ή την ομάδα ή το ID του federated cloud.", "Share with other people by entering a user or group or an email address." : "Διαμοιραστείτε με άλλους εισάγοντας τον χρήστη ή την ομάδα ή μια διεύθυνση ηλεκτρονικού ταχυδρομείου.", diff --git a/core/l10n/en_GB.js b/core/l10n/en_GB.js index 269026c479a..1530abaedb8 100644 --- a/core/l10n/en_GB.js +++ b/core/l10n/en_GB.js @@ -172,9 +172,6 @@ OC.L10N.register( "No users found for {search}" : "No users found for {search}", "An error occurred (\"{message}\"). Please try again" : "An error occurred (\"{message}\"). Please try again", "An error occurred. Please try again" : "An error occurred. Please try again", - "{sharee} (group)" : "{sharee} (group)", - "{sharee} (remote)" : "{sharee} (remote)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Share", "Name or email address..." : "Name or email address...", @@ -325,6 +322,9 @@ OC.L10N.register( "Error setting expiration date" : "Error setting expiration date", "The public link will expire no later than {days} days after it is created" : "The public link will expire no later than {days} days after it is created", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} shared via link", + "{sharee} (group)" : "{sharee} (group)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Share with other people by entering a user or group, a federated cloud ID or an email address.", "Share with other people by entering a user or group or a federated cloud ID." : "Share with other people by entering a user or group or a federated cloud ID.", "Share with other people by entering a user or group or an email address." : "Share with other people by entering a user or group or an email address.", diff --git a/core/l10n/en_GB.json b/core/l10n/en_GB.json index 66c984ba1d7..5fd03c9de3d 100644 --- a/core/l10n/en_GB.json +++ b/core/l10n/en_GB.json @@ -170,9 +170,6 @@ "No users found for {search}" : "No users found for {search}", "An error occurred (\"{message}\"). Please try again" : "An error occurred (\"{message}\"). Please try again", "An error occurred. Please try again" : "An error occurred. Please try again", - "{sharee} (group)" : "{sharee} (group)", - "{sharee} (remote)" : "{sharee} (remote)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Share", "Name or email address..." : "Name or email address...", @@ -323,6 +320,9 @@ "Error setting expiration date" : "Error setting expiration date", "The public link will expire no later than {days} days after it is created" : "The public link will expire no later than {days} days after it is created", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} shared via link", + "{sharee} (group)" : "{sharee} (group)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Share with other people by entering a user or group, a federated cloud ID or an email address.", "Share with other people by entering a user or group or a federated cloud ID." : "Share with other people by entering a user or group or a federated cloud ID.", "Share with other people by entering a user or group or an email address." : "Share with other people by entering a user or group or an email address.", diff --git a/core/l10n/eo.js b/core/l10n/eo.js index 3900daa108b..2ebc961173f 100644 --- a/core/l10n/eo.js +++ b/core/l10n/eo.js @@ -116,9 +116,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Neniu uzanto aŭ grupo troviĝis por {search}", "An error occurred (\"{message}\"). Please try again" : "Eraro okazis (\"{message}\"). Bonvolu provi ree.", "An error occurred. Please try again" : "Eraro okazis. Bonvolu provi ree", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (fora)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Kunhavigi", "Name or email address..." : "Nomo aŭ retpoŝtadreso...", @@ -215,6 +212,9 @@ OC.L10N.register( "Shared with {recipients}" : "Kunhavigis kun {recipients}", "Error setting expiration date" : "Eraro dum agordado de limdato", "The public link will expire no later than {days} days after it is created" : "La publika ligilo senvalidiĝos ne pli malfrue ol {days} tagojn post ĝi kreiĝos", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (fora)", + "{sharee} (email)" : "{sharee} (email)", "This action requires you to confirm your password:" : "Tiu ĉi ago bezonas ke vi konfirmas vian pasvorton:", "Wrong password. Reset it?" : "Falsa pasvorto. Ĉu vi volas rekomenci ĝin?", "Stay logged in" : "Daŭri ensalutinta", diff --git a/core/l10n/eo.json b/core/l10n/eo.json index c48216f51b5..1a1b56551f6 100644 --- a/core/l10n/eo.json +++ b/core/l10n/eo.json @@ -114,9 +114,6 @@ "No users or groups found for {search}" : "Neniu uzanto aŭ grupo troviĝis por {search}", "An error occurred (\"{message}\"). Please try again" : "Eraro okazis (\"{message}\"). Bonvolu provi ree.", "An error occurred. Please try again" : "Eraro okazis. Bonvolu provi ree", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (fora)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Kunhavigi", "Name or email address..." : "Nomo aŭ retpoŝtadreso...", @@ -213,6 +210,9 @@ "Shared with {recipients}" : "Kunhavigis kun {recipients}", "Error setting expiration date" : "Eraro dum agordado de limdato", "The public link will expire no later than {days} days after it is created" : "La publika ligilo senvalidiĝos ne pli malfrue ol {days} tagojn post ĝi kreiĝos", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (fora)", + "{sharee} (email)" : "{sharee} (email)", "This action requires you to confirm your password:" : "Tiu ĉi ago bezonas ke vi konfirmas vian pasvorton:", "Wrong password. Reset it?" : "Falsa pasvorto. Ĉu vi volas rekomenci ĝin?", "Stay logged in" : "Daŭri ensalutinta", diff --git a/core/l10n/es.js b/core/l10n/es.js index ce580b7d2de..7b8c50b4034 100644 --- a/core/l10n/es.js +++ b/core/l10n/es.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "No se han encontrado usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Ha ocurrido un error (\"{message}\"). Por favor inténtelo de nuevo", "An error occurred. Please try again" : "Ha ocurrido un error. Por favor inténtelo de nuevo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", "{sharee} (remote group)" : "{sharee} (grupo remoto)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversación)", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico...", "Name or federated cloud ID..." : "Nombre o ID de nube federada...", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Error estableciendo fecha de caducidad", "The public link will expire no later than {days} days after it is created" : "El vínculo público no expirará antes de {days} desde que se creó", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} compartido por medio de un link", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas introduciendo un usuario, grupo, ID de nube federada o dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas introduciendo un usuario, grupo o ID de nube federada.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas introduciendo un usuario, grupo o una dirección de correo electrónico.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Estás a punto de conceder a %s acceso a tu cuenta de %s", "Depending on your configuration, this button could also work to trust the domain:" : "Dependiendo de tu configuración, este botón también podría servir para confiar en el dominio:", "Copy URL" : "Copiar URL", + "{sharee} (conversation)" : "{sharee} (conversación)", "Please log in before granting %s access to your %s account." : "Por favor, inicie sesión antes de conceder a %s acceso a tu %s cuenta.", "Further information how to configure this can be found in the %sdocumentation%s." : "Más información sobre cómo configurar esto se puede encontrar en la %sdocumentación%s." }, diff --git a/core/l10n/es.json b/core/l10n/es.json index a2be02603df..15fa4d62ad7 100644 --- a/core/l10n/es.json +++ b/core/l10n/es.json @@ -208,12 +208,8 @@ "No users found for {search}" : "No se han encontrado usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Ha ocurrido un error (\"{message}\"). Por favor inténtelo de nuevo", "An error occurred. Please try again" : "Ha ocurrido un error. Por favor inténtelo de nuevo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", "{sharee} (remote group)" : "{sharee} (grupo remoto)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversación)", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico...", "Name or federated cloud ID..." : "Nombre o ID de nube federada...", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Error estableciendo fecha de caducidad", "The public link will expire no later than {days} days after it is created" : "El vínculo público no expirará antes de {days} desde que se creó", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} compartido por medio de un link", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas introduciendo un usuario, grupo, ID de nube federada o dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas introduciendo un usuario, grupo o ID de nube federada.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas introduciendo un usuario, grupo o una dirección de correo electrónico.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Estás a punto de conceder a %s acceso a tu cuenta de %s", "Depending on your configuration, this button could also work to trust the domain:" : "Dependiendo de tu configuración, este botón también podría servir para confiar en el dominio:", "Copy URL" : "Copiar URL", + "{sharee} (conversation)" : "{sharee} (conversación)", "Please log in before granting %s access to your %s account." : "Por favor, inicie sesión antes de conceder a %s acceso a tu %s cuenta.", "Further information how to configure this can be found in the %sdocumentation%s." : "Más información sobre cómo configurar esto se puede encontrar en la %sdocumentación%s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/es_419.js b/core/l10n/es_419.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_419.js +++ b/core/l10n/es_419.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_419.json b/core/l10n/es_419.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_419.json +++ b/core/l10n/es_419.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_AR.js b/core/l10n/es_AR.js index 88229c30d51..36ff6cfc7ea 100644 --- a/core/l10n/es_AR.js +++ b/core/l10n/es_AR.js @@ -147,9 +147,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Favor de volver a intentar", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -265,6 +262,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "El link público expirará a los {days} días de haber sido creado", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compatido mediante un link", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparta con otras personas ingresando un usuario, un grupo, un ID de nube federado o una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparta con otras personas ingresando un usuario, un grupo o un ID de nube federado.", "Share with other people by entering a user or group or an email address." : "Comparta con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_AR.json b/core/l10n/es_AR.json index 1036a3cba25..c13e9e0bffb 100644 --- a/core/l10n/es_AR.json +++ b/core/l10n/es_AR.json @@ -145,9 +145,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Favor de volver a intentar", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -263,6 +260,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "El link público expirará a los {days} días de haber sido creado", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compatido mediante un link", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparta con otras personas ingresando un usuario, un grupo, un ID de nube federado o una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparta con otras personas ingresando un usuario, un grupo o un ID de nube federado.", "Share with other people by entering a user or group or an email address." : "Comparta con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_CL.js b/core/l10n/es_CL.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_CL.js +++ b/core/l10n/es_CL.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_CL.json b/core/l10n/es_CL.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_CL.json +++ b/core/l10n/es_CL.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_CO.js b/core/l10n/es_CO.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_CO.js +++ b/core/l10n/es_CO.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_CO.json b/core/l10n/es_CO.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_CO.json +++ b/core/l10n/es_CO.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_CR.js b/core/l10n/es_CR.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_CR.js +++ b/core/l10n/es_CR.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_CR.json b/core/l10n/es_CR.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_CR.json +++ b/core/l10n/es_CR.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_DO.js b/core/l10n/es_DO.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_DO.js +++ b/core/l10n/es_DO.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_DO.json b/core/l10n/es_DO.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_DO.json +++ b/core/l10n/es_DO.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_EC.js b/core/l10n/es_EC.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_EC.js +++ b/core/l10n/es_EC.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_EC.json b/core/l10n/es_EC.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_EC.json +++ b/core/l10n/es_EC.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_GT.js b/core/l10n/es_GT.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_GT.js +++ b/core/l10n/es_GT.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_GT.json b/core/l10n/es_GT.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_GT.json +++ b/core/l10n/es_GT.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_HN.js b/core/l10n/es_HN.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_HN.js +++ b/core/l10n/es_HN.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_HN.json b/core/l10n/es_HN.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_HN.json +++ b/core/l10n/es_HN.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_MX.js b/core/l10n/es_MX.js index cfa292606c7..705c2721a69 100644 --- a/core/l10n/es_MX.js +++ b/core/l10n/es_MX.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_MX.json b/core/l10n/es_MX.json index ea929476c1f..87529c8e1b2 100644 --- a/core/l10n/es_MX.json +++ b/core/l10n/es_MX.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_NI.js b/core/l10n/es_NI.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_NI.js +++ b/core/l10n/es_NI.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_NI.json b/core/l10n/es_NI.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_NI.json +++ b/core/l10n/es_NI.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PA.js b/core/l10n/es_PA.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_PA.js +++ b/core/l10n/es_PA.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PA.json b/core/l10n/es_PA.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_PA.json +++ b/core/l10n/es_PA.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PE.js b/core/l10n/es_PE.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_PE.js +++ b/core/l10n/es_PE.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PE.json b/core/l10n/es_PE.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_PE.json +++ b/core/l10n/es_PE.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PR.js b/core/l10n/es_PR.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_PR.js +++ b/core/l10n/es_PR.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PR.json b/core/l10n/es_PR.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_PR.json +++ b/core/l10n/es_PR.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PY.js b/core/l10n/es_PY.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_PY.js +++ b/core/l10n/es_PY.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_PY.json b/core/l10n/es_PY.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_PY.json +++ b/core/l10n/es_PY.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_SV.js b/core/l10n/es_SV.js index 28531d48743..d98b3dcebed 100644 --- a/core/l10n/es_SV.js +++ b/core/l10n/es_SV.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -323,6 +320,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_SV.json b/core/l10n/es_SV.json index 9ec18d03f47..4446f7c8610 100644 --- a/core/l10n/es_SV.json +++ b/core/l10n/es_SV.json @@ -168,9 +168,6 @@ "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred (\"{message}\"). Please try again" : "Se presentó un error (\"{message}\"). Por favor vuelve a intentarlo", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -321,6 +318,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_UY.js b/core/l10n/es_UY.js index f44a641ce1e..6cb4f43e6a8 100644 --- a/core/l10n/es_UY.js +++ b/core/l10n/es_UY.js @@ -167,9 +167,6 @@ OC.L10N.register( "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -294,6 +291,9 @@ OC.L10N.register( "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/es_UY.json b/core/l10n/es_UY.json index 62d866f1327..fcb62367d14 100644 --- a/core/l10n/es_UY.json +++ b/core/l10n/es_UY.json @@ -165,9 +165,6 @@ "No users or groups found for {search}" : "No se encontraron usuarios o gurpos para {search}", "No users found for {search}" : "No se encontraron usuarios para {search}", "An error occurred. Please try again" : "Se presentó un error. Por favor vuelve a intentarlo", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (correo electrónico)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Compartir", "Name or email address..." : "Nombre o dirección de correo electrónico", @@ -292,6 +289,9 @@ "Error setting expiration date" : "Se presentó un error al establecer la fecha de expiración", "The public link will expire no later than {days} days after it is created" : "La liga pública expirará a los {days} días de haber sido creada", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha compartido mediante una liga", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (correo electrónico)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Comparte con otras personas ingresando una dirección de correo electrónico.", "Share with other people by entering a user or group or a federated cloud ID." : "Comparte con otras personas ingresando un usuario o un grupo.", "Share with other people by entering a user or group or an email address." : "Comparte con otras personas ingresando un usuario, un grupo o una dirección de correo electrónico.", diff --git a/core/l10n/et_EE.js b/core/l10n/et_EE.js index f52158fff67..d5dc8f888a1 100644 --- a/core/l10n/et_EE.js +++ b/core/l10n/et_EE.js @@ -153,9 +153,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Otsingu {search} põhjal kasutajaid ega gruppe ei leitud", "No users found for {search}" : "Otsingu {search} põhjal kasutajaid ei leitud", "An error occurred. Please try again" : "Tekkis tõrge. Palun proovi uuesti", - "{sharee} (group)" : "{sharee} (grupp)", - "{sharee} (remote)" : "{sharee} (mujal serveris)", - "{sharee} (email)" : "{sharee} (e-post)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Jaga", "Name or email address..." : "Nimi või e-posti aadress", @@ -275,6 +272,9 @@ OC.L10N.register( "Error setting expiration date" : "Viga aegumise kuupäeva määramisel", "The public link will expire no later than {days} days after it is created" : "Avalik link aegub mitte hiljem kui pärast {days} päeva selle loomist", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} lingiga jagatud", + "{sharee} (group)" : "{sharee} (grupp)", + "{sharee} (remote)" : "{sharee} (mujal serveris)", + "{sharee} (email)" : "{sharee} (e-post)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Jaga teiste inimestega sisestades kasutaja või grupi, liitpilve ID või e-posti aadressi.", "Share with other people by entering a user or group or a federated cloud ID." : "Jaga teiste inimestega, sisestades kasutaja või grupi või liitpilve ID.", "Share with other people by entering a user or group or an email address." : "Jaga teiste inimestega, sisestades kasutaja, grupi või e-posti aadressi.", diff --git a/core/l10n/et_EE.json b/core/l10n/et_EE.json index 7ae2161a144..01c2d1626d2 100644 --- a/core/l10n/et_EE.json +++ b/core/l10n/et_EE.json @@ -151,9 +151,6 @@ "No users or groups found for {search}" : "Otsingu {search} põhjal kasutajaid ega gruppe ei leitud", "No users found for {search}" : "Otsingu {search} põhjal kasutajaid ei leitud", "An error occurred. Please try again" : "Tekkis tõrge. Palun proovi uuesti", - "{sharee} (group)" : "{sharee} (grupp)", - "{sharee} (remote)" : "{sharee} (mujal serveris)", - "{sharee} (email)" : "{sharee} (e-post)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Jaga", "Name or email address..." : "Nimi või e-posti aadress", @@ -273,6 +270,9 @@ "Error setting expiration date" : "Viga aegumise kuupäeva määramisel", "The public link will expire no later than {days} days after it is created" : "Avalik link aegub mitte hiljem kui pärast {days} päeva selle loomist", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} lingiga jagatud", + "{sharee} (group)" : "{sharee} (grupp)", + "{sharee} (remote)" : "{sharee} (mujal serveris)", + "{sharee} (email)" : "{sharee} (e-post)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Jaga teiste inimestega sisestades kasutaja või grupi, liitpilve ID või e-posti aadressi.", "Share with other people by entering a user or group or a federated cloud ID." : "Jaga teiste inimestega, sisestades kasutaja või grupi või liitpilve ID.", "Share with other people by entering a user or group or an email address." : "Jaga teiste inimestega, sisestades kasutaja, grupi või e-posti aadressi.", diff --git a/core/l10n/eu.js b/core/l10n/eu.js index 041313326a6..248409d80d7 100644 --- a/core/l10n/eu.js +++ b/core/l10n/eu.js @@ -150,9 +150,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Ez dira {search} -rentzat erabiltzaile edo talderik aurkitu", "No users found for {search}" : "Ez dira {search} -rentzat erabiltzailerik aurkitu", "An error occurred. Please try again" : "Errore bat gertatu da. Saiatu berriro.", - "{sharee} (group)" : "{sharee} (taldea)", - "{sharee} (remote)" : "{sharee} (urrunekoa)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {jabea})", "Share" : "Partekatu", "Name or email address..." : "Izena edo e-posta helbidea...", @@ -273,6 +270,9 @@ OC.L10N.register( "Error setting expiration date" : "Errore bat egon da muga data ezartzean", "The public link will expire no later than {days} days after it is created" : "Esteka publikoak iraungi egingo du, askoz jota, sortu eta {days} egunetara.", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} esteka bidez partekatuta", + "{sharee} (group)" : "{sharee} (taldea)", + "{sharee} (remote)" : "{sharee} (urrunekoa)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Parteka ezazu jendearekin taldeko erabiltzailea, federatutako hodei baten IDa edo e-posta helbide bat sartuta.", "Share with other people by entering a user or group or a federated cloud ID." : "Parteka ezazu jendearekin taldeko erabiltzailea edo federatutako hodei baten IDa sartuta.", "Share with other people by entering a user or group or an email address." : "Parteka ezazu jendearekin taldeko erabiltzailea edo e-posta helbide bat sartuta.", diff --git a/core/l10n/eu.json b/core/l10n/eu.json index 37d0faa64b9..686e31fcc7d 100644 --- a/core/l10n/eu.json +++ b/core/l10n/eu.json @@ -148,9 +148,6 @@ "No users or groups found for {search}" : "Ez dira {search} -rentzat erabiltzaile edo talderik aurkitu", "No users found for {search}" : "Ez dira {search} -rentzat erabiltzailerik aurkitu", "An error occurred. Please try again" : "Errore bat gertatu da. Saiatu berriro.", - "{sharee} (group)" : "{sharee} (taldea)", - "{sharee} (remote)" : "{sharee} (urrunekoa)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {jabea})", "Share" : "Partekatu", "Name or email address..." : "Izena edo e-posta helbidea...", @@ -271,6 +268,9 @@ "Error setting expiration date" : "Errore bat egon da muga data ezartzean", "The public link will expire no later than {days} days after it is created" : "Esteka publikoak iraungi egingo du, askoz jota, sortu eta {days} egunetara.", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} esteka bidez partekatuta", + "{sharee} (group)" : "{sharee} (taldea)", + "{sharee} (remote)" : "{sharee} (urrunekoa)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Parteka ezazu jendearekin taldeko erabiltzailea, federatutako hodei baten IDa edo e-posta helbide bat sartuta.", "Share with other people by entering a user or group or a federated cloud ID." : "Parteka ezazu jendearekin taldeko erabiltzailea edo federatutako hodei baten IDa sartuta.", "Share with other people by entering a user or group or an email address." : "Parteka ezazu jendearekin taldeko erabiltzailea edo e-posta helbide bat sartuta.", diff --git a/core/l10n/fa.js b/core/l10n/fa.js index 6c5cd28899c..1b8c916cffe 100644 --- a/core/l10n/fa.js +++ b/core/l10n/fa.js @@ -150,9 +150,6 @@ OC.L10N.register( "No users or groups found for {search}" : "هیچ کاربری یا گروهی یافت نشد {search}", "No users found for {search}" : "هیچ کاربری با جستجوی {search} یافت نشد", "An error occurred. Please try again" : "یک خطا رخ داده است، لطفا مجددا تلاش کنید", - "{sharee} (group)" : "{sharee} (group)", - "{sharee} (remote)" : "{sharee} (remote)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "اشتراکگذاری", "Name or email address..." : "نام یا آدرس ایمیل ...", @@ -257,6 +254,9 @@ OC.L10N.register( "Error setting expiration date" : "خطا در تنظیم تاریخ انقضا", "The public link will expire no later than {days} days after it is created" : "لینک عمومی پس از {days} روز پس از ایجاد منقضی خواهد شد", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} به اشتراک گذاشته شده از طریق لینک", + "{sharee} (group)" : "{sharee} (group)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "با وارد کردن یک کاربر یا گروه، شناسه Federated Cloud یا آدرس ایمیل با دیگران به اشتراک بگذارید.", "Share with other people by entering a user or group or a federated cloud ID." : "با وارد کردن یک کاربر یا گروه یا شناسه Federated Cloud با افراد دیگر به اشتراک بگذارید.", "Share with other people by entering a user or group or an email address." : "با وارد کردن یک کاربر یا گروه یا یک آدرس ایمیل با افراد دیگر به اشتراک بگذارید.", diff --git a/core/l10n/fa.json b/core/l10n/fa.json index 24e8130b426..96cc772cc9e 100644 --- a/core/l10n/fa.json +++ b/core/l10n/fa.json @@ -148,9 +148,6 @@ "No users or groups found for {search}" : "هیچ کاربری یا گروهی یافت نشد {search}", "No users found for {search}" : "هیچ کاربری با جستجوی {search} یافت نشد", "An error occurred. Please try again" : "یک خطا رخ داده است، لطفا مجددا تلاش کنید", - "{sharee} (group)" : "{sharee} (group)", - "{sharee} (remote)" : "{sharee} (remote)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "اشتراکگذاری", "Name or email address..." : "نام یا آدرس ایمیل ...", @@ -255,6 +252,9 @@ "Error setting expiration date" : "خطا در تنظیم تاریخ انقضا", "The public link will expire no later than {days} days after it is created" : "لینک عمومی پس از {days} روز پس از ایجاد منقضی خواهد شد", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} به اشتراک گذاشته شده از طریق لینک", + "{sharee} (group)" : "{sharee} (group)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "با وارد کردن یک کاربر یا گروه، شناسه Federated Cloud یا آدرس ایمیل با دیگران به اشتراک بگذارید.", "Share with other people by entering a user or group or a federated cloud ID." : "با وارد کردن یک کاربر یا گروه یا شناسه Federated Cloud با افراد دیگر به اشتراک بگذارید.", "Share with other people by entering a user or group or an email address." : "با وارد کردن یک کاربر یا گروه یا یک آدرس ایمیل با افراد دیگر به اشتراک بگذارید.", diff --git a/core/l10n/fi.js b/core/l10n/fi.js index 8cbbf37cc80..52f76812da4 100644 --- a/core/l10n/fi.js +++ b/core/l10n/fi.js @@ -180,9 +180,6 @@ OC.L10N.register( "No users found for {search}" : "Haulla {search} ei löytynyt käyttäjiä", "An error occurred (\"{message}\"). Please try again" : "Tapahtui virhe (\"{message}\"). Yritä uudestaan", "An error occurred. Please try again" : "Tapahtui virhe, yritä uudelleen", - "{sharee} (group)" : "{sharee} (ryhmä)", - "{sharee} (remote)" : "{sharee} (etä)", - "{sharee} (email)" : "{sharee} (sähköposti)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Jaa", "Name or email address..." : "Nimi tai sähköpostiosoite...", @@ -332,6 +329,9 @@ OC.L10N.register( "Error setting expiration date" : "Virhe vanhenemispäivää asetettaessa", "The public link will expire no later than {days} days after it is created" : "Julkinen linkki vanhenee {days} päivän jälkeen sen luomisesta", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} jakoi linkillä", + "{sharee} (group)" : "{sharee} (ryhmä)", + "{sharee} (remote)" : "{sharee} (etä)", + "{sharee} (email)" : "{sharee} (sähköposti)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Jaa muille kirjoittamalla käyttäjä tai ryhmä, federoidun pilven tunniste tai sähköpostiosoite.", "Share with other people by entering a user or group or a federated cloud ID." : "Jaa muille kirjoittamalla käyttäjä, ryhmä tai federoidun pilven tunniste.", "Share with other people by entering a user or group or an email address." : "Jaa muille kirjoittamalla käyttäjä, ryhmä tai sähköpostiosoite.", diff --git a/core/l10n/fi.json b/core/l10n/fi.json index 22bcbca652b..cd83c50269d 100644 --- a/core/l10n/fi.json +++ b/core/l10n/fi.json @@ -178,9 +178,6 @@ "No users found for {search}" : "Haulla {search} ei löytynyt käyttäjiä", "An error occurred (\"{message}\"). Please try again" : "Tapahtui virhe (\"{message}\"). Yritä uudestaan", "An error occurred. Please try again" : "Tapahtui virhe, yritä uudelleen", - "{sharee} (group)" : "{sharee} (ryhmä)", - "{sharee} (remote)" : "{sharee} (etä)", - "{sharee} (email)" : "{sharee} (sähköposti)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Jaa", "Name or email address..." : "Nimi tai sähköpostiosoite...", @@ -330,6 +327,9 @@ "Error setting expiration date" : "Virhe vanhenemispäivää asetettaessa", "The public link will expire no later than {days} days after it is created" : "Julkinen linkki vanhenee {days} päivän jälkeen sen luomisesta", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} jakoi linkillä", + "{sharee} (group)" : "{sharee} (ryhmä)", + "{sharee} (remote)" : "{sharee} (etä)", + "{sharee} (email)" : "{sharee} (sähköposti)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Jaa muille kirjoittamalla käyttäjä tai ryhmä, federoidun pilven tunniste tai sähköpostiosoite.", "Share with other people by entering a user or group or a federated cloud ID." : "Jaa muille kirjoittamalla käyttäjä, ryhmä tai federoidun pilven tunniste.", "Share with other people by entering a user or group or an email address." : "Jaa muille kirjoittamalla käyttäjä, ryhmä tai sähköpostiosoite.", diff --git a/core/l10n/fr.js b/core/l10n/fr.js index a0e31cc9e93..5eaf3ba99f8 100644 --- a/core/l10n/fr.js +++ b/core/l10n/fr.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Aucun utilisateur trouvé pour {search}", "An error occurred (\"{message}\"). Please try again" : "Une erreur est survenue (\"{message}\"). Veuillez réessayer", "An error occurred. Please try again" : "Une erreur est survenue. Merci de réessayer", - "{sharee} (group)" : "{sharee} (groupe)", - "{sharee} (remote)" : "{sharee} (distant)", "{sharee} (remote group)" : "{sharee} (groupe distant)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (discussion)", "Share" : "Partager", "Name or email address..." : "Nom ou adresse mail...", "Name or federated cloud ID..." : "Nom ou ID du cloud fédéré...", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Erreur lors de la configuration de la date d'expiration", "The public link will expire no later than {days} days after it is created" : "Ce lien public expirera dans {days} jours après sa création.", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} a partagé via un lien", + "{sharee} (group)" : "{sharee} (groupe)", + "{sharee} (remote)" : "{sharee} (distant)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Partager avec d'autres personnes en indiquant un nom d'utilisateur, un groupe, un identifiant de cloud fédéré ou une adresse email.", "Share with other people by entering a user or group or a federated cloud ID." : "Partager avec d'autres personnes en indiquant un utilisateur, un groupe ou un identifiant de cloud fédéré.", "Share with other people by entering a user or group or an email address." : "Partager avec d'autres personnes en indiquant un utilisateur, un groupe ou une adresse email.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Vous êtes sur le point d'accorder à \"%s\" l'accès à votre compte \"%s\".", "Depending on your configuration, this button could also work to trust the domain:" : "En fonction de votre configuration, ce bouton peut aussi fonctionner pour approuver ce domaine :", "Copy URL" : "Copier l'adresse URL", + "{sharee} (conversation)" : "{sharee} (discussion)", "Please log in before granting %s access to your %s account." : "Veuillez vous connecter avant d'autoriser %s à accéder à votre compte %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Vous trouverez d'autres informations sur la configuration dans la %sdocumentation %s." }, diff --git a/core/l10n/fr.json b/core/l10n/fr.json index 8aa4264d799..d526c33fc7b 100644 --- a/core/l10n/fr.json +++ b/core/l10n/fr.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Aucun utilisateur trouvé pour {search}", "An error occurred (\"{message}\"). Please try again" : "Une erreur est survenue (\"{message}\"). Veuillez réessayer", "An error occurred. Please try again" : "Une erreur est survenue. Merci de réessayer", - "{sharee} (group)" : "{sharee} (groupe)", - "{sharee} (remote)" : "{sharee} (distant)", "{sharee} (remote group)" : "{sharee} (groupe distant)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (discussion)", "Share" : "Partager", "Name or email address..." : "Nom ou adresse mail...", "Name or federated cloud ID..." : "Nom ou ID du cloud fédéré...", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Erreur lors de la configuration de la date d'expiration", "The public link will expire no later than {days} days after it is created" : "Ce lien public expirera dans {days} jours après sa création.", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} a partagé via un lien", + "{sharee} (group)" : "{sharee} (groupe)", + "{sharee} (remote)" : "{sharee} (distant)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Partager avec d'autres personnes en indiquant un nom d'utilisateur, un groupe, un identifiant de cloud fédéré ou une adresse email.", "Share with other people by entering a user or group or a federated cloud ID." : "Partager avec d'autres personnes en indiquant un utilisateur, un groupe ou un identifiant de cloud fédéré.", "Share with other people by entering a user or group or an email address." : "Partager avec d'autres personnes en indiquant un utilisateur, un groupe ou une adresse email.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Vous êtes sur le point d'accorder à \"%s\" l'accès à votre compte \"%s\".", "Depending on your configuration, this button could also work to trust the domain:" : "En fonction de votre configuration, ce bouton peut aussi fonctionner pour approuver ce domaine :", "Copy URL" : "Copier l'adresse URL", + "{sharee} (conversation)" : "{sharee} (discussion)", "Please log in before granting %s access to your %s account." : "Veuillez vous connecter avant d'autoriser %s à accéder à votre compte %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Vous trouverez d'autres informations sur la configuration dans la %sdocumentation %s." },"pluralForm" :"nplurals=2; plural=(n > 1);" diff --git a/core/l10n/he.js b/core/l10n/he.js index 06645532032..5b34af12545 100644 --- a/core/l10n/he.js +++ b/core/l10n/he.js @@ -198,12 +198,8 @@ OC.L10N.register( "No users found for {search}" : "לא אותרו משתמשים עבור {search}", "An error occurred (\"{message}\"). Please try again" : "אירעה שגיאה (\"{message}\"). נא לנסות שוב", "An error occurred. Please try again" : "אירעה שגיאה. יש לנסות שנית", - "{sharee} (group)" : "{sharee} (קבוצה)", - "{sharee} (remote)" : "{sharee} (מרוחק)", "{sharee} (remote group)" : "{sharee} (קבוצה מרוחקת)", - "{sharee} (email)" : "{sharee} (דוא״ל)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (דיון)", "Share" : "שתף", "Name or email address..." : "שם או כתובת דוא״ל…", "Name or federated cloud ID..." : "שם או מזהה ענן מאוגד…", @@ -359,6 +355,9 @@ OC.L10N.register( "Error setting expiration date" : "אירעה שגיאה בעת הגדרת תאריך התפוגה", "The public link will expire no later than {days} days after it is created" : "הקישור הציבורי יפוג עד {days} ימים לאחר שנוצר", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} שותף על ידי קישור", + "{sharee} (group)" : "{sharee} (קבוצה)", + "{sharee} (remote)" : "{sharee} (מרוחק)", + "{sharee} (email)" : "{sharee} (דוא״ל)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "ניתן לשתף אחרים על ידי הקלדת משתמש או קבוצה או מזהה ענן מאוגד או כתובת דוא״ל.", "Share with other people by entering a user or group or a federated cloud ID." : "ניתן לשתף אחרים על ידי הקלדת משתמש או קבוצה או מזהה ענן מאוגד.", "Share with other people by entering a user or group or an email address." : "ניתן לשתף עם אנשים אחרים על ידי הקלדת משתמש או קבוצה או כתובת דוא״ל.", @@ -389,6 +388,7 @@ OC.L10N.register( "Back to log in" : "חזרה לכניסה", "You are about to grant %s access to your %s account." : "פעולה זו תעניק הרשאת %s לחשבון שלך ב־%s.", "Depending on your configuration, this button could also work to trust the domain:" : "בהתאם לתצורה שלך, הכפתור הזה יכול לעבוד גם כדי לתת אמון בשם המתחם:", + "{sharee} (conversation)" : "{sharee} (דיון)", "Please log in before granting %s access to your %s account." : "נא להיכנס בטרם מתן הרשאת %s לחשבון שלך ב־%s.", "Further information how to configure this can be found in the %sdocumentation%s." : "ניתן למצוא מידע נוסף כיצד להגדיר ב%sתיעוד%s." }, diff --git a/core/l10n/he.json b/core/l10n/he.json index 10a4653e898..649197398c3 100644 --- a/core/l10n/he.json +++ b/core/l10n/he.json @@ -196,12 +196,8 @@ "No users found for {search}" : "לא אותרו משתמשים עבור {search}", "An error occurred (\"{message}\"). Please try again" : "אירעה שגיאה (\"{message}\"). נא לנסות שוב", "An error occurred. Please try again" : "אירעה שגיאה. יש לנסות שנית", - "{sharee} (group)" : "{sharee} (קבוצה)", - "{sharee} (remote)" : "{sharee} (מרוחק)", "{sharee} (remote group)" : "{sharee} (קבוצה מרוחקת)", - "{sharee} (email)" : "{sharee} (דוא״ל)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (דיון)", "Share" : "שתף", "Name or email address..." : "שם או כתובת דוא״ל…", "Name or federated cloud ID..." : "שם או מזהה ענן מאוגד…", @@ -357,6 +353,9 @@ "Error setting expiration date" : "אירעה שגיאה בעת הגדרת תאריך התפוגה", "The public link will expire no later than {days} days after it is created" : "הקישור הציבורי יפוג עד {days} ימים לאחר שנוצר", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} שותף על ידי קישור", + "{sharee} (group)" : "{sharee} (קבוצה)", + "{sharee} (remote)" : "{sharee} (מרוחק)", + "{sharee} (email)" : "{sharee} (דוא״ל)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "ניתן לשתף אחרים על ידי הקלדת משתמש או קבוצה או מזהה ענן מאוגד או כתובת דוא״ל.", "Share with other people by entering a user or group or a federated cloud ID." : "ניתן לשתף אחרים על ידי הקלדת משתמש או קבוצה או מזהה ענן מאוגד.", "Share with other people by entering a user or group or an email address." : "ניתן לשתף עם אנשים אחרים על ידי הקלדת משתמש או קבוצה או כתובת דוא״ל.", @@ -387,6 +386,7 @@ "Back to log in" : "חזרה לכניסה", "You are about to grant %s access to your %s account." : "פעולה זו תעניק הרשאת %s לחשבון שלך ב־%s.", "Depending on your configuration, this button could also work to trust the domain:" : "בהתאם לתצורה שלך, הכפתור הזה יכול לעבוד גם כדי לתת אמון בשם המתחם:", + "{sharee} (conversation)" : "{sharee} (דיון)", "Please log in before granting %s access to your %s account." : "נא להיכנס בטרם מתן הרשאת %s לחשבון שלך ב־%s.", "Further information how to configure this can be found in the %sdocumentation%s." : "ניתן למצוא מידע נוסף כיצד להגדיר ב%sתיעוד%s." },"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;" diff --git a/core/l10n/hu.js b/core/l10n/hu.js index 6737eec4793..641f78aefb3 100644 --- a/core/l10n/hu.js +++ b/core/l10n/hu.js @@ -194,9 +194,6 @@ OC.L10N.register( "No users found for {search}" : "{search} keresésre nem található felhasználó", "An error occurred (\"{message}\"). Please try again" : "Hiba történt (\"{message}\"). Kérjük, próbálja meg újra! ", "An error occurred. Please try again" : "Hiba történt. Kérjük, próbálja meg újra!", - "{sharee} (group)" : "{sharee} (csoport)", - "{sharee} (remote)" : "{sharee} (távoli)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Megosztás", "Name or email address..." : "Név vagy e-mail cím...", @@ -350,6 +347,9 @@ OC.L10N.register( "Error setting expiration date" : "Nem sikerült a lejárati időt beállítani", "The public link will expire no later than {days} days after it is created" : "A nyilvános hivatkozás érvényessége legkorábban {days} nappal a létrehozása után jár csak le", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} megosztva hivatkozással", + "{sharee} (group)" : "{sharee} (csoport)", + "{sharee} (remote)" : "{sharee} (távoli)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Megosztás más emberekkel név vagy csoport, egy egységes felhőazonosító vagy e-mail cím megadásával.", "Share with other people by entering a user or group or a federated cloud ID." : "Megosztás más emberekkel felhasználó, csoport vagy egyesített felhőazonosító megadásával.", "Share with other people by entering a user or group or an email address." : "Megosztás más emberekkel név, csoport vagy e-mail cím megadásával.", diff --git a/core/l10n/hu.json b/core/l10n/hu.json index c4644231513..37152e84b68 100644 --- a/core/l10n/hu.json +++ b/core/l10n/hu.json @@ -192,9 +192,6 @@ "No users found for {search}" : "{search} keresésre nem található felhasználó", "An error occurred (\"{message}\"). Please try again" : "Hiba történt (\"{message}\"). Kérjük, próbálja meg újra! ", "An error occurred. Please try again" : "Hiba történt. Kérjük, próbálja meg újra!", - "{sharee} (group)" : "{sharee} (csoport)", - "{sharee} (remote)" : "{sharee} (távoli)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Megosztás", "Name or email address..." : "Név vagy e-mail cím...", @@ -348,6 +345,9 @@ "Error setting expiration date" : "Nem sikerült a lejárati időt beállítani", "The public link will expire no later than {days} days after it is created" : "A nyilvános hivatkozás érvényessége legkorábban {days} nappal a létrehozása után jár csak le", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} megosztva hivatkozással", + "{sharee} (group)" : "{sharee} (csoport)", + "{sharee} (remote)" : "{sharee} (távoli)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Megosztás más emberekkel név vagy csoport, egy egységes felhőazonosító vagy e-mail cím megadásával.", "Share with other people by entering a user or group or a federated cloud ID." : "Megosztás más emberekkel felhasználó, csoport vagy egyesített felhőazonosító megadásával.", "Share with other people by entering a user or group or an email address." : "Megosztás más emberekkel név, csoport vagy e-mail cím megadásával.", diff --git a/core/l10n/id.js b/core/l10n/id.js index 66ac2c6cc56..db6412940a0 100644 --- a/core/l10n/id.js +++ b/core/l10n/id.js @@ -119,9 +119,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Tidak ada pengguna atau grup ditemukan untuk {search}", "No users found for {search}" : "Tidak ada pengguna ditemukan untuk {search}", "An error occurred. Please try again" : "Terjadi kesalahan. Silakan coba lagi", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (remote)", - "{sharee} (email)" : "{sharee} (surel)", "Share" : "Bagikan", "Error" : "Kesalahan", "Error removing share" : "Terjadi kesalahan saat menghapus pembagian", @@ -222,6 +219,9 @@ OC.L10N.register( "Error setting expiration date" : "Kesalahan saat mengatur tanggal kedaluwarsa", "The public link will expire no later than {days} days after it is created" : "Tautan publik akan kadaluarsa tidak lebih dari {days} hari setelah ini dibuat", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} dibagikan lewat tautan", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (surel)", "The specified document has not been found on the server." : "Dokumen yang diminta tidak tersedia pada server.", "You can click here to return to %s." : "Anda dapat klik disini unutk kembali ke %s.", "Stay logged in" : "Tetap masuk", diff --git a/core/l10n/id.json b/core/l10n/id.json index 3fb08a344a2..8435a76b3fa 100644 --- a/core/l10n/id.json +++ b/core/l10n/id.json @@ -117,9 +117,6 @@ "No users or groups found for {search}" : "Tidak ada pengguna atau grup ditemukan untuk {search}", "No users found for {search}" : "Tidak ada pengguna ditemukan untuk {search}", "An error occurred. Please try again" : "Terjadi kesalahan. Silakan coba lagi", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (remote)", - "{sharee} (email)" : "{sharee} (surel)", "Share" : "Bagikan", "Error" : "Kesalahan", "Error removing share" : "Terjadi kesalahan saat menghapus pembagian", @@ -220,6 +217,9 @@ "Error setting expiration date" : "Kesalahan saat mengatur tanggal kedaluwarsa", "The public link will expire no later than {days} days after it is created" : "Tautan publik akan kadaluarsa tidak lebih dari {days} hari setelah ini dibuat", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} dibagikan lewat tautan", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (surel)", "The specified document has not been found on the server." : "Dokumen yang diminta tidak tersedia pada server.", "You can click here to return to %s." : "Anda dapat klik disini unutk kembali ke %s.", "Stay logged in" : "Tetap masuk", diff --git a/core/l10n/is.js b/core/l10n/is.js index 7f7d83e37c5..0b0b26b723e 100644 --- a/core/l10n/is.js +++ b/core/l10n/is.js @@ -204,12 +204,8 @@ OC.L10N.register( "No users found for {search}" : "Engir notendur fundust með {search}", "An error occurred (\"{message}\"). Please try again" : "Villa kom upp (\"{message}\"). Endilega reyndu aftur", "An error occurred. Please try again" : "Villa kom upp. Endilega reyndu aftur", - "{sharee} (group)" : "{sharee} (hópur)", - "{sharee} (remote)" : "{sharee} (fjartengdur)", "{sharee} (remote group)" : "{sharee} (fjartengdur hópur)", - "{sharee} (email)" : "{sharee} (tölvupóstur)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (samtal)", "Share" : "Deila", "Name or email address..." : "Nafn eða tölvupóstfang...", "Name or federated cloud ID..." : "Nafn eða skýjasambandsauðkenni (Federated Cloud ID)...", @@ -372,6 +368,9 @@ OC.L10N.register( "Error setting expiration date" : "Villa við að setja gildistíma", "The public link will expire no later than {days} days after it is created" : "Almenningstengillinn rennur út eigi síðar en {days} dögum eftir að hann er útbúinn", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} deildi með tengli", + "{sharee} (group)" : "{sharee} (hópur)", + "{sharee} (remote)" : "{sharee} (fjartengdur)", + "{sharee} (email)" : "{sharee} (tölvupóstur)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Deildu með öðru fólki með því að setja inn notanda, hóp, skýjasambandsauðkenni eða tölvupóstfang.", "Share with other people by entering a user or group or a federated cloud ID." : "Deildu með öðru fólki með því að setja inn notanda, hóp eða skýjasambandsauðkenni.", "Share with other people by entering a user or group or an email address." : "Deildu með öðru fólki með því að setja inn notanda, hóp eða tölvupóstfang.", @@ -403,6 +402,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Þú ert að fara að leyfa %s aðgang að %s notandaaðgangnum þínum.", "Depending on your configuration, this button could also work to trust the domain:" : "Það fer eftir stillingunum þínum, þessi hnappur gæti einnig virkað til að treysta þessu léni.", "Copy URL" : "Afrita slóð", + "{sharee} (conversation)" : "{sharee} (samtal)", "Please log in before granting %s access to your %s account." : "Skráði þig inn áður en þú leyfir %s aðgang að %s notandaaðgangnum þínum.", "Further information how to configure this can be found in the %sdocumentation%s." : "Frekari upplýsingar um hvernig hægt er að stilla þetta má finna í %shjálparskjölunum%s." }, diff --git a/core/l10n/is.json b/core/l10n/is.json index a2837609110..05092ee314c 100644 --- a/core/l10n/is.json +++ b/core/l10n/is.json @@ -202,12 +202,8 @@ "No users found for {search}" : "Engir notendur fundust með {search}", "An error occurred (\"{message}\"). Please try again" : "Villa kom upp (\"{message}\"). Endilega reyndu aftur", "An error occurred. Please try again" : "Villa kom upp. Endilega reyndu aftur", - "{sharee} (group)" : "{sharee} (hópur)", - "{sharee} (remote)" : "{sharee} (fjartengdur)", "{sharee} (remote group)" : "{sharee} (fjartengdur hópur)", - "{sharee} (email)" : "{sharee} (tölvupóstur)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (samtal)", "Share" : "Deila", "Name or email address..." : "Nafn eða tölvupóstfang...", "Name or federated cloud ID..." : "Nafn eða skýjasambandsauðkenni (Federated Cloud ID)...", @@ -370,6 +366,9 @@ "Error setting expiration date" : "Villa við að setja gildistíma", "The public link will expire no later than {days} days after it is created" : "Almenningstengillinn rennur út eigi síðar en {days} dögum eftir að hann er útbúinn", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} deildi með tengli", + "{sharee} (group)" : "{sharee} (hópur)", + "{sharee} (remote)" : "{sharee} (fjartengdur)", + "{sharee} (email)" : "{sharee} (tölvupóstur)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Deildu með öðru fólki með því að setja inn notanda, hóp, skýjasambandsauðkenni eða tölvupóstfang.", "Share with other people by entering a user or group or a federated cloud ID." : "Deildu með öðru fólki með því að setja inn notanda, hóp eða skýjasambandsauðkenni.", "Share with other people by entering a user or group or an email address." : "Deildu með öðru fólki með því að setja inn notanda, hóp eða tölvupóstfang.", @@ -401,6 +400,7 @@ "You are about to grant %s access to your %s account." : "Þú ert að fara að leyfa %s aðgang að %s notandaaðgangnum þínum.", "Depending on your configuration, this button could also work to trust the domain:" : "Það fer eftir stillingunum þínum, þessi hnappur gæti einnig virkað til að treysta þessu léni.", "Copy URL" : "Afrita slóð", + "{sharee} (conversation)" : "{sharee} (samtal)", "Please log in before granting %s access to your %s account." : "Skráði þig inn áður en þú leyfir %s aðgang að %s notandaaðgangnum þínum.", "Further information how to configure this can be found in the %sdocumentation%s." : "Frekari upplýsingar um hvernig hægt er að stilla þetta má finna í %shjálparskjölunum%s." },"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);" diff --git a/core/l10n/it.js b/core/l10n/it.js index 28682cb778c..0c502a16885 100644 --- a/core/l10n/it.js +++ b/core/l10n/it.js @@ -167,6 +167,7 @@ OC.L10N.register( "Share to {name}" : "Condividi con {name}", "Copy link" : "Copia collegamento", "Link" : "Collegamento", + "Hide download" : "Nascondi scaricamento", "Password protect" : "Proteggi con password", "Allow editing" : "Consenti la modifica", "Email link to person" : "Invia collegamento via email", @@ -210,12 +211,10 @@ OC.L10N.register( "No users found for {search}" : "Nessun utente trovato per {search}", "An error occurred (\"{message}\"). Please try again" : "Si è verificato un errore (\"{message}\"). Prova ancora", "An error occurred. Please try again" : "Si è verificato un errore. Prova ancora", - "{sharee} (group)" : "{sharee} (group)", - "{sharee} (remote)" : "{sharee} (remote)", "{sharee} (remote group)" : "{sharee} (remote group)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Home", + "Other" : "Altro", "Share" : "Condividi", "Name or email address..." : "Nome o indirizzo email...", "Name or federated cloud ID..." : "Nome o ID di cloud federata...", @@ -382,6 +381,9 @@ OC.L10N.register( "Error setting expiration date" : "Errore durante l'impostazione della data di scadenza", "The public link will expire no later than {days} days after it is created" : "Il collegamento pubblico scadrà non più tardi di {days} giorni dopo la sua creazione", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha condiviso tramite collegamento", + "{sharee} (group)" : "{sharee} (group)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Condividi con altre persone digitando un utente o un gruppo, un ID di cloud federata o un indirizzo di posta elettronica.", "Share with other people by entering a user or group or a federated cloud ID." : "Condividi con altre persone digitando un utente, un gruppo o un ID di cloud federata.", "Share with other people by entering a user or group or an email address." : "Condividi con altre persone digitando un utente, un gruppo o un indirizzo di posta elettronica.", @@ -413,6 +415,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Stai per accordare a \"%s\" l'accesso al tuo account %s.", "Depending on your configuration, this button could also work to trust the domain:" : "In base alla tua configurazione, questo pulsante può funzionare anche per rendere attendibile il dominio:", "Copy URL" : "Copia URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Accedi prima di accordare a %s l'accesso al tuo account %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Ulteriori informazioni sulla configurazione sono disponibili nella %sdocumentazione%s." }, diff --git a/core/l10n/it.json b/core/l10n/it.json index 129e9471b69..e93e3137276 100644 --- a/core/l10n/it.json +++ b/core/l10n/it.json @@ -165,6 +165,7 @@ "Share to {name}" : "Condividi con {name}", "Copy link" : "Copia collegamento", "Link" : "Collegamento", + "Hide download" : "Nascondi scaricamento", "Password protect" : "Proteggi con password", "Allow editing" : "Consenti la modifica", "Email link to person" : "Invia collegamento via email", @@ -208,12 +209,10 @@ "No users found for {search}" : "Nessun utente trovato per {search}", "An error occurred (\"{message}\"). Please try again" : "Si è verificato un errore (\"{message}\"). Prova ancora", "An error occurred. Please try again" : "Si è verificato un errore. Prova ancora", - "{sharee} (group)" : "{sharee} (group)", - "{sharee} (remote)" : "{sharee} (remote)", "{sharee} (remote group)" : "{sharee} (remote group)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Home", + "Other" : "Altro", "Share" : "Condividi", "Name or email address..." : "Nome o indirizzo email...", "Name or federated cloud ID..." : "Nome o ID di cloud federata...", @@ -380,6 +379,9 @@ "Error setting expiration date" : "Errore durante l'impostazione della data di scadenza", "The public link will expire no later than {days} days after it is created" : "Il collegamento pubblico scadrà non più tardi di {days} giorni dopo la sua creazione", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} ha condiviso tramite collegamento", + "{sharee} (group)" : "{sharee} (group)", + "{sharee} (remote)" : "{sharee} (remote)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Condividi con altre persone digitando un utente o un gruppo, un ID di cloud federata o un indirizzo di posta elettronica.", "Share with other people by entering a user or group or a federated cloud ID." : "Condividi con altre persone digitando un utente, un gruppo o un ID di cloud federata.", "Share with other people by entering a user or group or an email address." : "Condividi con altre persone digitando un utente, un gruppo o un indirizzo di posta elettronica.", @@ -411,6 +413,7 @@ "You are about to grant %s access to your %s account." : "Stai per accordare a \"%s\" l'accesso al tuo account %s.", "Depending on your configuration, this button could also work to trust the domain:" : "In base alla tua configurazione, questo pulsante può funzionare anche per rendere attendibile il dominio:", "Copy URL" : "Copia URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Accedi prima di accordare a %s l'accesso al tuo account %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Ulteriori informazioni sulla configurazione sono disponibili nella %sdocumentazione%s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/ja.js b/core/l10n/ja.js index c3eb3db054e..668748296d8 100644 --- a/core/l10n/ja.js +++ b/core/l10n/ja.js @@ -155,9 +155,6 @@ OC.L10N.register( "No users or groups found for {search}" : "{search} の検索でユーザー、グループが見つかりません", "No users found for {search}" : "{search} のユーザーはいませんでした", "An error occurred. Please try again" : "エラーが発生しました。もう一度実行してください。", - "{sharee} (group)" : "{sharee} (グループ)", - "{sharee} (remote)" : "{sharee} (リモート)", - "{sharee} (email)" : "{sharee} (メール)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "共有", "Name or email address..." : "名前またはメールアドレス", @@ -281,6 +278,9 @@ OC.L10N.register( "Error setting expiration date" : "有効期限の設定でエラー発生", "The public link will expire no later than {days} days after it is created" : "URLによる共有は、作成してから {days} 日以内に有効期限切れになります", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} がリンク経由で共有", + "{sharee} (group)" : "{sharee} (グループ)", + "{sharee} (remote)" : "{sharee} (リモート)", + "{sharee} (email)" : "{sharee} (メール)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "ユーザー名、グループ、クラウド統合ID、メールアドレスで共有", "Share with other people by entering a user or group or a federated cloud ID." : "ユーザー名、グループ、クラウド統合IDで共有", "Share with other people by entering a user or group or an email address." : "ユーザー名やグループ名、メールアドレスで共有", diff --git a/core/l10n/ja.json b/core/l10n/ja.json index 1a290bfc641..b0819cbfc32 100644 --- a/core/l10n/ja.json +++ b/core/l10n/ja.json @@ -153,9 +153,6 @@ "No users or groups found for {search}" : "{search} の検索でユーザー、グループが見つかりません", "No users found for {search}" : "{search} のユーザーはいませんでした", "An error occurred. Please try again" : "エラーが発生しました。もう一度実行してください。", - "{sharee} (group)" : "{sharee} (グループ)", - "{sharee} (remote)" : "{sharee} (リモート)", - "{sharee} (email)" : "{sharee} (メール)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "共有", "Name or email address..." : "名前またはメールアドレス", @@ -279,6 +276,9 @@ "Error setting expiration date" : "有効期限の設定でエラー発生", "The public link will expire no later than {days} days after it is created" : "URLによる共有は、作成してから {days} 日以内に有効期限切れになります", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} がリンク経由で共有", + "{sharee} (group)" : "{sharee} (グループ)", + "{sharee} (remote)" : "{sharee} (リモート)", + "{sharee} (email)" : "{sharee} (メール)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "ユーザー名、グループ、クラウド統合ID、メールアドレスで共有", "Share with other people by entering a user or group or a federated cloud ID." : "ユーザー名、グループ、クラウド統合IDで共有", "Share with other people by entering a user or group or an email address." : "ユーザー名やグループ名、メールアドレスで共有", diff --git a/core/l10n/ka_GE.js b/core/l10n/ka_GE.js index c1b5a9c3029..8b5b8a9ed69 100644 --- a/core/l10n/ka_GE.js +++ b/core/l10n/ka_GE.js @@ -169,9 +169,6 @@ OC.L10N.register( "No users or groups found for {search}" : "მომხმარებლები და ჯგუფები {search}-ისთვის არ იქნა ნაპოვნი", "No users found for {search}" : "მომხმარებლები {search}-ისთვის არ იქნა ნაპოვნი", "An error occurred. Please try again" : "წარმოიშვა შეცდომა. გთხოვთ სცადოთ ახლიდან.", - "{sharee} (group)" : "{sharee} (ჯგუფი)", - "{sharee} (remote)" : "{sharee} (დისტანციური)", - "{sharee} (email)" : "{sharee} (ელ-ფოსტა)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "გაზიარება", "Name or email address..." : "სახელი ან ელ-ფოსტის მისამართი...", @@ -315,6 +312,9 @@ OC.L10N.register( "Error setting expiration date" : "ვადის გასვლის მითითებისას წარმოიშვა შეცდომა", "The public link will expire no later than {days} days after it is created" : "საზოგადო ბმული გაუქმედება შექმნის მომენტიდან {days} დღის შემდეგ", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} მომხმარებელმა გააზიარა ბმულით", + "{sharee} (group)" : "{sharee} (ჯგუფი)", + "{sharee} (remote)" : "{sharee} (დისტანციური)", + "{sharee} (email)" : "{sharee} (ელ-ფოსტა)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "გაუზიარეთ სხვა ადამიანებს მოხმარებლის, ჯგუფის, ფედერალური ქლაუდ ID-ის ან ელ-ფოსტის მისამართის შეყვანით.", "Share with other people by entering a user or group or a federated cloud ID." : "გაუზიარეთ სხვა ადამიანებს, მომხმარებლის, ჯგუფის ან ფედერალური ქლაუდ ID-ის შეყვანით.", "Share with other people by entering a user or group or an email address." : "გაუზიარეთ სხვა ადამიანებს მომხმარებლის, ჯგუფის ან ელ-ფოსტის მისამართის შეყვანით.", diff --git a/core/l10n/ka_GE.json b/core/l10n/ka_GE.json index f85e63cf772..2e2dff3d7b4 100644 --- a/core/l10n/ka_GE.json +++ b/core/l10n/ka_GE.json @@ -167,9 +167,6 @@ "No users or groups found for {search}" : "მომხმარებლები და ჯგუფები {search}-ისთვის არ იქნა ნაპოვნი", "No users found for {search}" : "მომხმარებლები {search}-ისთვის არ იქნა ნაპოვნი", "An error occurred. Please try again" : "წარმოიშვა შეცდომა. გთხოვთ სცადოთ ახლიდან.", - "{sharee} (group)" : "{sharee} (ჯგუფი)", - "{sharee} (remote)" : "{sharee} (დისტანციური)", - "{sharee} (email)" : "{sharee} (ელ-ფოსტა)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "გაზიარება", "Name or email address..." : "სახელი ან ელ-ფოსტის მისამართი...", @@ -313,6 +310,9 @@ "Error setting expiration date" : "ვადის გასვლის მითითებისას წარმოიშვა შეცდომა", "The public link will expire no later than {days} days after it is created" : "საზოგადო ბმული გაუქმედება შექმნის მომენტიდან {days} დღის შემდეგ", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} მომხმარებელმა გააზიარა ბმულით", + "{sharee} (group)" : "{sharee} (ჯგუფი)", + "{sharee} (remote)" : "{sharee} (დისტანციური)", + "{sharee} (email)" : "{sharee} (ელ-ფოსტა)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "გაუზიარეთ სხვა ადამიანებს მოხმარებლის, ჯგუფის, ფედერალური ქლაუდ ID-ის ან ელ-ფოსტის მისამართის შეყვანით.", "Share with other people by entering a user or group or a federated cloud ID." : "გაუზიარეთ სხვა ადამიანებს, მომხმარებლის, ჯგუფის ან ფედერალური ქლაუდ ID-ის შეყვანით.", "Share with other people by entering a user or group or an email address." : "გაუზიარეთ სხვა ადამიანებს მომხმარებლის, ჯგუფის ან ელ-ფოსტის მისამართის შეყვანით.", diff --git a/core/l10n/ko.js b/core/l10n/ko.js index 3fb9985a83f..be933a3af47 100644 --- a/core/l10n/ko.js +++ b/core/l10n/ko.js @@ -185,9 +185,6 @@ OC.L10N.register( "No users or groups found for {search}" : "{search} 사용자나 그룹을 찾을 수 없음", "No users found for {search}" : "{search} 사용자를 찾을 수 없음", "An error occurred. Please try again" : "오류가 발생했습니다. 다시 시도하십시오.", - "{sharee} (group)" : "{sharee}(그룹)", - "{sharee} (remote)" : "{sharee}(원격)", - "{sharee} (email)" : "{sharee}(이메일)", "{sharee} ({type}, {owner})" : "{sharee}({type}, {owner})", "Share" : "공유", "Name or email address..." : "이름이나 이메일 주소...", @@ -331,6 +328,9 @@ OC.L10N.register( "Error setting expiration date" : "만료 날짜 설정 오류", "The public link will expire no later than {days} days after it is created" : "공개 링크를 만든 후 최대 {days}일까지 유지됩니다", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} 님이 링크를 통해 공유", + "{sharee} (group)" : "{sharee}(그룹)", + "{sharee} (remote)" : "{sharee}(원격)", + "{sharee} (email)" : "{sharee}(이메일)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "사용자나 그룹 이름, 연합 클라우드 ID 및 이메일 주소를 입력해서 다른 사람과 공유하십시오.", "Share with other people by entering a user or group or a federated cloud ID." : "사용자나 그룹 이름, 연합 클라우드 ID를 입력해서 다른 사람과 공유하십시오.", "Share with other people by entering a user or group or an email address." : "사용자나 그룹 이름 및 이메일 주소를 입력해서 다른 사람과 공유하십시오.", diff --git a/core/l10n/ko.json b/core/l10n/ko.json index 4168d836fff..abf54238118 100644 --- a/core/l10n/ko.json +++ b/core/l10n/ko.json @@ -183,9 +183,6 @@ "No users or groups found for {search}" : "{search} 사용자나 그룹을 찾을 수 없음", "No users found for {search}" : "{search} 사용자를 찾을 수 없음", "An error occurred. Please try again" : "오류가 발생했습니다. 다시 시도하십시오.", - "{sharee} (group)" : "{sharee}(그룹)", - "{sharee} (remote)" : "{sharee}(원격)", - "{sharee} (email)" : "{sharee}(이메일)", "{sharee} ({type}, {owner})" : "{sharee}({type}, {owner})", "Share" : "공유", "Name or email address..." : "이름이나 이메일 주소...", @@ -329,6 +326,9 @@ "Error setting expiration date" : "만료 날짜 설정 오류", "The public link will expire no later than {days} days after it is created" : "공개 링크를 만든 후 최대 {days}일까지 유지됩니다", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} 님이 링크를 통해 공유", + "{sharee} (group)" : "{sharee}(그룹)", + "{sharee} (remote)" : "{sharee}(원격)", + "{sharee} (email)" : "{sharee}(이메일)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "사용자나 그룹 이름, 연합 클라우드 ID 및 이메일 주소를 입력해서 다른 사람과 공유하십시오.", "Share with other people by entering a user or group or a federated cloud ID." : "사용자나 그룹 이름, 연합 클라우드 ID를 입력해서 다른 사람과 공유하십시오.", "Share with other people by entering a user or group or an email address." : "사용자나 그룹 이름 및 이메일 주소를 입력해서 다른 사람과 공유하십시오.", diff --git a/core/l10n/lt_LT.js b/core/l10n/lt_LT.js index b189c271038..cce116db616 100644 --- a/core/l10n/lt_LT.js +++ b/core/l10n/lt_LT.js @@ -156,9 +156,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Nerasta vartotojų ar grupių pagal paieškos kriterijų: {search}", "No users found for {search}" : "Nerasta vartotojų pagal paieškos kriterijų: {search}", "An error occurred. Please try again" : "Įvyko klaida. Bandykite dar kartą", - "{sharee} (group)" : "{sharee} (grupė)", - "{sharee} (remote)" : "{sharee} (nuotolinis)", - "{sharee} (email)" : "{sharee} (elektroninis paštas)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Dalintis", "Name or email address..." : "Vardas arba elektroninio pašto adresas...", @@ -283,6 +280,9 @@ OC.L10N.register( "Error setting expiration date" : "Klaida nustatant dalinimosi pabaigos laiką", "The public link will expire no later than {days} days after it is created" : "Nuoroda veiks ne mažiau kaip {days} dienas nuo sukūrimo", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} pasidalino per nuorodą", + "{sharee} (group)" : "{sharee} (grupė)", + "{sharee} (remote)" : "{sharee} (nuotolinis)", + "{sharee} (email)" : "{sharee} (elektroninis paštas)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Pasidalinti su kitais asmenimis galima įvedus vartotojo ar grupės vardą, NextCloud tinklo kompiuterio ID arba elektroninio pašto adresą.", "Share with other people by entering a user or group or a federated cloud ID." : "Pasidalinti su kitais asmenimis galima įvedus vartotojo ar grupės vardą arba NextCloud tinklo kompiuterio ID.", "Share with other people by entering a user or group or an email address." : "Pasidalinti su kitais asmenimis galima įvedus vartotojo ar grupės vardą arba elektroninio pašto adresą.", diff --git a/core/l10n/lt_LT.json b/core/l10n/lt_LT.json index 6206e0193c3..8ab546d29e5 100644 --- a/core/l10n/lt_LT.json +++ b/core/l10n/lt_LT.json @@ -154,9 +154,6 @@ "No users or groups found for {search}" : "Nerasta vartotojų ar grupių pagal paieškos kriterijų: {search}", "No users found for {search}" : "Nerasta vartotojų pagal paieškos kriterijų: {search}", "An error occurred. Please try again" : "Įvyko klaida. Bandykite dar kartą", - "{sharee} (group)" : "{sharee} (grupė)", - "{sharee} (remote)" : "{sharee} (nuotolinis)", - "{sharee} (email)" : "{sharee} (elektroninis paštas)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Dalintis", "Name or email address..." : "Vardas arba elektroninio pašto adresas...", @@ -281,6 +278,9 @@ "Error setting expiration date" : "Klaida nustatant dalinimosi pabaigos laiką", "The public link will expire no later than {days} days after it is created" : "Nuoroda veiks ne mažiau kaip {days} dienas nuo sukūrimo", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} pasidalino per nuorodą", + "{sharee} (group)" : "{sharee} (grupė)", + "{sharee} (remote)" : "{sharee} (nuotolinis)", + "{sharee} (email)" : "{sharee} (elektroninis paštas)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Pasidalinti su kitais asmenimis galima įvedus vartotojo ar grupės vardą, NextCloud tinklo kompiuterio ID arba elektroninio pašto adresą.", "Share with other people by entering a user or group or a federated cloud ID." : "Pasidalinti su kitais asmenimis galima įvedus vartotojo ar grupės vardą arba NextCloud tinklo kompiuterio ID.", "Share with other people by entering a user or group or an email address." : "Pasidalinti su kitais asmenimis galima įvedus vartotojo ar grupės vardą arba elektroninio pašto adresą.", diff --git a/core/l10n/lv.js b/core/l10n/lv.js index 48e1297cc01..ea8322bea5e 100644 --- a/core/l10n/lv.js +++ b/core/l10n/lv.js @@ -171,9 +171,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Pēc {search} netika atrasts neviens lietotājs vai grupa", "No users found for {search}" : "Pēc {search} netika atrasts neviens lietotājs", "An error occurred. Please try again" : "Notika kļūda. Mēģini vēlreiz.", - "{sharee} (group)" : "{sharee} (grupa)", - "{sharee} (remote)" : "{sharee} (attālināti)", - "{sharee} (email)" : "{sharee} (e-pasts)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Koplietot", "Name or email address..." : "Vārds vai e-pasta adrese...", @@ -297,6 +294,9 @@ OC.L10N.register( "Error setting expiration date" : "Kļūda, iestatot termiņa datumu", "The public link will expire no later than {days} days after it is created" : "Šis links beigs strādāt pēc ne vēlāk kā {days} dienām pēc tam kad tas tiks izveidots", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} koplietots ar saiti", + "{sharee} (group)" : "{sharee} (grupa)", + "{sharee} (remote)" : "{sharee} (attālināti)", + "{sharee} (email)" : "{sharee} (e-pasts)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Dalīties ar citiem cilvēkiem ievadot lietotāju, grupu, federated cloud ID vai e-pasta adresi.", "Share with other people by entering a user or group or a federated cloud ID." : "Dalīties ar citiem cilvēkiem ievadot lietotāju, grupu vai federated cloud ID.", "Share with other people by entering a user or group or an email address." : "Dalīties ar citiem cilvēkiem ievadot lietotāju, grupu vai e-pasta adresi.", diff --git a/core/l10n/lv.json b/core/l10n/lv.json index 7745e88c50a..397a6c93c6e 100644 --- a/core/l10n/lv.json +++ b/core/l10n/lv.json @@ -169,9 +169,6 @@ "No users or groups found for {search}" : "Pēc {search} netika atrasts neviens lietotājs vai grupa", "No users found for {search}" : "Pēc {search} netika atrasts neviens lietotājs", "An error occurred. Please try again" : "Notika kļūda. Mēģini vēlreiz.", - "{sharee} (group)" : "{sharee} (grupa)", - "{sharee} (remote)" : "{sharee} (attālināti)", - "{sharee} (email)" : "{sharee} (e-pasts)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Koplietot", "Name or email address..." : "Vārds vai e-pasta adrese...", @@ -295,6 +292,9 @@ "Error setting expiration date" : "Kļūda, iestatot termiņa datumu", "The public link will expire no later than {days} days after it is created" : "Šis links beigs strādāt pēc ne vēlāk kā {days} dienām pēc tam kad tas tiks izveidots", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} koplietots ar saiti", + "{sharee} (group)" : "{sharee} (grupa)", + "{sharee} (remote)" : "{sharee} (attālināti)", + "{sharee} (email)" : "{sharee} (e-pasts)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Dalīties ar citiem cilvēkiem ievadot lietotāju, grupu, federated cloud ID vai e-pasta adresi.", "Share with other people by entering a user or group or a federated cloud ID." : "Dalīties ar citiem cilvēkiem ievadot lietotāju, grupu vai federated cloud ID.", "Share with other people by entering a user or group or an email address." : "Dalīties ar citiem cilvēkiem ievadot lietotāju, grupu vai e-pasta adresi.", diff --git a/core/l10n/nb.js b/core/l10n/nb.js index b1785137d1d..05659963e02 100644 --- a/core/l10n/nb.js +++ b/core/l10n/nb.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Ingen brukere funnet for {search}", "An error occurred (\"{message}\"). Please try again" : "En feil inntraff (\"{message}\"). Prøv igjen", "An error occurred. Please try again" : "Det oppstod en feil. Prøv igjen", - "{sharee} (group)" : "{sharee} (gruppe)", - "{sharee} (remote)" : "{sharee} (ekstern)", "{sharee} (remote group)" : "{sharee} (remote group)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", "Share" : "Del", "Name or email address..." : "Navn eller e-postadresse…", "Name or federated cloud ID..." : "Navn eller sammenknyttet sky-ID…", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Kan ikke sette utløpsdato", "The public link will expire no later than {days} days after it is created" : "Den offentlige lenken vil utløpe senest {days} dager etter at den lages", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delt via lenke", + "{sharee} (group)" : "{sharee} (gruppe)", + "{sharee} (remote)" : "{sharee} (ekstern)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Del med andre ved å skrive inn en bruker, en gruppe, en sammenknyttet sky-ID eller en e-postadresse.", "Share with other people by entering a user or group or a federated cloud ID." : "Del med andre ved å skrive inn en bruker, en gruppe eller en sammenknyttet sky-ID", "Share with other people by entering a user or group or an email address." : "Del med andre ved å skrive inn en bruker, en gruppe, eller en e-postadresse.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Du er i ferd med å gi %s tilgang til din %s konto.", "Depending on your configuration, this button could also work to trust the domain:" : "Avhengig av ditt oppsett, kan denne knappen også betro domenet.", "Copy URL" : "Kopier URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Logg inn før du innvilger %s tilgang til din %s konto.", "Further information how to configure this can be found in the %sdocumentation%s." : "Ytterligere informasjon om hvordan du konfigurerer dette kan du finne i %sdokumentasjon%s." }, diff --git a/core/l10n/nb.json b/core/l10n/nb.json index 704c3dc27f7..75981eb1d71 100644 --- a/core/l10n/nb.json +++ b/core/l10n/nb.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Ingen brukere funnet for {search}", "An error occurred (\"{message}\"). Please try again" : "En feil inntraff (\"{message}\"). Prøv igjen", "An error occurred. Please try again" : "Det oppstod en feil. Prøv igjen", - "{sharee} (group)" : "{sharee} (gruppe)", - "{sharee} (remote)" : "{sharee} (ekstern)", "{sharee} (remote group)" : "{sharee} (remote group)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", "Share" : "Del", "Name or email address..." : "Navn eller e-postadresse…", "Name or federated cloud ID..." : "Navn eller sammenknyttet sky-ID…", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Kan ikke sette utløpsdato", "The public link will expire no later than {days} days after it is created" : "Den offentlige lenken vil utløpe senest {days} dager etter at den lages", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delt via lenke", + "{sharee} (group)" : "{sharee} (gruppe)", + "{sharee} (remote)" : "{sharee} (ekstern)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Del med andre ved å skrive inn en bruker, en gruppe, en sammenknyttet sky-ID eller en e-postadresse.", "Share with other people by entering a user or group or a federated cloud ID." : "Del med andre ved å skrive inn en bruker, en gruppe eller en sammenknyttet sky-ID", "Share with other people by entering a user or group or an email address." : "Del med andre ved å skrive inn en bruker, en gruppe, eller en e-postadresse.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Du er i ferd med å gi %s tilgang til din %s konto.", "Depending on your configuration, this button could also work to trust the domain:" : "Avhengig av ditt oppsett, kan denne knappen også betro domenet.", "Copy URL" : "Kopier URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : "Logg inn før du innvilger %s tilgang til din %s konto.", "Further information how to configure this can be found in the %sdocumentation%s." : "Ytterligere informasjon om hvordan du konfigurerer dette kan du finne i %sdokumentasjon%s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/nl.js b/core/l10n/nl.js index e79ab4ab6a8..6296051f8d9 100644 --- a/core/l10n/nl.js +++ b/core/l10n/nl.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Geen gebruikers gevonden voor {search}", "An error occurred (\"{message}\"). Please try again" : "Er heeft zich een fout voorgedaan (\"{message}\"). Probeer het opnieuw", "An error occurred. Please try again" : "Er trad een fout op. Probeer het opnieuw", - "{sharee} (group)" : "{sharee} (groep)", - "{sharee} (remote)" : "{sharee} (extern)", "{sharee} (remote group)" : "{sharee} (remote group)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (gesprek)", "Share" : "Delen", "Name or email address..." : "Naam of emailadres...", "Name or federated cloud ID..." : "Naam of gefedereerd Cloud ID:", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Fout tijdens het instellen van de vervaldatum", "The public link will expire no later than {days} days after it is created" : "De openbare link vervalt niet eerder dan {days} dagen na het aanmaken", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delen via link", + "{sharee} (group)" : "{sharee} (groep)", + "{sharee} (remote)" : "{sharee} (extern)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Deel met anderen door het invullen van een gebruiker, groep, gefedereerd cloud ID of een emailadres.", "Share with other people by entering a user or group or a federated cloud ID." : "Deel met anderen door middel van gebruikers, groep of een gefedereerd cloud ID.", "Share with other people by entering a user or group or an email address." : "Deel met anderen door het invullen van een gebruiker, groep of een emailadres.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Je staat op het punt om %s toegang te verlenen to je %s account.", "Depending on your configuration, this button could also work to trust the domain:" : "Afhankelijk van je configuratie kan deze knop ook werken om het volgende domein te vertrouwen:", "Copy URL" : "Kopiëren URL", + "{sharee} (conversation)" : "{sharee} (gesprek)", "Please log in before granting %s access to your %s account." : "Log alsjeblieft in voordat je %s toegang geeft tot je %s account.", "Further information how to configure this can be found in the %sdocumentation%s." : "Verdere informatie over hoe je dit insteld staat in de %s documentatie %s." }, diff --git a/core/l10n/nl.json b/core/l10n/nl.json index f4b753fe016..ef3359e4005 100644 --- a/core/l10n/nl.json +++ b/core/l10n/nl.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Geen gebruikers gevonden voor {search}", "An error occurred (\"{message}\"). Please try again" : "Er heeft zich een fout voorgedaan (\"{message}\"). Probeer het opnieuw", "An error occurred. Please try again" : "Er trad een fout op. Probeer het opnieuw", - "{sharee} (group)" : "{sharee} (groep)", - "{sharee} (remote)" : "{sharee} (extern)", "{sharee} (remote group)" : "{sharee} (remote group)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (gesprek)", "Share" : "Delen", "Name or email address..." : "Naam of emailadres...", "Name or federated cloud ID..." : "Naam of gefedereerd Cloud ID:", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Fout tijdens het instellen van de vervaldatum", "The public link will expire no later than {days} days after it is created" : "De openbare link vervalt niet eerder dan {days} dagen na het aanmaken", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delen via link", + "{sharee} (group)" : "{sharee} (groep)", + "{sharee} (remote)" : "{sharee} (extern)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Deel met anderen door het invullen van een gebruiker, groep, gefedereerd cloud ID of een emailadres.", "Share with other people by entering a user or group or a federated cloud ID." : "Deel met anderen door middel van gebruikers, groep of een gefedereerd cloud ID.", "Share with other people by entering a user or group or an email address." : "Deel met anderen door het invullen van een gebruiker, groep of een emailadres.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Je staat op het punt om %s toegang te verlenen to je %s account.", "Depending on your configuration, this button could also work to trust the domain:" : "Afhankelijk van je configuratie kan deze knop ook werken om het volgende domein te vertrouwen:", "Copy URL" : "Kopiëren URL", + "{sharee} (conversation)" : "{sharee} (gesprek)", "Please log in before granting %s access to your %s account." : "Log alsjeblieft in voordat je %s toegang geeft tot je %s account.", "Further information how to configure this can be found in the %sdocumentation%s." : "Verdere informatie over hoe je dit insteld staat in de %s documentatie %s." },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/core/l10n/pl.js b/core/l10n/pl.js index c74cda973e7..b4562c98aaf 100644 --- a/core/l10n/pl.js +++ b/core/l10n/pl.js @@ -206,12 +206,8 @@ OC.L10N.register( "No users found for {search}" : "Nie znaleziono użytkowników dla {search}", "An error occurred (\"{message}\"). Please try again" : "Wystąpił błąd (\"{message}\"). Spróbuj ponownie", "An error occurred. Please try again" : "Wystąpił błąd. Proszę spróbować ponownie.", - "{sharee} (group)" : "{sharee} (grupa)", - "{sharee} (remote)" : "{sharee} (zdalny)", "{sharee} (remote group)" : "{sharee} (zdalna grupa)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (konwersacja)", "Share" : "Udostępnij", "Name or email address..." : "Nazwa lub adres e-mail…", "Name or federated cloud ID..." : "Nazwa lub ID chmury stowarzyszonej…", @@ -370,6 +366,9 @@ OC.L10N.register( "Error setting expiration date" : "Błąd podczas ustawiania daty wygaśnięcia", "The public link will expire no later than {days} days after it is created" : "Link publiczny wygaśnie nie później niż po {days} dniach od utworzenia", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} udostępniane za pośrednictwem łącza", + "{sharee} (group)" : "{sharee} (grupa)", + "{sharee} (remote)" : "{sharee} (zdalny)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Współdziel z innymi osobami przez wpisanie użytkownika lub grupy, ID chmury stowarzyszonej lub adres e-mail.", "Share with other people by entering a user or group or a federated cloud ID." : "Współdziel z innymi osobami przez wpisanie użytkownika lub grupy lub ID chmury stowarzyszonej.", "Share with other people by entering a user or group or an email address." : "Współdziel z innymi osobami przez wpisanie użytkownika lub grupy lub adresu e-mail.", @@ -401,6 +400,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Zamierzasz udzielić %s dostępu do Twojego konta %s.", "Depending on your configuration, this button could also work to trust the domain:" : "W zależności od Twojej konfiguracji, ten przycisk aby zaufać domenie powinien również zadziałać: ", "Copy URL" : "Skopiuj URL", + "{sharee} (conversation)" : "{sharee} (konwersacja)", "Please log in before granting %s access to your %s account." : "Zaloguj się aby udzielić %s dostępu do Twojego konta %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Więcej informacji o konfiguracji znajdziesz w %sdokumentacji%s." }, diff --git a/core/l10n/pl.json b/core/l10n/pl.json index f62f1ee31f6..be0ea0f0d69 100644 --- a/core/l10n/pl.json +++ b/core/l10n/pl.json @@ -204,12 +204,8 @@ "No users found for {search}" : "Nie znaleziono użytkowników dla {search}", "An error occurred (\"{message}\"). Please try again" : "Wystąpił błąd (\"{message}\"). Spróbuj ponownie", "An error occurred. Please try again" : "Wystąpił błąd. Proszę spróbować ponownie.", - "{sharee} (group)" : "{sharee} (grupa)", - "{sharee} (remote)" : "{sharee} (zdalny)", "{sharee} (remote group)" : "{sharee} (zdalna grupa)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (konwersacja)", "Share" : "Udostępnij", "Name or email address..." : "Nazwa lub adres e-mail…", "Name or federated cloud ID..." : "Nazwa lub ID chmury stowarzyszonej…", @@ -368,6 +364,9 @@ "Error setting expiration date" : "Błąd podczas ustawiania daty wygaśnięcia", "The public link will expire no later than {days} days after it is created" : "Link publiczny wygaśnie nie później niż po {days} dniach od utworzenia", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} udostępniane za pośrednictwem łącza", + "{sharee} (group)" : "{sharee} (grupa)", + "{sharee} (remote)" : "{sharee} (zdalny)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Współdziel z innymi osobami przez wpisanie użytkownika lub grupy, ID chmury stowarzyszonej lub adres e-mail.", "Share with other people by entering a user or group or a federated cloud ID." : "Współdziel z innymi osobami przez wpisanie użytkownika lub grupy lub ID chmury stowarzyszonej.", "Share with other people by entering a user or group or an email address." : "Współdziel z innymi osobami przez wpisanie użytkownika lub grupy lub adresu e-mail.", @@ -399,6 +398,7 @@ "You are about to grant %s access to your %s account." : "Zamierzasz udzielić %s dostępu do Twojego konta %s.", "Depending on your configuration, this button could also work to trust the domain:" : "W zależności od Twojej konfiguracji, ten przycisk aby zaufać domenie powinien również zadziałać: ", "Copy URL" : "Skopiuj URL", + "{sharee} (conversation)" : "{sharee} (konwersacja)", "Please log in before granting %s access to your %s account." : "Zaloguj się aby udzielić %s dostępu do Twojego konta %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Więcej informacji o konfiguracji znajdziesz w %sdokumentacji%s." },"pluralForm" :"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);" diff --git a/core/l10n/pt_BR.js b/core/l10n/pt_BR.js index a797647db5d..db7a373647c 100644 --- a/core/l10n/pt_BR.js +++ b/core/l10n/pt_BR.js @@ -167,6 +167,7 @@ OC.L10N.register( "Share to {name}" : "Compartilhar com {name}", "Copy link" : "Copiar link", "Link" : "Link", + "Hide download" : "Ocultar download", "Password protect" : "Proteger com senha", "Allow editing" : "Permitir edição", "Email link to person" : "Enviar link por e-mail", @@ -210,12 +211,10 @@ OC.L10N.register( "No users found for {search}" : "Nenhum usuário encontrado para {search}", "An error occurred (\"{message}\"). Please try again" : "Ocorreu um erro (\"{message}\"). Tente novamente", "An error occurred. Please try again" : "Ocorreu um erro. Tente novamente", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", "{sharee} (remote group)" : "{sharee} (grupo remoto)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Home", + "Other" : "Outro", "Share" : "Compartilhar", "Name or email address..." : "Nome ou endereço de e-mail...", "Name or federated cloud ID..." : "Nome ou ID de cloud federada...", @@ -382,6 +381,9 @@ OC.L10N.register( "Error setting expiration date" : "Erro ao definir data de expiração", "The public link will expire no later than {days} days after it is created" : "O link público irá expirar não antes de {days} depois de criado", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatiorDisplayName}} compartilhou via link", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Compartilhe com outras pessoas entrando um usuário, grupo, ID de cloud federada ou um e-mail.", "Share with other people by entering a user or group or a federated cloud ID." : "Compartilhe com outras pessoas entrando um usuário, grupo ou ID de nuvem federada.", "Share with other people by entering a user or group or an email address." : "Compartilhe com outras pessoas entrando um usuário, grupo ou um e-mail.", @@ -413,6 +415,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Você está prestes a conceder acesso a %s à sua conta %s.", "Depending on your configuration, this button could also work to trust the domain:" : "Dependendo de sua configuração, este botão também pode funcionar para confiar no domínio.", "Copy URL" : "Copiar URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : " Por favor, faça o login antes de conceder %s acesso à sua %s conta.", "Further information how to configure this can be found in the %sdocumentation%s." : "Mais informações sobre configuração podem ser encontradas na %sdocumentação%s." }, diff --git a/core/l10n/pt_BR.json b/core/l10n/pt_BR.json index 319e7368521..99330296c3b 100644 --- a/core/l10n/pt_BR.json +++ b/core/l10n/pt_BR.json @@ -165,6 +165,7 @@ "Share to {name}" : "Compartilhar com {name}", "Copy link" : "Copiar link", "Link" : "Link", + "Hide download" : "Ocultar download", "Password protect" : "Proteger com senha", "Allow editing" : "Permitir edição", "Email link to person" : "Enviar link por e-mail", @@ -208,12 +209,10 @@ "No users found for {search}" : "Nenhum usuário encontrado para {search}", "An error occurred (\"{message}\"). Please try again" : "Ocorreu um erro (\"{message}\"). Tente novamente", "An error occurred. Please try again" : "Ocorreu um erro. Tente novamente", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", "{sharee} (remote group)" : "{sharee} (grupo remoto)", - "{sharee} (email)" : "{sharee} (e-mail)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (conversation)", + "Home" : "Home", + "Other" : "Outro", "Share" : "Compartilhar", "Name or email address..." : "Nome ou endereço de e-mail...", "Name or federated cloud ID..." : "Nome ou ID de cloud federada...", @@ -380,6 +379,9 @@ "Error setting expiration date" : "Erro ao definir data de expiração", "The public link will expire no later than {days} days after it is created" : "O link público irá expirar não antes de {days} depois de criado", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatiorDisplayName}} compartilhou via link", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (e-mail)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Compartilhe com outras pessoas entrando um usuário, grupo, ID de cloud federada ou um e-mail.", "Share with other people by entering a user or group or a federated cloud ID." : "Compartilhe com outras pessoas entrando um usuário, grupo ou ID de nuvem federada.", "Share with other people by entering a user or group or an email address." : "Compartilhe com outras pessoas entrando um usuário, grupo ou um e-mail.", @@ -411,6 +413,7 @@ "You are about to grant %s access to your %s account." : "Você está prestes a conceder acesso a %s à sua conta %s.", "Depending on your configuration, this button could also work to trust the domain:" : "Dependendo de sua configuração, este botão também pode funcionar para confiar no domínio.", "Copy URL" : "Copiar URL", + "{sharee} (conversation)" : "{sharee} (conversation)", "Please log in before granting %s access to your %s account." : " Por favor, faça o login antes de conceder %s acesso à sua %s conta.", "Further information how to configure this can be found in the %sdocumentation%s." : "Mais informações sobre configuração podem ser encontradas na %sdocumentação%s." },"pluralForm" :"nplurals=2; plural=(n > 1);" diff --git a/core/l10n/pt_PT.js b/core/l10n/pt_PT.js index 5e6ca82b373..5328b26d402 100644 --- a/core/l10n/pt_PT.js +++ b/core/l10n/pt_PT.js @@ -169,9 +169,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Não foram encontrados nenhuns utilizadores ou grupos para {search}", "No users found for {search}" : "Não foram encontrados utilizadores para {search}", "An error occurred. Please try again" : "Ocorreu um erro. Por favor, tente de novo.", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Partilhar", "Name or email address..." : "Nome ou endereço de email...", @@ -315,6 +312,9 @@ OC.L10N.register( "Error setting expiration date" : "Erro ao definir a data de expiração", "The public link will expire no later than {days} days after it is created" : "A hiperligação pública irá expirar, o mais tardar {days} dias depois da sua criação", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} partilhado via ligação", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Partilhar com terceiros introduzindo um nome de utilizador ou grupo, um identificador de federação ou um endereço de e-mail.", "Share with other people by entering a user or group or a federated cloud ID." : "Partilhar com terceiros introduzindo um nome de utilizador ou grupo, um ID de cloud federada ou um endereço de e-mail.", "Share with other people by entering a user or group or an email address." : "Partilhar com terceiros introduzindo um nome de utilizador ou grupo ou um endereço de e-mail.", diff --git a/core/l10n/pt_PT.json b/core/l10n/pt_PT.json index 994cad2f5ca..1ff0eabc999 100644 --- a/core/l10n/pt_PT.json +++ b/core/l10n/pt_PT.json @@ -167,9 +167,6 @@ "No users or groups found for {search}" : "Não foram encontrados nenhuns utilizadores ou grupos para {search}", "No users found for {search}" : "Não foram encontrados utilizadores para {search}", "An error occurred. Please try again" : "Ocorreu um erro. Por favor, tente de novo.", - "{sharee} (group)" : "{sharee} (grupo)", - "{sharee} (remote)" : "{sharee} (remoto)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Partilhar", "Name or email address..." : "Nome ou endereço de email...", @@ -313,6 +310,9 @@ "Error setting expiration date" : "Erro ao definir a data de expiração", "The public link will expire no later than {days} days after it is created" : "A hiperligação pública irá expirar, o mais tardar {days} dias depois da sua criação", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} partilhado via ligação", + "{sharee} (group)" : "{sharee} (grupo)", + "{sharee} (remote)" : "{sharee} (remoto)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Partilhar com terceiros introduzindo um nome de utilizador ou grupo, um identificador de federação ou um endereço de e-mail.", "Share with other people by entering a user or group or a federated cloud ID." : "Partilhar com terceiros introduzindo um nome de utilizador ou grupo, um ID de cloud federada ou um endereço de e-mail.", "Share with other people by entering a user or group or an email address." : "Partilhar com terceiros introduzindo um nome de utilizador ou grupo ou um endereço de e-mail.", diff --git a/core/l10n/ro.js b/core/l10n/ro.js index aa63b37960c..de217f61e30 100644 --- a/core/l10n/ro.js +++ b/core/l10n/ro.js @@ -150,9 +150,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Nu au fost găsiți utilizatori sau grupuri pentru {search}", "No users found for {search}" : "Nu au fost găsiți utilizatori pentru {search}", "An error occurred. Please try again" : "A apărut o eroare. Încearcă din nou", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (distanță)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Partajează", "Name or email address..." : "Nume sau adresă de email...", @@ -272,6 +269,9 @@ OC.L10N.register( "Error setting expiration date" : "Eroare la specificarea datei de expirare", "The public link will expire no later than {days} days after it is created" : "Legătura publică va expira nu mai târziu de {days} zile de la ziua creării", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} partajat prin legătura", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (distanță)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Partajează cu alte persoane prin introducerea unui utilizator sau grup, a unui ID de cloud federalizat sau a unei adrese de email.", "Share with other people by entering a user or group or a federated cloud ID." : "Partajează cu alte persoane prin introducerea unui utilizator sau grup sau a unui ID de cloud federalizat.", "Share with other people by entering a user or group or an email address." : "Partajează cu alte persoane prin introducerea unui utilizator sau grup sau a unei adrese de email.", diff --git a/core/l10n/ro.json b/core/l10n/ro.json index f6fac2234f5..d1d457aaab3 100644 --- a/core/l10n/ro.json +++ b/core/l10n/ro.json @@ -148,9 +148,6 @@ "No users or groups found for {search}" : "Nu au fost găsiți utilizatori sau grupuri pentru {search}", "No users found for {search}" : "Nu au fost găsiți utilizatori pentru {search}", "An error occurred. Please try again" : "A apărut o eroare. Încearcă din nou", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (distanță)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Partajează", "Name or email address..." : "Nume sau adresă de email...", @@ -270,6 +267,9 @@ "Error setting expiration date" : "Eroare la specificarea datei de expirare", "The public link will expire no later than {days} days after it is created" : "Legătura publică va expira nu mai târziu de {days} zile de la ziua creării", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} partajat prin legătura", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (distanță)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Partajează cu alte persoane prin introducerea unui utilizator sau grup, a unui ID de cloud federalizat sau a unei adrese de email.", "Share with other people by entering a user or group or a federated cloud ID." : "Partajează cu alte persoane prin introducerea unui utilizator sau grup sau a unui ID de cloud federalizat.", "Share with other people by entering a user or group or an email address." : "Partajează cu alte persoane prin introducerea unui utilizator sau grup sau a unei adrese de email.", diff --git a/core/l10n/ru.js b/core/l10n/ru.js index 5af259d99d1..a8e2f077b7e 100644 --- a/core/l10n/ru.js +++ b/core/l10n/ru.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Не найдено пользователей по запросу {search}", "An error occurred (\"{message}\"). Please try again" : "Произошла ошибка («{message}»). Попробуйте ещё раз", "An error occurred. Please try again" : "Произошла ошибка. Попробуйте ещё раз", - "{sharee} (group)" : "{sharee} (группа)", - "{sharee} (remote)" : "{sharee} (на другом сервере)", "{sharee} (remote group)" : "{sharee} (группа на другом сервере)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (разговор)", "Share" : "Поделиться", "Name or email address..." : "Имя или адрес email…", "Name or federated cloud ID..." : "Имя или ID межсерверного обмена…", @@ -380,6 +376,9 @@ OC.L10N.register( "Error setting expiration date" : "Ошибка при установке срока доступа", "The public link will expire no later than {days} days after it is created" : "Срок действия общедоступной ссылки истекает не позже чем через {days} дней после её создания", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} предоставил(а) доступ созданием ссылки", + "{sharee} (group)" : "{sharee} (группа)", + "{sharee} (remote)" : "{sharee} (на другом сервере)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Поделиться, указав имя пользователя или группы, ID межсерверного обмена хранилища или адрес эл. почты.", "Share with other people by entering a user or group or a federated cloud ID." : "Поделиться, указав имя пользователя или группы или ID межсерверного обмена.", "Share with other people by entering a user or group or an email address." : "Поделиться, указав имя пользователя или группы, либо адрес email.", @@ -411,6 +410,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Вы собираетесь предоставить пользователю %s доступ к вашему аккаунту %s.", "Depending on your configuration, this button could also work to trust the domain:" : "В зависимости от конфигурации, эта кнопка может сделать доверенным следующий домен:", "Copy URL" : "Копировать ссылку", + "{sharee} (conversation)" : "{sharee} (разговор)", "Please log in before granting %s access to your %s account." : "Пожалуйста, авторизуйтесь до того, как предоставить пользователю %s доступ к вашей учётной записи %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Более подробная информация о том, как это сконфигурировать, может быть найдена в %sдокументации%s." }, diff --git a/core/l10n/ru.json b/core/l10n/ru.json index da774c5ee84..637b110e596 100644 --- a/core/l10n/ru.json +++ b/core/l10n/ru.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Не найдено пользователей по запросу {search}", "An error occurred (\"{message}\"). Please try again" : "Произошла ошибка («{message}»). Попробуйте ещё раз", "An error occurred. Please try again" : "Произошла ошибка. Попробуйте ещё раз", - "{sharee} (group)" : "{sharee} (группа)", - "{sharee} (remote)" : "{sharee} (на другом сервере)", "{sharee} (remote group)" : "{sharee} (группа на другом сервере)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (разговор)", "Share" : "Поделиться", "Name or email address..." : "Имя или адрес email…", "Name or federated cloud ID..." : "Имя или ID межсерверного обмена…", @@ -378,6 +374,9 @@ "Error setting expiration date" : "Ошибка при установке срока доступа", "The public link will expire no later than {days} days after it is created" : "Срок действия общедоступной ссылки истекает не позже чем через {days} дней после её создания", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} предоставил(а) доступ созданием ссылки", + "{sharee} (group)" : "{sharee} (группа)", + "{sharee} (remote)" : "{sharee} (на другом сервере)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Поделиться, указав имя пользователя или группы, ID межсерверного обмена хранилища или адрес эл. почты.", "Share with other people by entering a user or group or a federated cloud ID." : "Поделиться, указав имя пользователя или группы или ID межсерверного обмена.", "Share with other people by entering a user or group or an email address." : "Поделиться, указав имя пользователя или группы, либо адрес email.", @@ -409,6 +408,7 @@ "You are about to grant %s access to your %s account." : "Вы собираетесь предоставить пользователю %s доступ к вашему аккаунту %s.", "Depending on your configuration, this button could also work to trust the domain:" : "В зависимости от конфигурации, эта кнопка может сделать доверенным следующий домен:", "Copy URL" : "Копировать ссылку", + "{sharee} (conversation)" : "{sharee} (разговор)", "Please log in before granting %s access to your %s account." : "Пожалуйста, авторизуйтесь до того, как предоставить пользователю %s доступ к вашей учётной записи %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Более подробная информация о том, как это сконфигурировать, может быть найдена в %sдокументации%s." },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" diff --git a/core/l10n/sk.js b/core/l10n/sk.js index 9a66d5e379e..d4e68d0216b 100644 --- a/core/l10n/sk.js +++ b/core/l10n/sk.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Výrazu {search} nezodpovedá žiadny používateľ", "An error occurred (\"{message}\"). Please try again" : "Nastala chyba (\"{message}\"). Prosím, skúste znova", "An error occurred. Please try again" : "Nastala chyba. Skúste to prosím znovu", - "{sharee} (group)" : "{sharee} (skupina)", - "{sharee} (remote)" : "{sharee} (vzdialene)", "{sharee} (remote group)" : "{sharee} (vzdialená skupina)", - "{sharee} (email)" : "{sharee} (pošta)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (rozhovor)", "Share" : "Sprístupniť", "Name or email address..." : "Meno alebo e-mailová adresa...", "Name or federated cloud ID..." : "Meno alebo federatívny cloud ID...", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Chyba pri nastavení dátumu expirácie", "The public link will expire no later than {days} days after it is created" : "Verejný odkaz nevyprší skôr než za {days} dní po vytvorení", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} zdieľal pomocou odkazu", + "{sharee} (group)" : "{sharee} (skupina)", + "{sharee} (remote)" : "{sharee} (vzdialene)", + "{sharee} (email)" : "{sharee} (pošta)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Sprístupniť iným ľuďom zadaním používateľa alebo skupiny, federatívneho cloud ID alebo e-mailovej adresy.", "Share with other people by entering a user or group or a federated cloud ID." : "Sprístupniť iným ľuďom zadaním používateľa alebo skupiny, federatívneho cloud ID.", "Share with other people by entering a user or group or an email address." : "Sprístupniť iným ľuďom zadaním používateľa, skupiny alebo e-mailovej adresy.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Chystáte sa udeliť %s prístup k svojmu %s účtu.", "Depending on your configuration, this button could also work to trust the domain:" : "V závislosti od vašej konfigurácie by toto tlačidlo mohlo fungovať tak, že dôverujete doméne:", "Copy URL" : "Kopírovať URL", + "{sharee} (conversation)" : "{sharee} (rozhovor)", "Please log in before granting %s access to your %s account." : "Skôr než udelíte prístup pre %s do vášho účtu %s je potrebné sa prihlásiť.", "Further information how to configure this can be found in the %sdocumentation%s." : "Viac informácií o konfigurácii je možné nájsť v %sdokumentácii%s." }, diff --git a/core/l10n/sk.json b/core/l10n/sk.json index d6c86110020..12cfddd9888 100644 --- a/core/l10n/sk.json +++ b/core/l10n/sk.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Výrazu {search} nezodpovedá žiadny používateľ", "An error occurred (\"{message}\"). Please try again" : "Nastala chyba (\"{message}\"). Prosím, skúste znova", "An error occurred. Please try again" : "Nastala chyba. Skúste to prosím znovu", - "{sharee} (group)" : "{sharee} (skupina)", - "{sharee} (remote)" : "{sharee} (vzdialene)", "{sharee} (remote group)" : "{sharee} (vzdialená skupina)", - "{sharee} (email)" : "{sharee} (pošta)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (rozhovor)", "Share" : "Sprístupniť", "Name or email address..." : "Meno alebo e-mailová adresa...", "Name or federated cloud ID..." : "Meno alebo federatívny cloud ID...", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Chyba pri nastavení dátumu expirácie", "The public link will expire no later than {days} days after it is created" : "Verejný odkaz nevyprší skôr než za {days} dní po vytvorení", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} zdieľal pomocou odkazu", + "{sharee} (group)" : "{sharee} (skupina)", + "{sharee} (remote)" : "{sharee} (vzdialene)", + "{sharee} (email)" : "{sharee} (pošta)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Sprístupniť iným ľuďom zadaním používateľa alebo skupiny, federatívneho cloud ID alebo e-mailovej adresy.", "Share with other people by entering a user or group or a federated cloud ID." : "Sprístupniť iným ľuďom zadaním používateľa alebo skupiny, federatívneho cloud ID.", "Share with other people by entering a user or group or an email address." : "Sprístupniť iným ľuďom zadaním používateľa, skupiny alebo e-mailovej adresy.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Chystáte sa udeliť %s prístup k svojmu %s účtu.", "Depending on your configuration, this button could also work to trust the domain:" : "V závislosti od vašej konfigurácie by toto tlačidlo mohlo fungovať tak, že dôverujete doméne:", "Copy URL" : "Kopírovať URL", + "{sharee} (conversation)" : "{sharee} (rozhovor)", "Please log in before granting %s access to your %s account." : "Skôr než udelíte prístup pre %s do vášho účtu %s je potrebné sa prihlásiť.", "Further information how to configure this can be found in the %sdocumentation%s." : "Viac informácií o konfigurácii je možné nájsť v %sdokumentácii%s." },"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);" diff --git a/core/l10n/sl.js b/core/l10n/sl.js index 1a6bf3a645e..0b8772f9b2c 100644 --- a/core/l10n/sl.js +++ b/core/l10n/sl.js @@ -152,9 +152,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Ni najdenih uporabnikov ali skupin za {search}", "No users found for {search}" : "Ni uporabnikov, skladnih z iskalnim nizom {search}", "An error occurred. Please try again" : "Prišlo je do napake. Poskusite znova.", - "{sharee} (group)" : "{sharee} (skupina)", - "{sharee} (remote)" : "{sharee} (oddaljeno)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Souporaba", "Name or email address..." : "Ime ali e-poštni naslov...", @@ -265,6 +262,9 @@ OC.L10N.register( "Updated \"%s\" to %s" : "Datoteka \"%s\" je posodobljena na %s", "Error setting expiration date" : "Napaka nastavljanja datuma preteka", "The public link will expire no later than {days} days after it is created" : "Javna povezava bo potekla {days} dni po ustvarjanju.", + "{sharee} (group)" : "{sharee} (skupina)", + "{sharee} (remote)" : "{sharee} (oddaljeno)", + "{sharee} (email)" : "{sharee} (email)", "The specified document has not been found on the server." : "Določenega dokumenta na strežniku ni mogoče najti.", "You can click here to return to %s." : "S klikom na povezavo boste vrnjeni na %s.", "Wrong password. Reset it?" : "Napačno geslo. Ali ga želite ponastaviti?", diff --git a/core/l10n/sl.json b/core/l10n/sl.json index 15ffbd56712..662667a7dd6 100644 --- a/core/l10n/sl.json +++ b/core/l10n/sl.json @@ -150,9 +150,6 @@ "No users or groups found for {search}" : "Ni najdenih uporabnikov ali skupin za {search}", "No users found for {search}" : "Ni uporabnikov, skladnih z iskalnim nizom {search}", "An error occurred. Please try again" : "Prišlo je do napake. Poskusite znova.", - "{sharee} (group)" : "{sharee} (skupina)", - "{sharee} (remote)" : "{sharee} (oddaljeno)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Souporaba", "Name or email address..." : "Ime ali e-poštni naslov...", @@ -263,6 +260,9 @@ "Updated \"%s\" to %s" : "Datoteka \"%s\" je posodobljena na %s", "Error setting expiration date" : "Napaka nastavljanja datuma preteka", "The public link will expire no later than {days} days after it is created" : "Javna povezava bo potekla {days} dni po ustvarjanju.", + "{sharee} (group)" : "{sharee} (skupina)", + "{sharee} (remote)" : "{sharee} (oddaljeno)", + "{sharee} (email)" : "{sharee} (email)", "The specified document has not been found on the server." : "Določenega dokumenta na strežniku ni mogoče najti.", "You can click here to return to %s." : "S klikom na povezavo boste vrnjeni na %s.", "Wrong password. Reset it?" : "Napačno geslo. Ali ga želite ponastaviti?", diff --git a/core/l10n/sq.js b/core/l10n/sq.js index f67d4ff4646..1375211f79e 100644 --- a/core/l10n/sq.js +++ b/core/l10n/sq.js @@ -153,9 +153,6 @@ OC.L10N.register( "No users or groups found for {search}" : "S’u gjetën përdorues ose grupe për {search}", "No users found for {search}" : "S’u gjet përdorues për {search}", "An error occurred. Please try again" : "Ndodhi një gabim. Ju lutemi, riprovoni", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (i largët)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Ndaje", "Name or email address..." : "Emri ose adresa e email-it", @@ -277,6 +274,9 @@ OC.L10N.register( "Error setting expiration date" : "Gabim në caktimin e datës së skadimit", "The public link will expire no later than {days} days after it is created" : "Lidhja publike do të skadojë jo më vonë se {days} ditë pas krijimit të saj", "{{shareInitiatorDisplayName}} shared via link" : "{{shpërndaEmrinEShfaqurTëNismëtarit}} shpërnda nëpërmjet linkut", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (i largët)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Shpërndaje me persona të tjerë duke vendosur një përdorues ose një grup, një ID reje të federuar ose një adresë emaili", "Share with other people by entering a user or group or a federated cloud ID." : "Ndaj me njerëz të tjerë duke futur një pëdorues ose grup ose një ID reje federale.", "Share with other people by entering a user or group or an email address." : "Shpërndaje me persona të tjerë duke vendosur një perdorues ose një grup ose një adresë emaili", diff --git a/core/l10n/sq.json b/core/l10n/sq.json index 216537139b5..0085599091e 100644 --- a/core/l10n/sq.json +++ b/core/l10n/sq.json @@ -151,9 +151,6 @@ "No users or groups found for {search}" : "S’u gjetën përdorues ose grupe për {search}", "No users found for {search}" : "S’u gjet përdorues për {search}", "An error occurred. Please try again" : "Ndodhi një gabim. Ju lutemi, riprovoni", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (i largët)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Ndaje", "Name or email address..." : "Emri ose adresa e email-it", @@ -275,6 +272,9 @@ "Error setting expiration date" : "Gabim në caktimin e datës së skadimit", "The public link will expire no later than {days} days after it is created" : "Lidhja publike do të skadojë jo më vonë se {days} ditë pas krijimit të saj", "{{shareInitiatorDisplayName}} shared via link" : "{{shpërndaEmrinEShfaqurTëNismëtarit}} shpërnda nëpërmjet linkut", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (i largët)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Shpërndaje me persona të tjerë duke vendosur një përdorues ose një grup, një ID reje të federuar ose një adresë emaili", "Share with other people by entering a user or group or a federated cloud ID." : "Ndaj me njerëz të tjerë duke futur një pëdorues ose grup ose një ID reje federale.", "Share with other people by entering a user or group or an email address." : "Shpërndaje me persona të tjerë duke vendosur një perdorues ose një grup ose një adresë emaili", diff --git a/core/l10n/sr.js b/core/l10n/sr.js index 1d371ee480b..6302fb88b77 100644 --- a/core/l10n/sr.js +++ b/core/l10n/sr.js @@ -210,12 +210,8 @@ OC.L10N.register( "No users found for {search}" : "Није нађен ниједан корисник за претрагу {search}", "An error occurred (\"{message}\"). Please try again" : "Десила се грешка (\"{message}\"). Покушајте поново.", "An error occurred. Please try again" : "Дошло је до грешке. Покушајте поново", - "{sharee} (group)" : "{sharee} (група)", - "{sharee} (remote)" : "{sharee} (удаљено)", "{sharee} (remote group)" : "{sharee} (удаљена група)", - "{sharee} (email)" : "{sharee} (е-пошта)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (разговор)", "Share" : "Дели", "Name or email address..." : "Име или адреса е-поште...", "Name or federated cloud ID..." : "Име или ID здруженог облака...", @@ -382,6 +378,9 @@ OC.L10N.register( "Error setting expiration date" : "Грешка при постављању датума истека", "The public link will expire no later than {days} days after it is created" : "Јавна веза ће престати да важи {days} дана након стварања", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} је поделио преко везе", + "{sharee} (group)" : "{sharee} (група)", + "{sharee} (remote)" : "{sharee} (удаљено)", + "{sharee} (email)" : "{sharee} (е-пошта)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Делите са другим људима тако што унесете корисника, групу, ID здруженог облака или адресу е-поште. ", "Share with other people by entering a user or group or a federated cloud ID." : "Делите са другим људима тако што унесете корисника, групу или ID здруженог облака.", "Share with other people by entering a user or group or an email address." : "Делите са другим људима тако што унесете корисника или групу.", @@ -413,6 +412,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "Управо ћете одобрити %s приступ Вашем %s налогу.", "Depending on your configuration, this button could also work to trust the domain:" : "У зависности од Ваше конфигурације, овим дугметом може да послужи да почнете да верујете овом домену:", "Copy URL" : "Копирај URL", + "{sharee} (conversation)" : "{sharee} (разговор)", "Please log in before granting %s access to your %s account." : "Прво се пријавите пре него што одобрите привилегију %s приступ Вашем налогу %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Више информација о томе како ово подесити можете да нађете у %s документацији%s." }, diff --git a/core/l10n/sr.json b/core/l10n/sr.json index f6a3c9a2ed4..11245f5bcf4 100644 --- a/core/l10n/sr.json +++ b/core/l10n/sr.json @@ -208,12 +208,8 @@ "No users found for {search}" : "Није нађен ниједан корисник за претрагу {search}", "An error occurred (\"{message}\"). Please try again" : "Десила се грешка (\"{message}\"). Покушајте поново.", "An error occurred. Please try again" : "Дошло је до грешке. Покушајте поново", - "{sharee} (group)" : "{sharee} (група)", - "{sharee} (remote)" : "{sharee} (удаљено)", "{sharee} (remote group)" : "{sharee} (удаљена група)", - "{sharee} (email)" : "{sharee} (е-пошта)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (разговор)", "Share" : "Дели", "Name or email address..." : "Име или адреса е-поште...", "Name or federated cloud ID..." : "Име или ID здруженог облака...", @@ -380,6 +376,9 @@ "Error setting expiration date" : "Грешка при постављању датума истека", "The public link will expire no later than {days} days after it is created" : "Јавна веза ће престати да важи {days} дана након стварања", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} је поделио преко везе", + "{sharee} (group)" : "{sharee} (група)", + "{sharee} (remote)" : "{sharee} (удаљено)", + "{sharee} (email)" : "{sharee} (е-пошта)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Делите са другим људима тако што унесете корисника, групу, ID здруженог облака или адресу е-поште. ", "Share with other people by entering a user or group or a federated cloud ID." : "Делите са другим људима тако што унесете корисника, групу или ID здруженог облака.", "Share with other people by entering a user or group or an email address." : "Делите са другим људима тако што унесете корисника или групу.", @@ -411,6 +410,7 @@ "You are about to grant %s access to your %s account." : "Управо ћете одобрити %s приступ Вашем %s налогу.", "Depending on your configuration, this button could also work to trust the domain:" : "У зависности од Ваше конфигурације, овим дугметом може да послужи да почнете да верујете овом домену:", "Copy URL" : "Копирај URL", + "{sharee} (conversation)" : "{sharee} (разговор)", "Please log in before granting %s access to your %s account." : "Прво се пријавите пре него што одобрите привилегију %s приступ Вашем налогу %s.", "Further information how to configure this can be found in the %sdocumentation%s." : "Више информација о томе како ово подесити можете да нађете у %s документацији%s." },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" diff --git a/core/l10n/sv.js b/core/l10n/sv.js index f48fc60e087..4a3299422e5 100644 --- a/core/l10n/sv.js +++ b/core/l10n/sv.js @@ -170,9 +170,6 @@ OC.L10N.register( "No users found for {search}" : "Inga användare funna för {search}", "An error occurred (\"{message}\"). Please try again" : "Ett fel uppstod (\"{message}\"). Försök igen", "An error occurred. Please try again" : "Ett fel uppstod. Vänligen försök igen", - "{sharee} (group)" : "{sharee} (grupp)", - "{sharee} (remote)" : "{sharee} (externt)", - "{sharee} (email)" : "{sharee} (e-post)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Dela", "Name or email address..." : "Namn eller e-postadress", @@ -322,6 +319,9 @@ OC.L10N.register( "Error setting expiration date" : "Fel vid val av utgångsdatum", "The public link will expire no later than {days} days after it is created" : "Den offentliga länken kommer sluta gälla inte senare än {days} dagar efter att den skapades", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delad via länk", + "{sharee} (group)" : "{sharee} (grupp)", + "{sharee} (remote)" : "{sharee} (externt)", + "{sharee} (email)" : "{sharee} (e-post)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Dela med andra personer genom att ange användarnamn, grupp, ett federerat moln-ID eller en e-postadress.", "Share with other people by entering a user or group or a federated cloud ID." : "Dela med andra personer genom att ange användarnamn, grupp eller ett federerat moln-ID.", "Share with other people by entering a user or group or an email address." : "Dela med andra personer genom att ange användarnamn, grupp eller en e-postadress.", diff --git a/core/l10n/sv.json b/core/l10n/sv.json index 2d20e804a8d..5a8c4dc866f 100644 --- a/core/l10n/sv.json +++ b/core/l10n/sv.json @@ -168,9 +168,6 @@ "No users found for {search}" : "Inga användare funna för {search}", "An error occurred (\"{message}\"). Please try again" : "Ett fel uppstod (\"{message}\"). Försök igen", "An error occurred. Please try again" : "Ett fel uppstod. Vänligen försök igen", - "{sharee} (group)" : "{sharee} (grupp)", - "{sharee} (remote)" : "{sharee} (externt)", - "{sharee} (email)" : "{sharee} (e-post)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Dela", "Name or email address..." : "Namn eller e-postadress", @@ -320,6 +317,9 @@ "Error setting expiration date" : "Fel vid val av utgångsdatum", "The public link will expire no later than {days} days after it is created" : "Den offentliga länken kommer sluta gälla inte senare än {days} dagar efter att den skapades", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} delad via länk", + "{sharee} (group)" : "{sharee} (grupp)", + "{sharee} (remote)" : "{sharee} (externt)", + "{sharee} (email)" : "{sharee} (e-post)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Dela med andra personer genom att ange användarnamn, grupp, ett federerat moln-ID eller en e-postadress.", "Share with other people by entering a user or group or a federated cloud ID." : "Dela med andra personer genom att ange användarnamn, grupp eller ett federerat moln-ID.", "Share with other people by entering a user or group or an email address." : "Dela med andra personer genom att ange användarnamn, grupp eller en e-postadress.", diff --git a/core/l10n/tr.js b/core/l10n/tr.js index e5c85dfc7a6..080a6bc46f8 100644 --- a/core/l10n/tr.js +++ b/core/l10n/tr.js @@ -167,6 +167,7 @@ OC.L10N.register( "Share to {name}" : "{name} ile paylaş", "Copy link" : "Bağlantıyı kopyala", "Link" : "Bağlantı", + "Hide download" : "İndirmeyi gizle", "Password protect" : "Parola koruması", "Allow editing" : "Düzenlenebilsin", "Email link to person" : "Bağlantıyı e-posta ile gönder", @@ -210,12 +211,10 @@ OC.L10N.register( "No users found for {search}" : "{search} araması sonucunda uygun bir kullanıcı bulunamadı", "An error occurred (\"{message}\"). Please try again" : "Bir sorun çıktı (\"{message}\"). Lütfen yeniden deneyin.", "An error occurred. Please try again" : "Bir sorun çıktı. Lütfen yeniden deneyin", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (uzak)", "{sharee} (remote group)" : "{sharee} (uzak grup)", - "{sharee} (email)" : "{sharee} (e-posta)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (görüşme)", + "Home" : "Giriş", + "Other" : "Diğer", "Share" : "Paylaş", "Name or email address..." : "Ad ya da e-posta adresi...", "Name or federated cloud ID..." : "Ad ya da birleşmiş bulut kodu...", @@ -382,6 +381,9 @@ OC.L10N.register( "Error setting expiration date" : "Son kullanma tarihi ayarlanırken sorun çıktı", "The public link will expire no later than {days} days after it is created" : "Herkese açık bağlantı, oluşturulduktan {days} gün sonra kullanımdan kaldırılacak", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} bağlantı ile paylaşılmış", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (uzak)", + "{sharee} (email)" : "{sharee} (e-posta)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Bir kullanıcı, grup, birleşmiş bulut kodu ya da e-posta adresi yazarak başkaları ile paylaşın.", "Share with other people by entering a user or group or a federated cloud ID." : "Bir kullanıcı, grup ya da birleşmiş bulut kodu yazarak başkaları ile paylaşın.", "Share with other people by entering a user or group or an email address." : "Bir kullanıcı, grup ya da e-posta adresi yazarak başkaları ile paylaşın.", @@ -413,6 +415,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "%s erişim iznini %s hesabınız için vermek üzeresiniz.", "Depending on your configuration, this button could also work to trust the domain:" : "Yapılandırmanıza bağlı olarak, bu düğme etki alanına güvenmek için de kullanılabilir:", "Copy URL" : "Adresi Kopyala", + "{sharee} (conversation)" : "{sharee} (görüşme)", "Please log in before granting %s access to your %s account." : "Lütfen %s erişim izni %s vermeden önce oturum açın.", "Further information how to configure this can be found in the %sdocumentation%s." : "Bu ayar ile ilgili ayrıntılı bilgi almak için %sbelgelere%s bakabilirsiniz." }, diff --git a/core/l10n/tr.json b/core/l10n/tr.json index a97bd488941..fb66979b76f 100644 --- a/core/l10n/tr.json +++ b/core/l10n/tr.json @@ -165,6 +165,7 @@ "Share to {name}" : "{name} ile paylaş", "Copy link" : "Bağlantıyı kopyala", "Link" : "Bağlantı", + "Hide download" : "İndirmeyi gizle", "Password protect" : "Parola koruması", "Allow editing" : "Düzenlenebilsin", "Email link to person" : "Bağlantıyı e-posta ile gönder", @@ -208,12 +209,10 @@ "No users found for {search}" : "{search} araması sonucunda uygun bir kullanıcı bulunamadı", "An error occurred (\"{message}\"). Please try again" : "Bir sorun çıktı (\"{message}\"). Lütfen yeniden deneyin.", "An error occurred. Please try again" : "Bir sorun çıktı. Lütfen yeniden deneyin", - "{sharee} (group)" : "{sharee} (grup)", - "{sharee} (remote)" : "{sharee} (uzak)", "{sharee} (remote group)" : "{sharee} (uzak grup)", - "{sharee} (email)" : "{sharee} (e-posta)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (görüşme)", + "Home" : "Giriş", + "Other" : "Diğer", "Share" : "Paylaş", "Name or email address..." : "Ad ya da e-posta adresi...", "Name or federated cloud ID..." : "Ad ya da birleşmiş bulut kodu...", @@ -380,6 +379,9 @@ "Error setting expiration date" : "Son kullanma tarihi ayarlanırken sorun çıktı", "The public link will expire no later than {days} days after it is created" : "Herkese açık bağlantı, oluşturulduktan {days} gün sonra kullanımdan kaldırılacak", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} bağlantı ile paylaşılmış", + "{sharee} (group)" : "{sharee} (grup)", + "{sharee} (remote)" : "{sharee} (uzak)", + "{sharee} (email)" : "{sharee} (e-posta)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Bir kullanıcı, grup, birleşmiş bulut kodu ya da e-posta adresi yazarak başkaları ile paylaşın.", "Share with other people by entering a user or group or a federated cloud ID." : "Bir kullanıcı, grup ya da birleşmiş bulut kodu yazarak başkaları ile paylaşın.", "Share with other people by entering a user or group or an email address." : "Bir kullanıcı, grup ya da e-posta adresi yazarak başkaları ile paylaşın.", @@ -411,6 +413,7 @@ "You are about to grant %s access to your %s account." : "%s erişim iznini %s hesabınız için vermek üzeresiniz.", "Depending on your configuration, this button could also work to trust the domain:" : "Yapılandırmanıza bağlı olarak, bu düğme etki alanına güvenmek için de kullanılabilir:", "Copy URL" : "Adresi Kopyala", + "{sharee} (conversation)" : "{sharee} (görüşme)", "Please log in before granting %s access to your %s account." : "Lütfen %s erişim izni %s vermeden önce oturum açın.", "Further information how to configure this can be found in the %sdocumentation%s." : "Bu ayar ile ilgili ayrıntılı bilgi almak için %sbelgelere%s bakabilirsiniz." },"pluralForm" :"nplurals=2; plural=(n > 1);" diff --git a/core/l10n/uk.js b/core/l10n/uk.js index c5013f0ae59..d6d44f57788 100644 --- a/core/l10n/uk.js +++ b/core/l10n/uk.js @@ -152,9 +152,6 @@ OC.L10N.register( "No users or groups found for {search}" : "Не знайдено груп або користувачів за пошуком {search}", "No users found for {search}" : "Не знайдено жодного користувача для {search}", "An error occurred. Please try again" : "Сталася помилка. Спробуйте ще раз", - "{sharee} (group)" : "{sharee} (група)", - "{sharee} (remote)" : "{sharee} (віддалений)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Поділитися", "Name or email address..." : "Ім'я або адреса електронної пошти...", @@ -259,6 +256,9 @@ OC.L10N.register( "Updated \"%s\" to %s" : "Оновлено \"%s\" до %s", "Error setting expiration date" : "Помилка при встановленні терміну дії", "The public link will expire no later than {days} days after it is created" : "Доступ до опублікованого посилання буде припинено не пізніше ніж через {days} днів з моменту створення", + "{sharee} (group)" : "{sharee} (група)", + "{sharee} (remote)" : "{sharee} (віддалений)", + "{sharee} (email)" : "{sharee} (email)", "The specified document has not been found on the server." : "Не вдалось знайти вказаний документ на сервері.", "You can click here to return to %s." : "Ви можете натиснути тут для повернення до %s.", "Wrong password. Reset it?" : "Невірний пароль. Скинути його?", diff --git a/core/l10n/uk.json b/core/l10n/uk.json index 5eb7b3b93c2..af612818e9f 100644 --- a/core/l10n/uk.json +++ b/core/l10n/uk.json @@ -150,9 +150,6 @@ "No users or groups found for {search}" : "Не знайдено груп або користувачів за пошуком {search}", "No users found for {search}" : "Не знайдено жодного користувача для {search}", "An error occurred. Please try again" : "Сталася помилка. Спробуйте ще раз", - "{sharee} (group)" : "{sharee} (група)", - "{sharee} (remote)" : "{sharee} (віддалений)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Поділитися", "Name or email address..." : "Ім'я або адреса електронної пошти...", @@ -257,6 +254,9 @@ "Updated \"%s\" to %s" : "Оновлено \"%s\" до %s", "Error setting expiration date" : "Помилка при встановленні терміну дії", "The public link will expire no later than {days} days after it is created" : "Доступ до опублікованого посилання буде припинено не пізніше ніж через {days} днів з моменту створення", + "{sharee} (group)" : "{sharee} (група)", + "{sharee} (remote)" : "{sharee} (віддалений)", + "{sharee} (email)" : "{sharee} (email)", "The specified document has not been found on the server." : "Не вдалось знайти вказаний документ на сервері.", "You can click here to return to %s." : "Ви можете натиснути тут для повернення до %s.", "Wrong password. Reset it?" : "Невірний пароль. Скинути його?", diff --git a/core/l10n/vi.js b/core/l10n/vi.js index a6615109218..16882d7cc7d 100644 --- a/core/l10n/vi.js +++ b/core/l10n/vi.js @@ -159,9 +159,6 @@ OC.L10N.register( "No users found for {search}" : "Không tìm thấy người dùng cho {search}", "An error occurred (\"{message}\"). Please try again" : "Đã xảy ra lỗi (\"{message}\"). Hãy thử lại", "An error occurred. Please try again" : "Có lỗi vừa xảy ra. Xin vui lòng thử lại", - "{sharee} (group)" : "{sharee} (nhóm)", - "{sharee} (remote)" : "{sharee} (từ xa)", - "{sharee} (email)" : "{sharee} (thư điện tử)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Chia sẻ", "Name or email address..." : "Tên hoặc địa chỉ email.", @@ -292,6 +289,9 @@ OC.L10N.register( "Error setting expiration date" : "Lỗi cấu hình ngày kết thúc", "The public link will expire no later than {days} days after it is created" : "Liên kết công khai sẽ hết hạn sau {days} ngày sau khi được tạo", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} chia sẻ qua liên kết", + "{sharee} (group)" : "{sharee} (nhóm)", + "{sharee} (remote)" : "{sharee} (từ xa)", + "{sharee} (email)" : "{sharee} (thư điện tử)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Chia sẻ với người khác bằng cách nhập tên người dùng hoặc tên nhóm, ID đám mây liên kết hoặc địa chỉ email.", "Share with other people by entering a user or group or a federated cloud ID." : "Chia sẻ với người khác bằng cách nhập tên người dùng hoặc tên nhóm, ID đám mây liên kết.", "Share with other people by entering a user or group or an email address." : "Chia sẻ với người khác bằng cách nhập tên người dùng hoặc tên nhóm, hoặc địa chỉ email.", diff --git a/core/l10n/vi.json b/core/l10n/vi.json index cee3000c91a..ff500a839b4 100644 --- a/core/l10n/vi.json +++ b/core/l10n/vi.json @@ -157,9 +157,6 @@ "No users found for {search}" : "Không tìm thấy người dùng cho {search}", "An error occurred (\"{message}\"). Please try again" : "Đã xảy ra lỗi (\"{message}\"). Hãy thử lại", "An error occurred. Please try again" : "Có lỗi vừa xảy ra. Xin vui lòng thử lại", - "{sharee} (group)" : "{sharee} (nhóm)", - "{sharee} (remote)" : "{sharee} (từ xa)", - "{sharee} (email)" : "{sharee} (thư điện tử)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", "Share" : "Chia sẻ", "Name or email address..." : "Tên hoặc địa chỉ email.", @@ -290,6 +287,9 @@ "Error setting expiration date" : "Lỗi cấu hình ngày kết thúc", "The public link will expire no later than {days} days after it is created" : "Liên kết công khai sẽ hết hạn sau {days} ngày sau khi được tạo", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} chia sẻ qua liên kết", + "{sharee} (group)" : "{sharee} (nhóm)", + "{sharee} (remote)" : "{sharee} (từ xa)", + "{sharee} (email)" : "{sharee} (thư điện tử)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "Chia sẻ với người khác bằng cách nhập tên người dùng hoặc tên nhóm, ID đám mây liên kết hoặc địa chỉ email.", "Share with other people by entering a user or group or a federated cloud ID." : "Chia sẻ với người khác bằng cách nhập tên người dùng hoặc tên nhóm, ID đám mây liên kết.", "Share with other people by entering a user or group or an email address." : "Chia sẻ với người khác bằng cách nhập tên người dùng hoặc tên nhóm, hoặc địa chỉ email.", diff --git a/core/l10n/zh_CN.js b/core/l10n/zh_CN.js index ca39729ad29..815c457edf9 100644 --- a/core/l10n/zh_CN.js +++ b/core/l10n/zh_CN.js @@ -209,12 +209,8 @@ OC.L10N.register( "No users found for {search}" : "没有找到 {search} 用户", "An error occurred (\"{message}\"). Please try again" : "发生错误 (\"{message}\"). 请重试", "An error occurred. Please try again" : "发生错误. 请重试", - "{sharee} (group)" : "{sharee} (分组)", - "{sharee} (remote)" : "{sharee} (外部)", "{sharee} (remote group)" : "{sharee}(远程组)", - "{sharee} (email)" : "{sharee} (邮件)", "{sharee} ({type}, {owner})" : "{share}({type},{owner})", - "{sharee} (conversation)" : "{sharee}(对话)", "Share" : "共享", "Name or email address..." : "姓名或电子邮件地址...", "Name or federated cloud ID..." : "姓名或联合云 ID...", @@ -381,6 +377,9 @@ OC.L10N.register( "Error setting expiration date" : "设置过期日期时出错", "The public link will expire no later than {days} days after it is created" : "该共享链接将在创建后 {days} 天失效", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} 通过链接共享", + "{sharee} (group)" : "{sharee} (分组)", + "{sharee} (remote)" : "{sharee} (外部)", + "{sharee} (email)" : "{sharee} (邮件)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "通过输入用户或组,联合云ID或电子邮件地址与其他人共享。", "Share with other people by entering a user or group or a federated cloud ID." : "通过输入用户或组或联合云ID与其他人共享。", "Share with other people by entering a user or group or an email address." : "输入用户/组织或邮箱地址来共享给其他人.", @@ -412,6 +411,7 @@ OC.L10N.register( "You are about to grant %s access to your %s account." : "你将分配 %s 访问权限给你的 %s 账户。", "Depending on your configuration, this button could also work to trust the domain:" : "取决于配置,此按钮也可用作设置信任域名:", "Copy URL" : "复制超链接", + "{sharee} (conversation)" : "{sharee}(对话)", "Please log in before granting %s access to your %s account." : "请在登录之前授权 %s 访问你的 %s 账户。", "Further information how to configure this can be found in the %sdocumentation%s." : "更多配置信息可以查看 %s文档%s。" }, diff --git a/core/l10n/zh_CN.json b/core/l10n/zh_CN.json index 3a6f1c58999..87f1b38c1f5 100644 --- a/core/l10n/zh_CN.json +++ b/core/l10n/zh_CN.json @@ -207,12 +207,8 @@ "No users found for {search}" : "没有找到 {search} 用户", "An error occurred (\"{message}\"). Please try again" : "发生错误 (\"{message}\"). 请重试", "An error occurred. Please try again" : "发生错误. 请重试", - "{sharee} (group)" : "{sharee} (分组)", - "{sharee} (remote)" : "{sharee} (外部)", "{sharee} (remote group)" : "{sharee}(远程组)", - "{sharee} (email)" : "{sharee} (邮件)", "{sharee} ({type}, {owner})" : "{share}({type},{owner})", - "{sharee} (conversation)" : "{sharee}(对话)", "Share" : "共享", "Name or email address..." : "姓名或电子邮件地址...", "Name or federated cloud ID..." : "姓名或联合云 ID...", @@ -379,6 +375,9 @@ "Error setting expiration date" : "设置过期日期时出错", "The public link will expire no later than {days} days after it is created" : "该共享链接将在创建后 {days} 天失效", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} 通过链接共享", + "{sharee} (group)" : "{sharee} (分组)", + "{sharee} (remote)" : "{sharee} (外部)", + "{sharee} (email)" : "{sharee} (邮件)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "通过输入用户或组,联合云ID或电子邮件地址与其他人共享。", "Share with other people by entering a user or group or a federated cloud ID." : "通过输入用户或组或联合云ID与其他人共享。", "Share with other people by entering a user or group or an email address." : "输入用户/组织或邮箱地址来共享给其他人.", @@ -410,6 +409,7 @@ "You are about to grant %s access to your %s account." : "你将分配 %s 访问权限给你的 %s 账户。", "Depending on your configuration, this button could also work to trust the domain:" : "取决于配置,此按钮也可用作设置信任域名:", "Copy URL" : "复制超链接", + "{sharee} (conversation)" : "{sharee}(对话)", "Please log in before granting %s access to your %s account." : "请在登录之前授权 %s 访问你的 %s 账户。", "Further information how to configure this can be found in the %sdocumentation%s." : "更多配置信息可以查看 %s文档%s。" },"pluralForm" :"nplurals=1; plural=0;" diff --git a/core/l10n/zh_TW.js b/core/l10n/zh_TW.js index db99f2107a3..89787aa34aa 100644 --- a/core/l10n/zh_TW.js +++ b/core/l10n/zh_TW.js @@ -193,12 +193,8 @@ OC.L10N.register( "No users found for {search}" : "沒有使用者符合 {search}", "An error occurred (\"{message}\"). Please try again" : "發生錯誤({message}),請再試一次", "An error occurred. Please try again" : "發生錯誤,請再試一次", - "{sharee} (group)" : "{sharee} (群組)", - "{sharee} (remote)" : "{sharee} (遠端)", "{sharee} (remote group)" : "{sharee} (遠端群組)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (對話)", "Share" : "分享", "Name or email address..." : "名字或電子郵件地址", "Name or federated cloud ID..." : "名稱或者聯盟式雲端ID...", @@ -353,6 +349,9 @@ OC.L10N.register( "Error setting expiration date" : "設定到期日發生錯誤", "The public link will expire no later than {days} days after it is created" : "這個公開連結會在 {days} 天內失效", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} 分享了連結", + "{sharee} (group)" : "{sharee} (群組)", + "{sharee} (remote)" : "{sharee} (遠端)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "透過輸入使用者、群組名稱,聯盟式雲端ID或e-mail信箱來分享給其他人。 ", "Share with other people by entering a user or group or a federated cloud ID." : "透過輸入使用者、群組名稱,聯盟式雲端ID來分享給其他人。", "Share with other people by entering a user or group or an email address." : "透過輸入使用者、群組名稱或email來分享給其他人。", @@ -379,6 +378,7 @@ OC.L10N.register( "Back to log in" : "回到登入頁面", "You are about to grant %s access to your %s account." : "您將授予「%s」存取您的 %s 帳戶", "Depending on your configuration, this button could also work to trust the domain:" : "根據你的設定值,此按鈕也可用於信任以下網域:", + "{sharee} (conversation)" : "{sharee} (對話)", "Please log in before granting %s access to your %s account." : "請登入後再授權 %s 存取你的 %s 帳號", "Further information how to configure this can be found in the %sdocumentation%s." : "關於如何設定這個的更多訊息,請見 %s 文件 %s" }, diff --git a/core/l10n/zh_TW.json b/core/l10n/zh_TW.json index 45c57f4bc38..a82889658ea 100644 --- a/core/l10n/zh_TW.json +++ b/core/l10n/zh_TW.json @@ -191,12 +191,8 @@ "No users found for {search}" : "沒有使用者符合 {search}", "An error occurred (\"{message}\"). Please try again" : "發生錯誤({message}),請再試一次", "An error occurred. Please try again" : "發生錯誤,請再試一次", - "{sharee} (group)" : "{sharee} (群組)", - "{sharee} (remote)" : "{sharee} (遠端)", "{sharee} (remote group)" : "{sharee} (遠端群組)", - "{sharee} (email)" : "{sharee} (email)", "{sharee} ({type}, {owner})" : "{sharee} ({type}, {owner})", - "{sharee} (conversation)" : "{sharee} (對話)", "Share" : "分享", "Name or email address..." : "名字或電子郵件地址", "Name or federated cloud ID..." : "名稱或者聯盟式雲端ID...", @@ -351,6 +347,9 @@ "Error setting expiration date" : "設定到期日發生錯誤", "The public link will expire no later than {days} days after it is created" : "這個公開連結會在 {days} 天內失效", "{{shareInitiatorDisplayName}} shared via link" : "{{shareInitiatorDisplayName}} 分享了連結", + "{sharee} (group)" : "{sharee} (群組)", + "{sharee} (remote)" : "{sharee} (遠端)", + "{sharee} (email)" : "{sharee} (email)", "Share with other people by entering a user or group, a federated cloud ID or an email address." : "透過輸入使用者、群組名稱,聯盟式雲端ID或e-mail信箱來分享給其他人。 ", "Share with other people by entering a user or group or a federated cloud ID." : "透過輸入使用者、群組名稱,聯盟式雲端ID來分享給其他人。", "Share with other people by entering a user or group or an email address." : "透過輸入使用者、群組名稱或email來分享給其他人。", @@ -377,6 +376,7 @@ "Back to log in" : "回到登入頁面", "You are about to grant %s access to your %s account." : "您將授予「%s」存取您的 %s 帳戶", "Depending on your configuration, this button could also work to trust the domain:" : "根據你的設定值,此按鈕也可用於信任以下網域:", + "{sharee} (conversation)" : "{sharee} (對話)", "Please log in before granting %s access to your %s account." : "請登入後再授權 %s 存取你的 %s 帳號", "Further information how to configure this can be found in the %sdocumentation%s." : "關於如何設定這個的更多訊息,請見 %s 文件 %s" },"pluralForm" :"nplurals=1; plural=0;" diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index d82043b2572..6f0344aa600 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -47,7 +47,7 @@ <ul id="appmenu" <?php if ($_['themingInvertMenu']) { ?>class="inverted"<?php } ?>> <?php foreach ($_['navigation'] as $entry): ?> - <li data-id="<?php p($entry['id']); ?>" class="hidden"> + <li data-id="<?php p($entry['id']); ?>" class="hidden" tabindex="-1"> <a href="<?php print_unescaped($entry['href']); ?>" <?php if ($entry['active']): ?> class="active"<?php endif; ?> aria-label="<?php p($entry['name']); ?>"> @@ -69,7 +69,7 @@ aria-haspopup="true" aria-controls="navigation" aria-expanded="false"> <a href="#" aria-label="<?php p($l->t('More apps')); ?>"> <div class="icon-more-white"></div> - <span><?php p($l->t('More apps')); ?></span> + <span><?php p($l->t('More')); ?></span> </a> </li> </ul> diff --git a/core/templates/login.php b/core/templates/login.php index 989ea1eaad5..3035d23da70 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -42,7 +42,7 @@ use OC\Core\Controller\LoginController; aria-label="<?php p($l->t('Username or email')); ?>" value="<?php p($_['loginName']); ?>" <?php p($_['user_autofocus'] ? 'autofocus' : ''); ?> - autocomplete="on" autocapitalize="none" autocorrect="off" required> + autocomplete="<?php p($_['login_form_autocomplete']); ?>" autocapitalize="none" autocorrect="off" required> <label for="user" class="infield"><?php p($l->t('Username or email')); ?></label> </p> @@ -51,7 +51,7 @@ use OC\Core\Controller\LoginController; placeholder="<?php p($l->t('Password')); ?>" aria-label="<?php p($l->t('Password')); ?>" <?php p($_['user_autofocus'] ? '' : 'autofocus'); ?> - autocomplete="on" autocapitalize="off" autocorrect="none" required> + autocomplete="<?php p($_['login_form_autocomplete']); ?>" autocapitalize="none" autocorrect="off" required> <label for="password" class="infield"><?php p($l->t('Password')); ?></label> </p> diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index e880d5ede49..d7523d52caa 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -231,7 +231,25 @@ return array( 'OCP\\Files\\Storage\\INotifyStorage' => $baseDir . '/lib/public/Files/Storage/INotifyStorage.php', 'OCP\\Files\\Storage\\IStorage' => $baseDir . '/lib/public/Files/Storage/IStorage.php', 'OCP\\Files\\Storage\\IStorageFactory' => $baseDir . '/lib/public/Files/Storage/IStorageFactory.php', + 'OCP\\Files\\Storage\\IWriteStreamStorage' => $baseDir . '/lib/public/Files/Storage/IWriteStreamStorage.php', 'OCP\\Files\\UnseekableException' => $baseDir . '/lib/public/Files/UnseekableException.php', + 'OCP\\Files_FullTextSearch\\Model\\AFilesDocument' => $baseDir . '/lib/public/Files_FullTextSearch/Model/AFilesDocument.php', + 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchAppNotAvailableException' => $baseDir . '/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php', + 'OCP\\FullTextSearch\\IFullTextSearchManager' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchManager.php', + 'OCP\\FullTextSearch\\IFullTextSearchPlatform' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchPlatform.php', + 'OCP\\FullTextSearch\\IFullTextSearchProvider' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchProvider.php', + 'OCP\\FullTextSearch\\Model\\DocumentAccess' => $baseDir . '/lib/public/FullTextSearch/Model/DocumentAccess.php', + 'OCP\\FullTextSearch\\Model\\IIndex' => $baseDir . '/lib/public/FullTextSearch/Model/IIndex.php', + 'OCP\\FullTextSearch\\Model\\IIndexOptions' => $baseDir . '/lib/public/FullTextSearch/Model/IIndexOptions.php', + 'OCP\\FullTextSearch\\Model\\IRunner' => $baseDir . '/lib/public/FullTextSearch/Model/IRunner.php', + 'OCP\\FullTextSearch\\Model\\ISearchRequest' => $baseDir . '/lib/public/FullTextSearch/Model/ISearchRequest.php', + 'OCP\\FullTextSearch\\Model\\ISearchResult' => $baseDir . '/lib/public/FullTextSearch/Model/ISearchResult.php', + 'OCP\\FullTextSearch\\Model\\IndexDocument' => $baseDir . '/lib/public/FullTextSearch/Model/IndexDocument.php', + 'OCP\\FullTextSearch\\Model\\SearchOption' => $baseDir . '/lib/public/FullTextSearch/Model/SearchOption.php', + 'OCP\\FullTextSearch\\Model\\SearchTemplate' => $baseDir . '/lib/public/FullTextSearch/Model/SearchTemplate.php', + 'OCP\\FullTextSearch\\Service\\IIndexService' => $baseDir . '/lib/public/FullTextSearch/Service/IIndexService.php', + 'OCP\\FullTextSearch\\Service\\IProviderService' => $baseDir . '/lib/public/FullTextSearch/Service/IProviderService.php', + 'OCP\\FullTextSearch\\Service\\ISearchService' => $baseDir . '/lib/public/FullTextSearch/Service/ISearchService.php', 'OCP\\GlobalScale\\IConfig' => $baseDir . '/lib/public/GlobalScale/IConfig.php', 'OCP\\GroupInterface' => $baseDir . '/lib/public/GroupInterface.php', 'OCP\\Group\\Backend\\ABackend' => $baseDir . '/lib/public/Group/Backend/ABackend.php', @@ -458,6 +476,7 @@ return array( 'OC\\Archive\\Archive' => $baseDir . '/lib/private/Archive/Archive.php', 'OC\\Archive\\TAR' => $baseDir . '/lib/private/Archive/TAR.php', 'OC\\Archive\\ZIP' => $baseDir . '/lib/private/Archive/ZIP.php', + 'OC\\Authentication\\Exceptions\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Exceptions\\InvalidProviderException' => $baseDir . '/lib/private/Authentication/Exceptions/InvalidProviderException.php', 'OC\\Authentication\\Exceptions\\InvalidTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/InvalidTokenException.php', 'OC\\Authentication\\Exceptions\\LoginRequiredException' => $baseDir . '/lib/private/Authentication/Exceptions/LoginRequiredException.php', @@ -471,7 +490,6 @@ return array( 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php', 'OC\\Authentication\\Token\\DefaultTokenProvider' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenProvider.php', - 'OC\\Authentication\\Token\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Token\\IProvider' => $baseDir . '/lib/private/Authentication/Token/IProvider.php', 'OC\\Authentication\\Token\\IToken' => $baseDir . '/lib/private/Authentication/Token/IToken.php', 'OC\\Authentication\\Token\\Manager' => $baseDir . '/lib/private/Authentication/Token/Manager.php', @@ -652,6 +670,7 @@ return array( 'OC\\Core\\Migrations\\Version14000Date20180710092004' => $baseDir . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => $baseDir . '/core/Migrations/Version14000Date20180712153140.php', 'OC\\Core\\Migrations\\Version15000Date20180926101451' => $baseDir . '/core/Migrations/Version15000Date20180926101451.php', + 'OC\\Core\\Migrations\\Version15000Date20181015062942' => $baseDir . '/core/Migrations/Version15000Date20181015062942.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php', @@ -803,6 +822,7 @@ return array( 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => $baseDir . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => $baseDir . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => $baseDir . '/lib/private/Files/Storage/Wrapper/Wrapper.php', + 'OC\\Files\\Stream\\CountReadStream' => $baseDir . '/lib/private/Files/Stream/CountReadStream.php', 'OC\\Files\\Stream\\Encryption' => $baseDir . '/lib/private/Files/Stream/Encryption.php', 'OC\\Files\\Stream\\Quota' => $baseDir . '/lib/private/Files/Stream/Quota.php', 'OC\\Files\\Type\\Detection' => $baseDir . '/lib/private/Files/Type/Detection.php', @@ -811,6 +831,7 @@ return array( 'OC\\Files\\Utils\\Scanner' => $baseDir . '/lib/private/Files/Utils/Scanner.php', 'OC\\Files\\View' => $baseDir . '/lib/private/Files/View.php', 'OC\\ForbiddenException' => $baseDir . '/lib/private/ForbiddenException.php', + 'OC\\FullTextSearch\\FullTextSearchManager' => $baseDir . '/lib/private/FullTextSearch/FullTextSearchManager.php', 'OC\\GlobalScale\\Config' => $baseDir . '/lib/private/GlobalScale/Config.php', 'OC\\Group\\Backend' => $baseDir . '/lib/private/Group/Backend.php', 'OC\\Group\\Database' => $baseDir . '/lib/private/Group/Database.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c5f6211b69d..cf2fef4282d 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -261,7 +261,25 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Files\\Storage\\INotifyStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/INotifyStorage.php', 'OCP\\Files\\Storage\\IStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IStorage.php', 'OCP\\Files\\Storage\\IStorageFactory' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IStorageFactory.php', + 'OCP\\Files\\Storage\\IWriteStreamStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IWriteStreamStorage.php', 'OCP\\Files\\UnseekableException' => __DIR__ . '/../../..' . '/lib/public/Files/UnseekableException.php', + 'OCP\\Files_FullTextSearch\\Model\\AFilesDocument' => __DIR__ . '/../../..' . '/lib/public/Files_FullTextSearch/Model/AFilesDocument.php', + 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchAppNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php', + 'OCP\\FullTextSearch\\IFullTextSearchManager' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchManager.php', + 'OCP\\FullTextSearch\\IFullTextSearchPlatform' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchPlatform.php', + 'OCP\\FullTextSearch\\IFullTextSearchProvider' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchProvider.php', + 'OCP\\FullTextSearch\\Model\\DocumentAccess' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/DocumentAccess.php', + 'OCP\\FullTextSearch\\Model\\IIndex' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IIndex.php', + 'OCP\\FullTextSearch\\Model\\IIndexOptions' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IIndexOptions.php', + 'OCP\\FullTextSearch\\Model\\IRunner' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IRunner.php', + 'OCP\\FullTextSearch\\Model\\ISearchRequest' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/ISearchRequest.php', + 'OCP\\FullTextSearch\\Model\\ISearchResult' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/ISearchResult.php', + 'OCP\\FullTextSearch\\Model\\IndexDocument' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IndexDocument.php', + 'OCP\\FullTextSearch\\Model\\SearchOption' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/SearchOption.php', + 'OCP\\FullTextSearch\\Model\\SearchTemplate' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/SearchTemplate.php', + 'OCP\\FullTextSearch\\Service\\IIndexService' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Service/IIndexService.php', + 'OCP\\FullTextSearch\\Service\\IProviderService' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Service/IProviderService.php', + 'OCP\\FullTextSearch\\Service\\ISearchService' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Service/ISearchService.php', 'OCP\\GlobalScale\\IConfig' => __DIR__ . '/../../..' . '/lib/public/GlobalScale/IConfig.php', 'OCP\\GroupInterface' => __DIR__ . '/../../..' . '/lib/public/GroupInterface.php', 'OCP\\Group\\Backend\\ABackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ABackend.php', @@ -488,6 +506,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Archive\\Archive' => __DIR__ . '/../../..' . '/lib/private/Archive/Archive.php', 'OC\\Archive\\TAR' => __DIR__ . '/../../..' . '/lib/private/Archive/TAR.php', 'OC\\Archive\\ZIP' => __DIR__ . '/../../..' . '/lib/private/Archive/ZIP.php', + 'OC\\Authentication\\Exceptions\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Exceptions\\InvalidProviderException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/InvalidProviderException.php', 'OC\\Authentication\\Exceptions\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/InvalidTokenException.php', 'OC\\Authentication\\Exceptions\\LoginRequiredException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/LoginRequiredException.php', @@ -501,7 +520,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php', 'OC\\Authentication\\Token\\DefaultTokenProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenProvider.php', - 'OC\\Authentication\\Token\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IProvider.php', 'OC\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IToken.php', 'OC\\Authentication\\Token\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/Manager.php', @@ -682,6 +700,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version14000Date20180710092004' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180712153140.php', 'OC\\Core\\Migrations\\Version15000Date20180926101451' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20180926101451.php', + 'OC\\Core\\Migrations\\Version15000Date20181015062942' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20181015062942.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php', @@ -833,6 +852,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Wrapper.php', + 'OC\\Files\\Stream\\CountReadStream' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/CountReadStream.php', 'OC\\Files\\Stream\\Encryption' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Encryption.php', 'OC\\Files\\Stream\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Quota.php', 'OC\\Files\\Type\\Detection' => __DIR__ . '/../../..' . '/lib/private/Files/Type/Detection.php', @@ -841,6 +861,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Utils\\Scanner' => __DIR__ . '/../../..' . '/lib/private/Files/Utils/Scanner.php', 'OC\\Files\\View' => __DIR__ . '/../../..' . '/lib/private/Files/View.php', 'OC\\ForbiddenException' => __DIR__ . '/../../..' . '/lib/private/ForbiddenException.php', + 'OC\\FullTextSearch\\FullTextSearchManager' => __DIR__ . '/../../..' . '/lib/private/FullTextSearch/FullTextSearchManager.php', 'OC\\GlobalScale\\Config' => __DIR__ . '/../../..' . '/lib/private/GlobalScale/Config.php', 'OC\\Group\\Backend' => __DIR__ . '/../../..' . '/lib/private/Group/Backend.php', 'OC\\Group\\Database' => __DIR__ . '/../../..' . '/lib/private/Group/Database.php', diff --git a/lib/private/Authentication/Exceptions/ExpiredTokenException.php b/lib/private/Authentication/Exceptions/ExpiredTokenException.php index a45ca5b6955..d5b2e2cbca7 100644 --- a/lib/private/Authentication/Exceptions/ExpiredTokenException.php +++ b/lib/private/Authentication/Exceptions/ExpiredTokenException.php @@ -21,9 +21,9 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -namespace OC\Authentication\Token; +namespace OC\Authentication\Exceptions; -use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Token\IToken; class ExpiredTokenException extends InvalidTokenException { /** @var IToken */ diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index a27a875a27f..98609a3f14b 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -29,6 +29,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; use Exception; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OCP\AppFramework\Db\DoesNotExistException; diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index 7ee76b7b384..21223cecdf7 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -26,6 +26,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index 98a48f41523..3174599221d 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 33c0b1d59eb..9f596ac4568 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OCP\AppFramework\Db\DoesNotExistException; diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 101d6845ec3..6faa5d5d125 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 e0f5298f83b..d877346b155 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/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 3ce919a4cbe..71acd27783c 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -28,6 +28,7 @@ namespace OC\Files\ObjectStore; use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Cache\CacheEntry; +use OC\Files\Stream\CountReadStream; use OCP\Files\ObjectStore\IObjectStore; class ObjectStoreStorage extends \OC\Files\Storage\Common { @@ -382,25 +383,48 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { } public function writeBack($tmpFile, $path) { + $size = filesize($tmpFile); + $this->writeStream($path, fopen($tmpFile, 'r'), $size); + } + + /** + * external changes are not supported, exclusive access to the object storage is assumed + * + * @param string $path + * @param int $time + * @return false + */ + public function hasUpdated($path, $time) { + return false; + } + + public function needsPartFile() { + return false; + } + + public function file_put_contents($path, $data) { + $stream = fopen('php://temp', 'r+'); + fwrite($stream, $data); + rewind($stream); + return $this->writeStream($path, $stream, strlen($data)) > 0; + } + + public function writeStream(string $path, $stream, int $size = null): int { $stat = $this->stat($path); if (empty($stat)) { // create new file - $stat = array( + $stat = [ 'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, - ); + ]; } // update stat with new data $mTime = time(); - $stat['size'] = filesize($tmpFile); + $stat['size'] = (int)$size; $stat['mtime'] = $mTime; $stat['storage_mtime'] = $mTime; - // run path based detection first, to use file extension because $tmpFile is only a random string $mimetypeDetector = \OC::$server->getMimeTypeDetector(); $mimetype = $mimetypeDetector->detectPath($path); - if ($mimetype === 'application/octet-stream') { - $mimetype = $mimetypeDetector->detect($tmpFile); - } $stat['mimetype'] = $mimetype; $stat['etag'] = $this->getETag($path); @@ -408,7 +432,20 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { $fileId = $this->getCache()->put($path, $stat); try { //upload to object storage - $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r')); + if ($size === null) { + $countStream = CountReadStream::wrap($stream, function ($writtenSize) use ($fileId, &$size) { + $this->getCache()->update($fileId, [ + 'size' => $writtenSize + ]); + $size = $writtenSize; + }); + $this->objectStore->writeObject($this->getURN($fileId), $countStream); + if (is_resource($countStream)) { + fclose($countStream); + } + } else { + $this->objectStore->writeObject($this->getURN($fileId), $stream); + } } catch (\Exception $ex) { $this->getCache()->remove($path); $this->logger->logException($ex, [ @@ -417,20 +454,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { ]); throw $ex; // make this bubble up } - } - /** - * external changes are not supported, exclusive access to the object storage is assumed - * - * @param string $path - * @param int $time - * @return false - */ - public function hasUpdated($path, $time) { - return false; - } - - public function needsPartFile() { - return false; + return $size; } } diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index b6c82f3a1df..72fe3a79792 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -54,6 +54,7 @@ use OCP\Files\InvalidPathException; use OCP\Files\ReservedWordException; use OCP\Files\Storage\ILockingStorage; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IWriteStreamStorage; use OCP\ILogger; use OCP\Lock\ILockingProvider; use OCP\Lock\LockedException; @@ -69,7 +70,7 @@ use OCP\Lock\LockedException; * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ -abstract class Common implements Storage, ILockingStorage { +abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { use LocalTempFileTrait; @@ -809,4 +810,23 @@ abstract class Common implements Storage, ILockingStorage { public function needsPartFile() { return true; } + + /** + * fallback implementation + * + * @param string $path + * @param resource $stream + * @param int $size + * @return int + */ + public function writeStream(string $path, $stream, int $size = null): int { + $target = $this->fopen($path, 'w'); + if (!$target) { + return 0; + } + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } } diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index 46b53dcf95c..5f7232e64b3 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -462,4 +462,8 @@ class Local extends \OC\Files\Storage\Common { return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); } } + + public function writeStream(string $path, $stream, int $size = null): int { + return (int)file_put_contents($this->getSourcePath($path), $stream); + } } diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 42653b2d4a6..e1c1225e0cc 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -1029,4 +1029,13 @@ class Encryption extends Wrapper { } + public function writeStream(string $path, $stream, int $size = null): int { + // always fall back to fopen + $target = $this->fopen($path, 'w'); + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } + } diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php index 56514af6d80..f21b5716467 100644 --- a/lib/private/Files/Storage/Wrapper/Jail.php +++ b/lib/private/Files/Storage/Wrapper/Jail.php @@ -29,6 +29,7 @@ use OC\Files\Cache\Wrapper\CacheJail; use OC\Files\Cache\Wrapper\JailPropagator; use OC\Files\Filesystem; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IWriteStreamStorage; use OCP\Lock\ILockingProvider; /** @@ -515,4 +516,18 @@ class Jail extends Wrapper { $this->propagator = new JailPropagator($storage, \OC::$server->getDatabaseConnection()); return $this->propagator; } + + public function writeStream(string $path, $stream, int $size = null): int { + $storage = $this->getWrapperStorage(); + if ($storage->instanceOfStorage(IWriteStreamStorage::class)) { + /** @var IWriteStreamStorage $storage */ + return $storage->writeStream($this->getUnjailedPath($path), $stream, $size); + } else { + $target = $this->fopen($path, 'w'); + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } + } } diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php index 060c596ad65..f9c84b89fe5 100644 --- a/lib/private/Files/Storage/Wrapper/Wrapper.php +++ b/lib/private/Files/Storage/Wrapper/Wrapper.php @@ -32,9 +32,10 @@ namespace OC\Files\Storage\Wrapper; use OCP\Files\InvalidPathException; use OCP\Files\Storage\ILockingStorage; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IWriteStreamStorage; use OCP\Lock\ILockingProvider; -class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage { +class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStreamStorage { /** * @var \OC\Files\Storage\Storage $storage */ @@ -621,4 +622,18 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage { public function needsPartFile() { return $this->getWrapperStorage()->needsPartFile(); } + + public function writeStream(string $path, $stream, int $size = null): int { + $storage = $this->getWrapperStorage(); + if ($storage->instanceOfStorage(IWriteStreamStorage::class)) { + /** @var IWriteStreamStorage $storage */ + return $storage->writeStream($path, $stream, $size); + } else { + $target = $this->fopen($path, 'w'); + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } + } } diff --git a/lib/private/Files/Stream/CountReadStream.php b/lib/private/Files/Stream/CountReadStream.php new file mode 100644 index 00000000000..93cadf8f214 --- /dev/null +++ b/lib/private/Files/Stream/CountReadStream.php @@ -0,0 +1,65 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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\Files\Stream; + +use Icewind\Streams\Wrapper; + +class CountReadStream extends Wrapper { + /** @var int */ + private $count; + + /** @var callback */ + private $callback; + + public static function wrap($source, $callback) { + $context = stream_context_create(array( + 'count' => array( + 'source' => $source, + 'callback' => $callback, + ) + )); + return Wrapper::wrapSource($source, $context, 'count', self::class); + } + + public function dir_opendir($path, $options) { + return false; + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $context = $this->loadContext('count'); + + $this->callback = $context['callback']; + return true; + } + + public function stream_read($count) { + $result = parent::stream_read($count); + $this->count += strlen($result); + return $result; + } + + public function stream_close() { + $result = parent::stream_close(); + call_user_func($this->callback, $this->count); + return $result; + } +} diff --git a/lib/private/FullTextSearch/FullTextSearchManager.php b/lib/private/FullTextSearch/FullTextSearchManager.php new file mode 100644 index 00000000000..9a9b077cf23 --- /dev/null +++ b/lib/private/FullTextSearch/FullTextSearchManager.php @@ -0,0 +1,227 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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\FullTextSearch; + + +use OCP\FullTextSearch\Exceptions\FullTextSearchAppNotAvailableException; +use OCP\FullTextSearch\IFullTextSearchManager; +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Service\IIndexService; +use OCP\FullTextSearch\Service\IProviderService; +use OCP\FullTextSearch\Service\ISearchService; + + +/** + * Class FullTextSearchManager + * + * @package OC\FullTextSearch + */ +class FullTextSearchManager implements IFullTextSearchManager { + + + /** @var IProviderService */ + private $providerService; + + /** @var IIndexService */ + private $indexService; + + /** @var ISearchService */ + private $searchService; + + + /** + * @since 15.0.0 + * + * @param IProviderService $providerService + */ + public function registerProviderService(IProviderService $providerService) { + $this->providerService = $providerService; + } + + /** + * @since 15.0.0 + * + * @param IIndexService $indexService + */ + public function registerIndexService(IIndexService $indexService) { + $this->indexService = $indexService; + } + + /** + * @since 15.0.0 + * + * @param ISearchService $searchService + */ + public function registerSearchService(ISearchService $searchService) { + $this->searchService = $searchService; + } + + + /** + * @return IProviderService + * @throws FullTextSearchAppNotAvailableException + */ + private function getProviderService(): IProviderService { + if ($this->providerService === null) { + throw new FullTextSearchAppNotAvailableException('No IProviderService registered'); + } + + return $this->providerService; + } + + + /** + * @return IIndexService + * @throws FullTextSearchAppNotAvailableException + */ + private function getIndexService(): IIndexService { + if ($this->indexService === null) { + throw new FullTextSearchAppNotAvailableException('No IIndexService registered'); + } + + return $this->indexService; + } + + + /** + * @return ISearchService + * @throws FullTextSearchAppNotAvailableException + */ + private function getSearchService(): ISearchService { + if ($this->searchService === null) { + throw new FullTextSearchAppNotAvailableException('No ISearchService registered'); + } + + return $this->searchService; + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + public function addJavascriptAPI() { + $this->getProviderService()->addJavascriptAPI(); + } + + + /** + * @param string $providerId + * + * @return bool + * @throws FullTextSearchAppNotAvailableException + */ + public function isProviderIndexed(string $providerId): bool { + return $this->getProviderService()->isProviderIndexed($providerId); + } + + + /** + * @param string $providerId + * @param string $documentId + * @return IIndex + * @throws FullTextSearchAppNotAvailableException + */ + public function getIndex(string $providerId, string $documentId): IIndex { + return $this->getIndexService()->getIndex($providerId, $documentId); + } + + /** + * @param string $providerId + * @param string $documentId + * @param string $userId + * @param int $status + * + * @see IIndex for available value for $status. + * + * @return IIndex + * @throws FullTextSearchAppNotAvailableException + */ + public function createIndex(string $providerId, string $documentId, string $userId, int $status = 0): IIndex { + return $this->getIndexService()->getIndex($providerId, $documentId); + } + + + /** + * @param string $providerId + * @param string $documentId + * @param int $status + * @param bool $reset + * + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false) { + $this->getIndexService()->updateIndexStatus($providerId, $documentId, $status, $reset); + } + + /** + * @param string $providerId + * @param array $documentIds + * @param int $status + * @param bool $reset + * + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false) { + $this->getIndexService()->updateIndexesStatus($providerId, $documentIds, $status, $reset); + } + + + /** + * @param IIndex[] $indexes + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexes(array $indexes) { + $this->getIndexService()->updateIndexes($indexes); + } + + + /** + * @param array $request + * @param string $userId + * + * @return ISearchResult[] + * @throws FullTextSearchAppNotAvailableException + */ + public function search(array $request, string $userId = ''): array { + $searchRequest = $this->getSearchService()->generateSearchRequest($request); + + return $this->getSearchService()->search($userId, $searchRequest); + } + + +} + diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index 86579e3480b..1f7decf2b79 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -298,19 +298,23 @@ class Generator { if ($height !== $maxHeight && $width !== $maxWidth) { /* - * Scale to the nearest power of two + * Scale to the nearest power of four */ - $pow2height = 2 ** ceil(log($height) / log(2)); - $pow2width = 2 ** ceil(log($width) / log(2)); + $pow4height = 4 ** ceil(log($height) / log(4)); + $pow4width = 4 ** ceil(log($width) / log(4)); - $ratioH = $height / $pow2height; - $ratioW = $width / $pow2width; + // Minimum size is 64 + $pow4height = max($pow4height, 64); + $pow4width = max($pow4width, 64); + + $ratioH = $height / $pow4height; + $ratioW = $width / $pow4width; if ($ratioH < $ratioW) { - $width = $pow2width; + $width = $pow4width; $height /= $ratioW; } else { - $height = $pow2height; + $height = $pow4height; $width /= $ratioH; } } diff --git a/lib/private/Server.php b/lib/private/Server.php index 32d7705919c..ceecd059df2 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -82,6 +82,7 @@ use OC\Files\Node\LazyRoot; use OC\Files\Node\Root; use OC\Files\Storage\StorageFactory; use OC\Files\View; +use OC\FullTextSearch\FullTextSearchManager; use OC\Http\Client\ClientService; use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\AppLocator; @@ -138,6 +139,7 @@ use OCP\Federation\ICloudIdManager; use OCP\Authentication\LoginCredentials\IStore; use OCP\Files\NotFoundException; use OCP\Files\Storage\IStorageFactory; +use OCP\FullTextSearch\IFullTextSearchManager; use OCP\GlobalScale\IConfig; use OCP\ICacheFactory; use OCP\IDBConnection; @@ -758,7 +760,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService('TrustedDomainHelper', function ($c) { return new TrustedDomainHelper($this->getConfig()); }); - $this->registerService('Throttler', function (Server $c) { + $this->registerService(Throttler::class, function (Server $c) { return new Throttler( $c->getDatabaseConnection(), new TimeFactory(), @@ -766,6 +768,7 @@ class Server extends ServerContainer implements IServerContainer { $c->getConfig() ); }); + $this->registerAlias('Throttler', Throttler::class); $this->registerService('IntegrityCodeChecker', function (Server $c) { // IConfig and IAppManager requires a working database. This code // might however be called when ownCloud is not yet setup. @@ -1183,6 +1186,7 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerAlias(IDashboardManager::class, Dashboard\DashboardManager::class); + $this->registerAlias(IFullTextSearchManager::class, FullTextSearchManager::class); $this->connectDispatcher(); } diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 9c5d78a5958..3dcca0facbc 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -296,6 +296,7 @@ class DefaultShareProvider implements IShareProvider { ->set('token', $qb->createNamedParameter($share->getToken())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) ->set('note', $qb->createNamedParameter($share->getNote())) + ->set('hide_download', $qb->createNamedParameter($share->getHideDownload() ? 1 : 0), IQueryBuilder::PARAM_INT) ->execute(); } @@ -953,6 +954,7 @@ class DefaultShareProvider implements IShareProvider { } $share->setProviderId($this->identifier()); + $share->setHideDownload((int)$data['hide_download'] === 1); return $share; } diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index 71c0453d9e5..e218360f87b 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -30,6 +30,7 @@ use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IUserManager; use OCP\Share\Exceptions\IllegalIDChangeException; +use OCP\Share\IShare; class Share implements \OCP\Share\IShare { @@ -85,6 +86,9 @@ class Share implements \OCP\Share\IShare { /** @var ICacheEntry|null */ private $nodeCacheEntry; + /** @var bool */ + private $hideDownload = false; + public function __construct(IRootFolder $rootFolder, IUserManager $userManager) { $this->rootFolder = $rootFolder; $this->userManager = $userManager; @@ -514,4 +518,13 @@ class Share implements \OCP\Share\IShare { public function getNodeCacheEntry() { return $this->nodeCacheEntry; } + + public function setHideDownload(bool $hide): IShare { + $this->hideDownload = $hide; + return $this; + } + + public function getHideDownload(): bool { + return $this->hideDownload; + } } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index a9c638dca93..674f38e2401 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -38,6 +38,7 @@ namespace OC\User; use OC; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\PasswordLoginForbiddenException; @@ -401,7 +402,13 @@ class Session implements IUserSession, Emitter { $this->manager->emit('\OC\User', 'preLogin', array($user, $password)); } - $isTokenPassword = $this->isTokenPassword($password); + try { + $isTokenPassword = $this->isTokenPassword($password); + } catch (ExpiredTokenException $e) { + // Just return on an expired token no need to check further or record a failed login + return false; + } + if (!$isTokenPassword && $this->isTokenAuthEnforced()) { throw new PasswordLoginForbiddenException(); } @@ -474,11 +481,14 @@ class Session implements IUserSession, Emitter { * * @param string $password * @return boolean + * @throws ExpiredTokenException */ public function isTokenPassword($password) { try { $this->tokenProvider->getToken($password); return true; + } catch (ExpiredTokenException $e) { + throw $e; } catch (InvalidTokenException $ex) { return false; } diff --git a/lib/public/Files/Storage/IWriteStreamStorage.php b/lib/public/Files/Storage/IWriteStreamStorage.php new file mode 100644 index 00000000000..39a28dd037b --- /dev/null +++ b/lib/public/Files/Storage/IWriteStreamStorage.php @@ -0,0 +1,40 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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 OCP\Files\Storage; + +/** + * Interface that adds the ability to write a stream directly to file + * + * @since 15.0.0 + */ +interface IWriteStreamStorage extends IStorage { + /** + * Write the data from a stream to a file + * + * @param string $path + * @param resource $stream + * @param int|null $size the size of the stream if known in advance + * @return int the number of bytes written + * @since 15.0.0 + */ + public function writeStream(string $path, $stream, int $size = null): int; +} diff --git a/lib/public/Files_FullTextSearch/Model/AFilesDocument.php b/lib/public/Files_FullTextSearch/Model/AFilesDocument.php new file mode 100644 index 00000000000..3eed956df84 --- /dev/null +++ b/lib/public/Files_FullTextSearch/Model/AFilesDocument.php @@ -0,0 +1,112 @@ +<?php +declare(strict_types=1); + + +/** + * Files_FullTextSearch - Index the content of your files + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\Files_FullTextSearch\Model; + + +use OCP\FullTextSearch\Model\IndexDocument; + + +/** + * Abstract Class AFilesDocument + * + * This is mostly used by 3rd party apps that want to complete the IndexDocument + * with more information about a file before its index: + * + * \OC::$server->getEventDispatcher()->addListener( + * '\OCA\Files_FullTextSearch::onFileIndexing', + * function(GenericEvent $e) { + * //@var \OCP\Files\Node $file + * $file = $e->getArgument('file'); + * + * // @var \OCP\Files_FullTextSearch\Model\AFilesDocument $document + * $document = $e->getArgument('document'); + * + * } + * ); + * + * @since 15.0.0 + * + * @package OCP\Files_FullTextSearch\Model + */ +abstract class AFilesDocument extends IndexDocument { + + + /** + * Returns the owner of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getOwnerId(): string; + + + /** + * Returns the current viewer of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getViewerId(): string; + + + /** + * Returns the type of the document/file. + * + * @since 15.0.0 + * + * @return string \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER + */ + abstract public function getType(): string; + + + /** + * Returns the mimetype of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getMimetype(): string; + + /** + * Returns the path of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getPath(): string; + + +} + diff --git a/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php b/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php new file mode 100644 index 00000000000..4363376f0f4 --- /dev/null +++ b/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php @@ -0,0 +1,42 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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 OCP\FullTextSearch\Exceptions; + +/** + * @since 15.0.0 + * + * Class FullTextSearchAppNotAvailableException + * + * @package OCP\FullTextSearch\Exceptions + */ +class FullTextSearchAppNotAvailableException extends \Exception { +} + diff --git a/lib/public/FullTextSearch/IFullTextSearchManager.php b/lib/public/FullTextSearch/IFullTextSearchManager.php new file mode 100644 index 00000000000..1027f7ade75 --- /dev/null +++ b/lib/public/FullTextSearch/IFullTextSearchManager.php @@ -0,0 +1,186 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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 OCP\FullTextSearch; + + +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Service\IIndexService; +use OCP\FullTextSearch\Service\IProviderService; +use OCP\FullTextSearch\Service\ISearchService; + + +/** + * Interface IFullTextSearchManager + * + * Should be used to manage FullTextSearch from the app that contains your + * Content Provider/Search Platform. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch + */ +interface IFullTextSearchManager { + + + /** + * Register a IProviderService. + * + * @since 15.0.0 + * + * @param IProviderService $providerService + */ + public function registerProviderService(IProviderService $providerService); + + /** + * Register a IIndexService. + * + * @since 15.0.0 + * + * @param IIndexService $indexService + */ + public function registerIndexService(IIndexService $indexService); + + /** + * Register a ISearchService. + * + * @since 15.0.0 + * + * @param ISearchService $searchService + */ + public function registerSearchService(ISearchService $searchService); + + + /** + * Add the Javascript API in the navigation page of an app. + * Needed to replace the default search. + * + * @since 15.0.0 + */ + public function addJavascriptAPI(); + + + /** + * Check if the provider $providerId is already indexed. + * + * @since 15.0.0 + * + * @param string $providerId + * + * @return bool + */ + public function isProviderIndexed(string $providerId): bool; + + + /** + * Retrieve an Index from the database, based on the Id of the Provider + * and the Id of the Document + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * + * @return IIndex + */ + public function getIndex(string $providerId, string $documentId): IIndex; + + + /** + * Create a new Index. + * + * This method must be called when a new document is created. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * @param string $userId + * @param int $status + * + * @return IIndex + */ + public function createIndex(string $providerId, string $documentId, string $userId, int $status = 0): IIndex; + + + /** + * Update the status of an Index. status is a bitflag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * @param int $status + * @param bool $reset + */ + public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false); + + + /** + * Update the status of an array of Index. status is a bit flag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param array $documentIds + * @param int $status + * @param bool $reset + */ + public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false); + + /** + * Update an array of Index. + * + * @since 15.0.0 + * + * @param IIndex[] $indexes + */ + public function updateIndexes(array $indexes); + + /** + * Search using an array as request. If $userId is empty, will use the + * current session. + * + * @see ISearchService::generateSearchRequest + * + * @since 15.0.0 + * + * @param array $request + * @param string $userId + * @return ISearchResult[] + */ + public function search(array $request, string $userId = ''): array; + + +} + diff --git a/lib/public/FullTextSearch/IFullTextSearchPlatform.php b/lib/public/FullTextSearch/IFullTextSearchPlatform.php new file mode 100644 index 00000000000..f3f9a35bae2 --- /dev/null +++ b/lib/public/FullTextSearch/IFullTextSearchPlatform.php @@ -0,0 +1,227 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch; + + +use OCP\FullTextSearch\Model\DocumentAccess; +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\IndexDocument; +use OCP\FullTextSearch\Model\IRunner; +use OCP\FullTextSearch\Model\ISearchResult; + + +/** + * Interface IFullTextSearchPlatform + * + * This interface must be use when creating a Search Platform for FullTextSearch. + * + * A Search Platform is an extension to the FullTextSearch that will act as a + * a gateway between FullTextSearch and a search server (ie. ElasticSearch, + * Solr, ...) + * + * Multiple Search Platform can exist at the same time in Nextcloud, however only + * one Search Platform will be used by FullTextSearch. + * Administrator must select at least one Search Platform to be used by + * FullTextSearch in the admin settings page. + * + * The content provided by FullTextSearch comes in chunk from multiple Content + * Provider. Each chunk is identified by the ID of the Content Provider, and the + * ID of the document. + * + * + * To oversimplify the mechanism: + * + * - When indexing, FullTextSearch will send providerId, documentId, content. + * - When searching within the content of a Content Provider, identified by its + * providerId, FullTextSearch expect documentId as result. + * + * + * The Search Platform ia a PHP class that implement this interface and is defined + * in appinfo/info.xml of the app that contains that class: + * + * <fulltextsearch> + * <platform>OCA\YourApp\YourSearchPlatform</platform> + * </fulltextsearch> + * + * Multiple Search Platform can be defined in a single app. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch + */ +interface IFullTextSearchPlatform { + + + /** + * Must returns a unique Id used to identify the Search Platform. + * Id must contains only alphanumeric chars, with no space. + * + * @since 15.0.0 + * + * @return string + */ + public function getId(): string; + + + /** + * Must returns a descriptive name of the Search Platform. + * This is used mainly in the admin settings page to display the list of + * available Search Platform + * + * @since 15.0.0 + * + * @return string + */ + public function getName(): string; + + + /** + * should returns the current configuration of the Search Platform. + * This is used to display the configuration when using the + * ./occ fulltextsearch:check command line. + * + * @since 15.0.0 + * + * @return array + */ + public function getConfiguration(): array; + + + /** + * Set the wrapper of the currently executed process. + * Because the index process can be long and heavy, and because errors can + * be encountered during the process, the IRunner is a wrapper that allow the + * Search Platform to communicate with the process initiated by + * FullTextSearch. + * + * The IRunner is coming with some methods so the Search Platform can + * returns important information and errors to be displayed to the admin. + * + * @since 15.0.0 + * + * @param IRunner $runner + */ + public function setRunner(IRunner $runner); + + + /** + * Called when FullTextSearch is loading your Search Platform. + * + * @since 15.0.0 + */ + public function loadPlatform(); + + + /** + * Called to check that your Search Platform is correctly configured and that + * This is also the right place to check that the Search Service is available. + * + * @since 15.0.0 + * + * @return bool + */ + public function testPlatform(): bool; + + + /** + * Called before an index is initiated. + * Best place to initiate some stuff on the Search Server (mapping, ...) + * + * @since 15.0.0 + */ + public function initializeIndex(); + + + /** + * Reset the indexes for a specific providerId. + * $providerId can be 'all' if it is a global reset. + * + * @since 15.0.0 + * + * @param string $providerId + */ + public function resetIndex(string $providerId); + + + /** + * Deleting some IIndex, sent in an array + * + * @see IIndex + * + * @since 15.0.0 + * + * @param IIndex[] $indexes + */ + public function deleteIndexes(array $indexes); + + + /** + * Indexing a document. + * + * @see IndexDocument + * + * @since 15.0.0 + * + * @param IndexDocument $document + * + * @return IIndex + */ + public function indexDocument(IndexDocument $document): IIndex; + + + /** + * Searching documents, ISearchResult should be updated with the result of + * the search. + * + * @since 15.0.0 + * + * @param ISearchResult $result + * @param DocumentAccess $access + */ + public function searchRequest(ISearchResult $result, DocumentAccess $access); + + + /** + * Return a document based on its Id and the Provider. + * This is used when an admin execute ./occ fulltextsearch:document:platform + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * + * @return IndexDocument + */ + public function getDocument(string $providerId, string $documentId): IndexDocument; + + +} + diff --git a/lib/public/FullTextSearch/IFullTextSearchProvider.php b/lib/public/FullTextSearch/IFullTextSearchProvider.php new file mode 100644 index 00000000000..890b57d84c9 --- /dev/null +++ b/lib/public/FullTextSearch/IFullTextSearchProvider.php @@ -0,0 +1,304 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch; + + +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\IIndexOptions; +use OCP\FullTextSearch\Model\IndexDocument; +use OCP\FullTextSearch\Model\IRunner; +use OCP\FullTextSearch\Model\ISearchRequest; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Model\SearchTemplate; + + +/** + * Interface IFullTextSearchProvider + * + * This interface must be use when creating a Content Provider for FullTextSearch. + * + * A Content Provider is an extension to the FullTextSearch that will extract and + * provide content to the FullTextSearch. + * + * There is no limit to the number of Content Provider that can be integrated to + * FullTextSearch. Each Content Provider corresponding to a type of content + * available in Nextcloud (files, bookmarks, notes, deck cards, mails, ...) + * + * Content is split in document identified by an ID and the ID of the Content + * Provider. The content is indexed by a Search Platform that will returns a + * documentId as a result on a search request. + * + * + * To oversimplify the mechanism: + * + * - When indexing, FullTextSearch will ask for documents to every Content Provider. + * - On search, results from the Search Platform, identified by documentId, will + * be improved by each relative Content Provider. + * + * + * The Content Provider is a PHP class that implement this interface and is defined + * in appinfo/info.xml of the app that contains that class: + * + * <fulltextsearch> + * <provider>OCA\YourApp\YourContentProvider</provider> + * </fulltextsearch> + * + * Multiple Content Provider can be defined in a single app. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch + */ +interface IFullTextSearchProvider { + + + /** + * Must returns a unique Id used to identify the Content Provider. + * Id must contains only alphanumeric chars, with no space. + * + * @since 15.0.0 + * + * @return string + */ + public function getId(): string; + + + /** + * Must returns a descriptive name of the Content Provider. + * This is used in multiple places, so better use a clear display name. + * + * @since 15.0.0 + * + * @return string + */ + public function getName(): string; + + + /** + * Should returns the current configuration of the Content Provider. + * This is used to display the configuration when using the + * ./occ fulltextsearch:check command line. + * + * @since 15.0.0 + * + * @return array + */ + public function getConfiguration(): array; + + + /** + * Must returns a SearchTemplate that contains displayable items and + * available options to users when searching. + * + * @see SearchTemplate + * + * @since 15.0.0 + * + * @return SearchTemplate + */ + public function getSearchTemplate(): SearchTemplate; + + + /** + * Called when FullTextSearch is loading your Content Provider. + * + * @since 15.0.0 + */ + public function loadProvider(); + + + /** + * Set the wrapper of the currently executed process. + * Because the index process can be long and heavy, and because errors can + * be encountered during the process, the IRunner is a wrapper that allow the + * Content Provider to communicate with the process initiated by + * FullTextSearch. + * + * The IRunner is coming with some methods so the Content Provider can + * returns important information and errors to be displayed to the admin. + * + * @since 15.0.0 + * + * @param IRunner $runner + */ + public function setRunner(IRunner $runner); + + + /** + * This method is called when the administrator specify options when running + * the ./occ fulltextsearch:index or ./occ fulltextsearch:live + * + * @since 15.0.0 + * + * @param IIndexOptions $options + */ + public function setIndexOptions(IIndexOptions $options); + + + /** + * Returns all indexable document for a user as an array of IndexDocument. + * + * There is no need to fill each IndexDocument with content; at this point, + * only fill the object with the minimum information to not waste memory while + * still being able to identify the document it is referring to. + * + * FullTextSearch will call 2 other methods of this interface for each + * IndexDocument of the array, prior to their indexing: + * + * - first, to compare the date of the last index, + * - then, to fill each IndexDocument with complete data + * + * @see IndexDocument + * + * @since 15.0.0 + * + * @param string $userId + * + * @return IndexDocument[] + */ + public function generateIndexableDocuments(string $userId): array; + + + /** + * Called to verify that the document is not already indexed and that the + * old index is not up-to-date, using the IIndex from + * IndexDocument->getIndex() + * + * Returning true will not queue the current IndexDocument to any further + * operation and will continue on the next element from the list returned by + * generateIndexableDocuments(). + * + * @since 15.0.0 + * + * @param IndexDocument $document + * + * @return bool + */ + public function isDocumentUpToDate(IndexDocument $document): bool; + + + /** + * Must fill IndexDocument with all information relative to the document, + * before its indexing by the Search Platform. + * + * Method is called for each element returned previously by + * generateIndexableDocuments(). + * + * @see IndexDocument + * + * @since 15.0.0 + * + * @param IndexDocument $document + */ + public function fillIndexDocument(IndexDocument $document); + + + /** + * The Search Provider must create and return an IndexDocument + * based on the IIndex and its status. The IndexDocument must contains all + * information as it will be send for indexing. + * + * Method is called during a cron or a ./occ fulltextsearch:live after a + * new document is created, or an old document is set as modified. + * + * @since 15.0.0 + * + * @param IIndex $index + * + * @return IndexDocument + */ + public function updateDocument(IIndex $index): IndexDocument; + + + /** + * Called when an index is initiated by the administrator. + * This is should only be used in case of a specific mapping is needed. + * (ie. _almost_ never) + * + * @since 15.0.0 + * + * @param IFullTextSearchPlatform $platform + */ + public function onInitializingIndex(IFullTextSearchPlatform $platform); + + + /** + * Called when administrator is resetting the index. + * This is should only be used in case of a specific mapping has been + * created. + * + * @since 15.0.0 + * + * @param IFullTextSearchPlatform $platform + */ + public function onResettingIndex(IFullTextSearchPlatform $platform); + + + /** + * Method is called when a search request is initiated by a user, prior to + * be sent to the Search Platform. + * + * Your Content Provider can interact with the ISearchRequest to apply the + * search options and make the search more precise. + * + * @see ISearchRequest + * + * @since 15.0.0 + * + * @param ISearchRequest $searchRequest + */ + public function improveSearchRequest(ISearchRequest $searchRequest); + + + /** + * Method is called after results of a search are returned by the + * Search Platform. + * + * Your Content Provider can detail each entry with local data to improve + * the display of the search result. + * + * @see ISearchResult + * + * @since 15.0.0 + * + * @param ISearchResult $searchResult + */ + public function improveSearchResult(ISearchResult $searchResult); + + + /** + * not used yet. + * + * @since 15.0.0 + */ + public function unloadProvider(); + +} diff --git a/lib/public/FullTextSearch/Model/DocumentAccess.php b/lib/public/FullTextSearch/Model/DocumentAccess.php new file mode 100644 index 00000000000..ef199fb7385 --- /dev/null +++ b/lib/public/FullTextSearch/Model/DocumentAccess.php @@ -0,0 +1,363 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +use JsonSerializable; + + +/** + * Class DocumentAccess + * + * This object is used as a data transfer object when + * + * - indexing a document, + * - generating a search request. + * + * During the index, it is used to define which users, groups, circles, ... + * have access to the IndexDocument + * + * During the search, it is internally use to define to which group, circles, ... + * a user that perform the search belongs to. + * + * @see IndexDocument::setAccess + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +final class DocumentAccess implements JsonSerializable { + + /** @var string */ + private $ownerId; + + /** @var string */ + private $viewerId = ''; + + /** @var array */ + private $users = []; + + /** @var array */ + private $groups = []; + + /** @var array */ + private $circles = []; + + /** @var array */ + private $links = []; + + + /** + * Owner of the document can be set at the init of the object. + * + * @since 15.0.0 + * + * DocumentAccess constructor. + * + * @param string $ownerId + */ + public function __construct(string $ownerId = '') { + $this->setOwnerId($ownerId); + } + + + /** + * Set the Owner of the document. + * + * @since 15.0.0 + * + * @param string $ownerId + * + * @return DocumentAccess + */ + public function setOwnerId(string $ownerId) { + $this->ownerId = $ownerId; + + return $this; + } + + /** + * Get the Owner of the document. + * + * @since 15.0.0 + * + * @return string + */ + public function getOwnerId(): string { + return $this->ownerId; + } + + + /** + * Set the viewer of the document. + * + * @since 15.0.0 + * + * @param string $viewerId + * + * @return DocumentAccess + */ + public function setViewerId(string $viewerId): DocumentAccess { + $this->viewerId = $viewerId; + + return $this; + } + + /** + * Get the viewer of the document. + * + * @since 15.0.0 + * + * @return string + */ + public function getViewerId(): string { + return $this->viewerId; + } + + + /** + * Set the list of users that have read access to the document. + * + * @since 15.0.0 + * + * @param array $users + * + * @return DocumentAccess + */ + public function setUsers(array $users): DocumentAccess { + $this->users = $users; + + return $this; + } + + /** + * Add an entry to the list of users that have read access to the document. + * + * @since 15.0.0 + * + * @param string $user + * + * @return DocumentAccess + */ + public function addUser(string $user): DocumentAccess { + $this->users[] = $user; + + return $this; + } + + /** + * Add multiple entries to the list of users that have read access to the + * document. + * + * @since 15.0.0 + * + * @param array $users + * + * @return DocumentAccess + */ + public function addUsers($users): DocumentAccess { + $this->users = array_merge($this->users, $users); + + return $this; + } + + /** + * Get the complete list of users that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getUsers(): array { + return $this->users; + } + + + /** + * Set the list of groups that have read access to the document. + * + * @since 15.0.0 + * + * @param array $groups + * + * @return DocumentAccess + */ + public function setGroups(array $groups): DocumentAccess { + $this->groups = $groups; + + return $this; + } + + /** + * Add an entry to the list of groups that have read access to the document. + * + * @since 15.0.0 + * + * @param string $group + * + * @return DocumentAccess + */ + public function addGroup(string $group): DocumentAccess { + $this->groups[] = $group; + + return $this; + } + + /** + * Add multiple entries to the list of groups that have read access to the + * document. + * + * @since 15.0.0 + * + * @param array $groups + * + * @return DocumentAccess + */ + public function addGroups(array $groups) { + $this->groups = array_merge($this->groups, $groups); + + return $this; + } + + /** + * Get the complete list of groups that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getGroups(): array { + return $this->groups; + } + + + /** + * Set the list of circles that have read access to the document. + * + * @since 15.0.0 + * + * @param array $circles + * + * @return DocumentAccess + */ + public function setCircles(array $circles): DocumentAccess { + $this->circles = $circles; + + return $this; + } + + /** + * Add an entry to the list of circles that have read access to the document. + * + * @since 15.0.0 + * + * @param string $circle + * + * @return DocumentAccess + */ + public function addCircle(string $circle): DocumentAccess { + $this->circles[] = $circle; + + return $this; + } + + /** + * Add multiple entries to the list of groups that have read access to the + * document. + * + * @since 15.0.0 + * + * @param array $circles + * + * @return DocumentAccess + */ + public function addCircles(array $circles): DocumentAccess { + $this->circles = array_merge($this->circles, $circles); + + return $this; + } + + /** + * Get the complete list of circles that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getCircles(): array { + return $this->circles; + } + + + /** + * Set the list of links that have read access to the document. + * + * @since 15.0.0 + * + * @param array $links + * + * @return DocumentAccess + */ + public function setLinks(array $links): DocumentAccess { + $this->links = $links; + + return $this; + } + + /** + * Get the list of links that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getLinks(): array { + return $this->links; + } + + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize(): array { + return [ + 'ownerId' => $this->getOwnerId(), + 'viewerId' => $this->getViewerId(), + 'users' => $this->getUsers(), + 'groups' => $this->getGroups(), + 'circles' => $this->getCircles(), + 'links' => $this->getLinks() + ]; + } +} + diff --git a/lib/public/FullTextSearch/Model/IIndex.php b/lib/public/FullTextSearch/Model/IIndex.php new file mode 100644 index 00000000000..adfdf34aee6 --- /dev/null +++ b/lib/public/FullTextSearch/Model/IIndex.php @@ -0,0 +1,292 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for extcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +/** + * Interface IIndex + * + * Index are generated by FullTextSearch to manage the status of a document + * regarding the date of the last index and the date of the last modification + * of the original document. + * + * The uniqueness of an IndexDocument is made by the Id of the Content Provider + * and the Id of the original document within the Content Provider. + * + * We will call original document the source from which the IndexDocument is + * generated. As an example, an original document can be a file, a mail, ... + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface IIndex { + + + const INDEX_OK = 1; + const INDEX_IGNORE = 2; + + const INDEX_META = 4; + const INDEX_CONTENT = 8; + const INDEX_FULL = 12; + const INDEX_REMOVE = 16; + + const INDEX_DONE = 32; + const INDEX_FAILED = 64; + + const ERROR_FAILED = 1; + const ERROR_FAILED2 = 2; + const ERROR_FAILED3 = 4; + + const ERROR_SEV_1 = 1; + const ERROR_SEV_2 = 2; + const ERROR_SEV_3 = 3; + const ERROR_SEV_4 = 4; + + + /** + * Get the Id of the Content Provider. + * + * @since 15.0.0 + * + * @return string + */ + public function getProviderId(): string; + + + /** + * Get the Id of the original document. + * + * @since 15.0.0 + * + * @return string + */ + public function getDocumentId(): string; + + + /** + * Set the source of the original document. + * + * @since 15.0.0 + * + * @param string $source + * + * @return IIndex + */ + public function setSource(string $source): IIndex; + + /** + * Get the source of the original document. + * + * @since 15.0.0 + * + * @return string + */ + public function getSource(): string; + + + /** + * Set the owner of the original document. + * + * @since 15.0.0 + * + * @param string $ownerId + * + * @return IIndex + */ + public function setOwnerId(string $ownerId): IIndex; + + /** + * Get the owner of the original document. + * + * @since 15.0.0 + * + * @return string + */ + public function getOwnerId(): string; + + + /** + * Set the current index status (bit flag) of the original document. + * If $reset is true, the status is reset to the defined value. + * + * @since 15.0.0 + * + * @param int $status + * @param bool $reset + * + * @return IIndex + */ + public function setStatus(int $status, bool $reset = false): IIndex; + + /** + * Get the current index status of the original document. + * + * @since 15.0.0 + * + * @return int + */ + public function getStatus(): int; + + /** + * Check if the document fit a specific status. + * + * @since 15.0.0 + * + * @param int $status + * + * @return bool + */ + public function isStatus(int $status): bool; + + /** + * Remove a status. + * + * @since 15.0.0 + * + * @param int $status + * + * @return IIndex + */ + public function unsetStatus(int $status): IIndex; + + + /** + * Add an option related to the original document (as string). + * + * @since 15.0.0 + * + * @param string $option + * @param string|int $value + * + * @return IIndex + */ + public function addOption(string $option, string $value): IIndex; + + /** + * Add an option related to the original document (as integer). + * + * @since 15.0.0 + * + * @param string $option + * @param int $value + * + * @return IIndex + */ + public function addOptionInt(string $option, int $value): IIndex; + + /** + * Get the option related to the original document (as string). + * + * @since 15.0.0 + * + * @param string $option + * @param string $default + * + * @return string + */ + public function getOption(string $option, string $default = ''): string; + + /** + * Get the option related to the original document (as integer). + * + * @since 15.0.0 + * + * @param string $option + * @param int $default + * + * @return int + */ + public function getOptionInt(string $option, int $default = 0): int; + + /** + * Get all options related to the original document. + * + * @since 15.0.0 + * + * @return array + */ + public function getOptions(): array; + + + /** + * Add an error log related to the Index. + * + * @since 15.0.0 + * + * @param string $message + * @param string $exception + * @param int $sev + * + * @return IIndex + */ + public function addError(string $message, string $exception = '', int $sev = self::ERROR_SEV_3): IIndex; + + /** + * Returns the number of known errors related to the Index. + * + * @since 15.0.0 + * + * @return int + */ + public function getErrorCount(): int; + + /** + * Reset all error logs related to the Index. + * + * @since 15.0.0 + */ + public function resetErrors(): IIndex; + + + /** + * Set the date of the last index. + * + * @since 15.0.0 + * + * @param int $lastIndex + * + * @return IIndex + */ + public function setLastIndex(int $lastIndex = -1): IIndex; + + /** + * Get the date of the last index. + * + * @since 15.0.0 + * + * @return int + */ + public function getLastIndex(): int; + + +} + diff --git a/lib/public/FullTextSearch/Model/IIndexOptions.php b/lib/public/FullTextSearch/Model/IIndexOptions.php new file mode 100644 index 00000000000..8cc5da13d4d --- /dev/null +++ b/lib/public/FullTextSearch/Model/IIndexOptions.php @@ -0,0 +1,86 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +/** + * Interface IIndexOptions + * + * IndexOptions are created in FullTextSearch when an admin initiate an index + * from the command line: + * + * ./occ fulltextsearch:index "{\"option1\": \"value\", \"option2\": true}" + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface IIndexOptions { + + + /** + * Get the value (as a string) for an option. + * + * @since 15.0.0 + * + * @param string $option + * @param string $default + * + * @return string + */ + public function getOption(string $option, string $default = ''): string; + + /** + * Get the value (as an array) for an option. + * + * @since 15.0.0 + * + * @param string $option + * @param array $default + * + * @return array + */ + public function getOptionArray(string $option, array $default = []): array; + + /** + * Get the value (as an boolean) for an option. + * + * @since 15.0.0 + * + * @param string $option + * @param bool $default + * + * @return bool + */ + public function getOptionBool(string $option, bool $default): bool; + +} + diff --git a/lib/public/FullTextSearch/Model/IRunner.php b/lib/public/FullTextSearch/Model/IRunner.php new file mode 100644 index 00000000000..0dff82bd5a0 --- /dev/null +++ b/lib/public/FullTextSearch/Model/IRunner.php @@ -0,0 +1,142 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +/** + * Interface IRunner + * + * The indexing process can be long and heavy, and because errors can + * be encountered the process is wrapped using this interface. + * It allows the any extension of FullTextSearch to communicate with the process. + * + * The IRunner is coming with some methods so the Search Platform can + * returns important information and errors to be displayed to the admin. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface IRunner { + + + const RESULT_TYPE_SUCCESS = 1; + const RESULT_TYPE_WARNING = 4; + const RESULT_TYPE_FAIL = 9; + + + /** + * Info are displayed in the user interface when an admin execute the + * ./occ fulltextsearch:index command. + * + * quick list of info that can be edited: + * 'documentId', 'info', 'title', 'resultIndex', 'resultStatus', + * 'content', 'documentCurrent', 'documentTotal', 'progressStatus', + * 'errorCurrent', 'errorException', 'errorIndex'. + * + * List of all editable info can be find in the Command\Index.php of the + * FullTextSearch app. + * (look for a comment 'full list of info that can be edited') + * + * @since 15.0.0 + * + * @param string $info + * @param string $value + */ + public function setInfo(string $info, string $value); + + + /** + * This method should be used when editing multiple info to avoid too many + * refresh of the interface. + * + * @since 15.0.0 + * + * @param array $data + */ + public function setInfoArray(array $data); + + + /** + * Method used to update the current Action when an index is running. + * + * This method should be used instead of manually update the 'action' using + * setInfo()/setInfoArray() as it is also used to keep the process alive, + * manage the input, and some statistics of the load of the process. + * + * $action is a string with no space + * $force should be set to true if the action is heavy while being executed + * multiple times + * + * @since 15.0.0 + * + * @param string $action + * @param bool $force + * + * @return string + * @throws \Exception + */ + public function updateAction(string $action = '', bool $force = false): string; + + + /** + * Call this method in a Search Platform or Content Provider if there is an + * issue while generating a document or while indexing the current document. + * This is used to store and display errors in the UI during an index to help + * admin to keep track of errors. + * + * @since 15.0.0 + * + * @param IIndex $index + * @param string $message + * @param string $class + * @param int $sev + */ + public function newIndexError(IIndex $index, string $message, string $class = '', int $sev = 3); + + + /** + * Call this method only in a Search Platform after an index of a document. + * This is used to store and display results (good or bad) in the UI during + * an index to help admin to keep track of fail and successful indexes. + * + * @since 15.0.0 + * + * @param IIndex $index + * @param string $message + * @param string $status + * @param int $type + */ + public function newIndexResult(IIndex $index, string $message, string $status, int $type); + + +} + diff --git a/lib/public/FullTextSearch/Model/ISearchRequest.php b/lib/public/FullTextSearch/Model/ISearchRequest.php new file mode 100644 index 00000000000..073b4805f63 --- /dev/null +++ b/lib/public/FullTextSearch/Model/ISearchRequest.php @@ -0,0 +1,326 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +/** + * Interface ISearchRequest + * + * When a search request is initiated, from a request from the front-end or using + * the IFullTextSearchManager::search() method, FullTextSearch will create a + * SearchRequest object, based on this interface. + * + * The object will be passed to the targeted Content Provider so it can convert + * search options using available method. + * + * The object is then encapsulated in a SearchResult and send to the + * Search Platform. + * + * @since 15.0.0 + * + * + * @package OCP\FullTextSearch\Model + */ +interface ISearchRequest { + + + /** + * Get the maximum number of results to be returns by the Search Platform. + * + * @since 15.0.0 + * + * @return int + */ + public function getSize(): int; + + + /** + * Get the current page. + * Used by pagination. + * + * @since 15.0.0 + * + * @return int + */ + public function getPage(): int; + + + /** + * Get the author of the request. + * + * @since 15.0.0 + * + * @return string + */ + public function getAuthor(): string; + + /** + * Get the searched string. + * + * @since 15.0.0 + * + * @return string + */ + public function getSearch(): string; + + + /** + * Get the value of an option (as string). + * + * @since 15.0.0 + * + * @param string $option + * @param string $default + * + * @return string + */ + public function getOption(string $option, string $default = ''): string; + + /** + * Get the value of an option (as array). + * + * @since 15.0.0 + * + * @param string $option + * @param array $default + * + * @return array + */ + public function getOptionArray(string $option, array $default = []): array; + + + /** + * Limit the search to a part of the document. + * + * @since 15.0.0 + * + * @param string $part + * + * @return ISearchRequest + */ + public function addPart(string $part): ISearchRequest; + + /** + * Limit the search to an array of parts of the document. + * + * @since 15.0.0 + * + * @param array $parts + * + * @return ISearchRequest + */ + public function setParts(array $parts): ISearchRequest; + + /** + * Get the parts the search is limited to. + * + * @since 15.0.0 + * + * @return array + */ + public function getParts(): array; + + + /** + * Limit the search to a specific meta tag. + * + * @since 15.0.0 + * + * @param string $tag + * + * @return ISearchRequest + */ + public function addMetaTag(string $tag): ISearchRequest; + + /** + * Get the meta tags the search is limited to. + * + * @since 15.0.0 + * + * @return array + */ + public function getMetaTags(): array; + + /** + * Limit the search to an array of meta tags. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return ISearchRequest + */ + public function setMetaTags(array $tags): IsearchRequest; + + + /** + * Limit the search to a specific sub tag. + * + * @since 15.0.0 + * + * @param string $source + * @param string $tag + * + * @return ISearchRequest + */ + public function addSubTag(string $source, string $tag): ISearchRequest; + + /** + * Get the sub tags the search is limited to. + * + * @since 15.0.0 + * + * @param bool $formatted + * + * @return array + */ + public function getSubTags(bool $formatted): array; + + /** + * Limit the search to an array of sub tags. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return ISearchRequest + */ + public function setSubTags(array $tags): ISearchRequest; + + + /** + * Limit the search to a specific field of the mapping, using a full string. + * + * @since 15.0.0 + * + * @param string $field + * + * @return ISearchRequest + */ + public function addLimitField(string $field): ISearchRequest; + + /** + * Get the fields the search is limited to. + * + * @since 15.0.0 + * + * @return array + */ + public function getLimitFields(): array; + + + /** + * Limit the search to a specific field of the mapping, using a wildcard on + * the search string. + * + * @since 15.0.0 + * + * @param string $field + * + * @return ISearchRequest + */ + public function addWildcardField(string $field): ISearchRequest; + + /** + * Get the limit to field of the mapping. + * + * @since 15.0.0 + * + * @return array + */ + public function getWildcardFields(): array; + + + /** + * Filter the results, based on a group of field, using regex + * + * @since 15.0.0 + * + * @param array $filters + * + * @return ISearchRequest + */ + public function addRegexFilters(array $filters): ISearchRequest; + + /** + * Get the regex filters the search is limit to. + * + * @since 15.0.0 + * + * @return array + */ + public function getRegexFilters(): array; + + + /** + * Filter the results, based on a group of field, using wildcard + * + * @since 15.0.0 + * + * @param array $filter + * + * @return ISearchRequest + */ + public function addWildcardFilter(array $filter): ISearchRequest; + + /** + * Get the wildcard filters the search is limit to. + * + * @since 15.0.0 + * + * @return array + */ + public function getWildcardFilters(): array; + + + /** + * Add an extra field to the search. + * + * @since 15.0.0 + * + * @param string $field + * + * @return ISearchRequest + */ + public function addField(string $field): ISearchRequest; + + /** + * Get the list of extra field to search into. + * + * @since 15.0.0 + * + * @return array + */ + public function getFields(): array; + + +} + diff --git a/lib/public/FullTextSearch/Model/ISearchResult.php b/lib/public/FullTextSearch/Model/ISearchResult.php new file mode 100644 index 00000000000..a7dcba82f5c --- /dev/null +++ b/lib/public/FullTextSearch/Model/ISearchResult.php @@ -0,0 +1,198 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +use OCP\FullTextSearch\IFullTextSearchProvider; + + +/** + * Interface ISearchResult + * + * When a search request is initiated, FullTextSearch will create a SearchResult + * object, based on this interface, containing the SearchRequest and the targeted + * Content Provider. + * + * The object will be passed to the Search Platform, which will proceed to the + * search and fill the SearchResult object with results. + * + * Then, the object will be passed to the targeted Content Provider that will + * improve the Search Results with detailed informations. + * + * Finally, the SearchResult is returned to the original search request. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface ISearchResult { + + + /** + * Get the original SearchRequest. + * + * @see ISearchRequest + * + * @since 15.0.0 + * + * @return ISearchRequest + */ + public function getRequest(): ISearchRequest; + + /** + * Get the targeted Content Provider. + * + * @since 15.0.0 + * + * @return IFullTextSearchProvider + */ + public function getProvider(): IFullTextSearchProvider; + + + /** + * Add an IndexDocument as one of the result of the search request. + * + * @since 15.0.0 + * + * @param IndexDocument $document + * + * @return ISearchResult + */ + public function addDocument(IndexDocument $document): ISearchResult; + + /** + * Returns all result of the search request, in an array of IndexDocument. + * + * @since 15.0.0 + * + * @return array + */ + public function getDocuments(): array; + + /** + * Set an array of IndexDocument as the result of the search request. + * + * @since 15.0.0 + * + * @param IndexDocument[] $documents + * + * @return ISearchResult + */ + public function setDocuments(array $documents): ISearchResult; + + + /** + * Add an aggregation to the result. + * + * @since 15.0.0 + * + * @param string $category + * @param string $value + * @param int $count + * + * @return ISearchResult + */ + public function addAggregation(string $category, string $value, int $count): ISearchResult; + + /** + * Get all aggregations. + * + * @since 15.0.0 + * + * @param string $category + * + * @return array + */ + public function getAggregations(string $category): array; + + + /** + * Set the raw result of the request. + * + * @since 15.0.0 + * + * @param string $result + * + * @return ISearchResult + */ + public function setRawResult(string $result): ISearchResult; + + + /** + * Set the total number of results for the search request. + * Used by pagination. + * + * @since 15.0.0 + * + * @param int $total + * + * @return ISearchResult + */ + public function setTotal(int $total): ISearchResult; + + + /** + * Set the top score for the search request. + * + * @since 15.0.0 + * + * @param int $score + * + * @return ISearchResult + */ + public function setMaxScore(int $score): ISearchResult; + + + /** + * Set the time spent by the request to perform the search. + * + * @since 15.0.0 + * + * @param int $time + * + * @return ISearchResult + */ + public function setTime(int $time): ISearchResult; + + + /** + * Set to true if the request timed out. + * + * @since 15.0.0 + * + * @param bool $timedOut + * + * @return ISearchResult + */ + public function setTimedOut(bool $timedOut): ISearchResult; + +} + diff --git a/lib/public/FullTextSearch/Model/IndexDocument.php b/lib/public/FullTextSearch/Model/IndexDocument.php new file mode 100644 index 00000000000..a73b702e506 --- /dev/null +++ b/lib/public/FullTextSearch/Model/IndexDocument.php @@ -0,0 +1,898 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +use JsonSerializable; + +/** + * Class IndexDocument + * + * This is one of the main class of the FullTextSearch, used as a data transfer + * object. An IndexDocument is created to manage documents around FullTextSearch, + * during an index and during a search. + * The uniqueness of an IndexDocument is made by the Id of the Content Provider + * and the Id of the original document within the Content Provider. + * + * We will call original document the source from which the IndexDocument is + * generated. As an example, an original document can be a file, a mail, ... + * + * @since 15.0.0 + * + * @package OC\FullTextSearch\Model + */ +class IndexDocument implements JsonSerializable { + + + const NOT_ENCODED = 0; + const ENCODED_BASE64 = 1; + + + /** @var string */ + protected $id; + + /** @var string */ + protected $providerId; + + /** @var DocumentAccess */ + protected $access; + + /** @var IIndex */ + protected $index; + + /** @var int */ + protected $modifiedTime = 0; + + /** @var string */ + protected $source = ''; + + /** @var array */ + protected $tags = []; + + /** @var array */ + protected $metaTags = []; + + /** @var array */ + protected $subTags = []; + + /** @var string */ + protected $title = ''; + + /** @var string */ + protected $content = ''; + + /** @var string */ + protected $hash = ''; + + /** @var array */ + protected $parts = []; + + /** @var string */ + protected $link = ''; + + /** @var array */ + protected $more = []; + + /** @var array */ + protected $excerpts = []; + + /** @var string */ + protected $score = ''; + + /** @var array */ + protected $info = []; + + /** @var int */ + protected $contentEncoded; + + + /** + * IndexDocument constructor. + * + * On creation, we assure the uniqueness of the object using the providerId + * and the Id of the original document. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + */ + public function __construct(string $providerId, string $documentId) { + $this->providerId = $providerId; + $this->id = $documentId; + } + + + /** + * Returns the Id of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getId(): string { + return $this->id; + } + + + /** + * Returns the Id of the provider. + * + * @since 15.0.0 + * + * @return string + */ + final public function getProviderId(): string { + return $this->providerId; + } + + + /** + * Set the Index related to the IndexDocument. + * + * @see IIndex + * + * @since 15.0.0 + * + * @param IIndex $index + * + * @return IndexDocument + */ + final public function setIndex(IIndex $index): IndexDocument { + $this->index = $index; + + return $this; + } + + /** + * Get the Index. + * + * @since 15.0.0 + * + * @return IIndex + */ + final public function getIndex(): IIndex { + return $this->index; + } + + + /** + * Set the modified time of the original document. + * + * @since 15.0.0 + * + * @param int $modifiedTime + * + * @return IndexDocument + */ + final public function setModifiedTime(int $modifiedTime): IndexDocument { + $this->modifiedTime = $modifiedTime; + + return $this; + } + + /** + * Get the modified time of the original document. + * + * @since 15.0.0 + * + * @return int + */ + final public function getModifiedTime(): int { + return $this->modifiedTime; + } + + /** + * Check if the original document of the IndexDocument is older than $time. + * + * @since 15.0.0 + * + * @param int $time + * + * @return bool + */ + final public function isOlderThan(int $time): bool { + return ($this->modifiedTime < $time); + } + + + /** + * Set the read rights of the original document using a DocumentAccess. + * + * @see DocumentAccess + * + * @since 15.0.0 + * + * @param DocumentAccess $access + * + * @return $this + */ + final public function setAccess(DocumentAccess $access) { + $this->access = $access; + + return $this; + } + + /** + * Get the DocumentAccess related to the original document. + * + * @since 15.0.0 + * + * @return DocumentAccess + */ + final public function getAccess(): DocumentAccess { + return $this->access; + } + + + /** + * Add a tag to the list. + * + * @since 15.0.0 + * + * @param string $tag + * + * @return IndexDocument + */ + final public function addTag(string $tag): IndexDocument { + $this->tags[] = $tag; + + return $this; + } + + /** + * Set the list of tags assigned to the original document. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return IndexDocument + */ + final public function setTags(array $tags): IndexDocument { + $this->tags = $tags; + + return $this; + } + + /** + * Get the list of tags assigned to the original document. + * + * @since 15.0.0 + * + * @return array + */ + final public function getTags(): array { + return $this->tags; + } + + + /** + * Add a meta tag to the list. + * + * @since 15.0.0 + * + * @param string $tag + * + * @return IndexDocument + */ + final public function addMetaTag(string $tag): IndexDocument { + $this->metaTags[] = $tag; + + return $this; + } + + /** + * Set the list of meta tags assigned to the original document. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return IndexDocument + */ + final public function setMetaTags(array $tags): IndexDocument { + $this->metaTags = $tags; + + return $this; + } + + /** + * Get the list of meta tags assigned to the original document. + * + * @since 15.0.0 + * + * @return array + */ + final public function getMetaTags(): array { + return $this->metaTags; + } + + + /** + * Add a sub tag to the list. + * + * @since 15.0.0 + * + * @param string $sub + * @param string $tag + * + * @return IndexDocument + */ + final public function addSubTag(string $sub, string $tag): IndexDocument { + $this->subTags[$sub] = $tag; + + return $this; + } + + /** + * Set the list of sub tags assigned to the original document. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return IndexDocument + */ + final public function setSubTags(array $tags): IndexDocument { + $this->subTags = $tags; + + return $this; + } + + /** + * Get the list of sub tags assigned to the original document. + * If $formatted is true, the result will be formatted in a one + * dimensional array. + * + * @since 15.0.0 + * + * @param bool $formatted + * + * @return array + */ + final public function getSubTags(bool $formatted = false): array { + if ($formatted === false) { + return $this->subTags; + } + + $subTags = []; + $ak = array_keys($this->subTags); + foreach ($ak as $source) { + $tags = $this->subTags[$source]; + foreach ($tags as $tag) { + $subTags[] = $source . '_' . $tag; + } + } + + return $subTags; + } + + + /** + * Set the source of the original document. + * + * @since 15.0.0 + * + * @param string $source + * + * @return IndexDocument + */ + final public function setSource(string $source): IndexDocument { + $this->source = $source; + + return $this; + } + + /** + * Get the source of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getSource(): string { + return $this->source; + } + + + /** + * Set the title of the original document. + * + * @since 15.0.0 + * + * @param string $title + * + * @return IndexDocument + */ + final public function setTitle(string $title): IndexDocument { + $this->title = $title; + + return $this; + } + + /** + * Get the title of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getTitle(): string { + return $this->title; + } + + + /** + * Set the content of the document. + * $encoded can be NOT_ENCODED or ENCODED_BASE64 if the content is raw or + * encoded in base64. + * + * @since 15.0.0 + * + * @param string $content + * @param int $encoded + * + * @return IndexDocument + */ + final public function setContent(string $content, int $encoded = 0): IndexDocument { + $this->content = $content; + $this->contentEncoded = $encoded; + + return $this; + } + + /** + * Get the content of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getContent(): string { + return $this->content; + } + + /** + * Returns the type of the encoding on the content. + * + * @since 15.0.0 + * + * @return int + */ + final public function isContentEncoded(): int { + return $this->contentEncoded; + } + + /** + * Return the size of the content. + * + * @since 15.0.0 + * + * @return int + */ + final public function getContentSize(): int { + return strlen($this->getContent()); + } + + + /** + * Generate an hash, based on the content of the original document. + * + * @since 15.0.0 + * + * @return IndexDocument + */ + final public function initHash(): IndexDocument { + if ($this->getContent() === '' || is_null($this->getContent())) { + return $this; + } + + $this->hash = hash("md5", $this->getContent()); + + return $this; + } + + /** + * Set the hash of the original document. + * + * @since 15.0.0 + * + * @param string $hash + * + * @return IndexDocument + */ + final public function setHash(string $hash): IndexDocument { + $this->hash = $hash; + + return $this; + } + + /** + * Get the hash of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getHash(): string { + return $this->hash; + } + + + /** + * Add a part, identified by a string, and its content. + * + * It is strongly advised to use alphanumerical chars with no space in the + * $part string. + * + * @since 15.0.0 + * + * @param string $part + * @param string $content + * + * @return IndexDocument + */ + final public function addPart(string $part, string $content): IndexDocument { + $this->parts[$part] = $content; + + return $this; + } + + /** + * Set all parts and their content. + * + * @since 15.0.0 + * + * @param array $parts + * + * @return IndexDocument + */ + final public function setParts(array $parts): IndexDocument { + $this->parts = $parts; + + return $this; + } + + /** + * Get all parts of the IndexDocument. + * + * @since 15.0.0 + * + * @return array + */ + final public function getParts(): array { + return $this->parts; + } + + + /** + * Add a link, usable by the frontend. + * + * @since 15.0.0 + * + * @param string $link + * + * @return IndexDocument + */ + final public function setLink(string $link): IndexDocument { + $this->link = $link; + + return $this; + } + + /** + * Get the link. + * + * @since 15.0.0 + * + * @return string + */ + final public function getLink(): string { + return $this->link; + } + + + /** + * Set more information that couldn't be set using other method. + * + * @since 15.0.0 + * + * @param array $more + * + * @return IndexDocument + */ + final public function setMore(array $more): IndexDocument { + $this->more = $more; + + return $this; + } + + /** + * Get more information. + * + * @since 15.0.0 + * + * @return array + */ + final public function getMore(): array { + return $this->more; + } + + + /** + * Add some excerpt of the content of the original document, usually based + * on the search request. + * + * @since 15.0.0 + * + * @param string $excerpt + * + * @return IndexDocument + */ + final public function addExcerpt(string $excerpt): IndexDocument { + $excerpt = $this->cleanExcerpt($excerpt); + + $this->excerpts[] = $excerpt; + + return $this; + } + + /** + * Set all excerpts of the content of the original document. + * + * @since 15.0.0 + * + * @param array $excerpts + * + * @return IndexDocument + */ + final public function setExcerpts(array $excerpts): IndexDocument { + $excerpts = array_map([$this, 'cleanExcerpt'], $excerpts); + + $this->excerpts = $excerpts; + + return $this; + } + + /** + * Get all excerpts of the content of the original document. + * + * @since 15.0.0 + * + * @return array + */ + final public function getExcerpts(): array { + return $this->excerpts; + } + + /** + * Clean excerpt. + * + * @since 15.0.0 + * + * @param string $excerpt + * + * @return string + */ + final public function cleanExcerpt(string $excerpt): string { + $excerpt = str_replace("\\n", ' ', $excerpt); + $excerpt = str_replace("\\r", ' ', $excerpt); + $excerpt = str_replace("\\t", ' ', $excerpt); + $excerpt = str_replace("\n", ' ', $excerpt); + $excerpt = str_replace("\r", ' ', $excerpt); + $excerpt = str_replace("\t", ' ', $excerpt); + + return $excerpt; + } + + /** + * Set the score to the result assigned to this document during a search + * request. + * + * @since 15.0.0 + * + * @param string $score + * + * @return IndexDocument + */ + final public function setScore(string $score): IndexDocument { + $this->score = $score; + + return $this; + } + + /** + * Get the score. + * + * @since 15.0.0 + * + * @return string + */ + final public function getScore(): string { + return $this->score; + } + + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as string) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IndexDocument before its + * indexing. + * + * @since 15.0.0 + * + * @param string $info + * @param string $value + * + * @return IndexDocument + */ + final public function setInfo(string $info, string $value): IndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (string) + * + * @since 15.0.0 + * + * @param string $info + * @param string $default + * + * @return string + */ + final public function getInfo(string $info, string $default = ''): string { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as array) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IndexDocument before its + * indexing. + * + * @since 15.0.0 + * + * @param string $info + * @param array $value + * + * @return IndexDocument + */ + final public function setInfoArray(string $info, array $value): IndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (array) + * + * @since 15.0.0 + * + * @param string $info + * @param array $default + * + * @return array + */ + final public function getInfoArray(string $info, array $default = []): array { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Get all info. + * + * @since 15.0.0 + * + * @return array + */ + final public function getInfoAll(): array { + + $info = []; + foreach ($this->info as $k => $v) { + if (substr($k, 0, 1) === '_') { + continue; + } + + $info[$k] = $v; + } + + return $info; + } + + + /** + * @since 15.0.0 + * + * On some version of PHP, it is better to force destruct the object. + * And during the index, the number of generated IndexDocument can be + * _huge_. + */ + public function __destruct() { + unset($this->id); + unset($this->providerId); + unset($this->access); + unset($this->modifiedTime); + unset($this->title); + unset($this->content); + unset($this->hash); + unset($this->link); + unset($this->source); + unset($this->tags); + unset($this->metaTags); + unset($this->subTags); + unset($this->more); + unset($this->excerpts); + unset($this->score); + unset($this->info); + unset($this->contentEncoded); + } + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize() { + return [ + 'id' => $this->getId(), + 'providerId' => $this->getProviderId(), + 'access' => $this->access, + 'modifiedTime' => $this->getModifiedTime(), + 'title' => $this->getTitle(), + 'link' => $this->getLink(), + 'index' => $this->index, + 'source' => $this->getSource(), + 'info' => $this->getInfoAll(), + 'hash' => $this->getHash(), + 'contentSize' => $this->getContentSize(), + 'tags' => $this->getTags(), + 'metatags' => $this->getMetaTags(), + 'subtags' => $this->getSubTags(), + 'more' => $this->getMore(), + 'excerpts' => $this->getExcerpts(), + 'score' => $this->getScore() + ]; + } + +} + diff --git a/lib/public/FullTextSearch/Model/SearchOption.php b/lib/public/FullTextSearch/Model/SearchOption.php new file mode 100644 index 00000000000..ae6ad3241b6 --- /dev/null +++ b/lib/public/FullTextSearch/Model/SearchOption.php @@ -0,0 +1,296 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +use JsonSerializable; + + +/** + * @since 15.0.0 + * + * Class SearchOption + * + * @package OCP\FullTextSearch\Model + */ +final class SearchOption implements JsonSerializable { + + + const CHECKBOX = 'checkbox'; + const INPUT = 'input'; + + const INPUT_SMALL = 'small'; + + + /** @var string */ + private $name = ''; + + /** @var string */ + private $title = ''; + + /** @var string */ + private $type = ''; + + /** @var string */ + private $size = ''; + + /** @var string */ + private $placeholder = ''; + + + /** + * * + * + * The array can be empty in case no search options are available. + * The format of the array must be like this: + * + * [ + * 'panel' => [ + * 'options' => [ + * OPTION1, + * OPTION2, + * OPTION3 + * ] + * ], + * 'navigation' => [ + * 'icon' => 'css-class-of-the-icon', + * 'options' => [ + * OPTION1, + * OPTION2, + * OPTION3 + * ] + * ] + * ] + * + * - PANEL contains entries that will be displayed in the app itself, when + * a search is initiated. + * - NAVIGATION contains entries that will be available when using the + * FullTextSearch navigation page + * - OPTION is an element that define each option available to the user. + * + * The format for the options must be like this: + * + * [ + * 'name' => 'name_of_the_option', + * 'title' => 'Name displayed in the panel', + * 'type' => '', + * 'size' => '' (optional), + * 'placeholder' => '' (optional) + * ] + * + * - NAME is the variable name that is sent to the IFullTextSearchProvider + * when a ISearchRequest is requested. (keys in the array returned by the + * ISearchRequest->getOptions()) + * - TYPE can be 'input' or 'checkbox' + * - SIZE is only used in case TYPE='input', default is 'large' but can be + * 'small' + * - PLACEHOLDER is only used in case TYPE='input', default is empty. + */ + + /** + * SearchOption constructor. + * + * Some value can be setduring the creation of the object. + * + * @since 15.0.0 + * + * @param string $name + * @param string $title + * @param string $type + * @param string $size + * @param string $placeholder + */ + public function __construct(string $name = '', string $title = '', string $type = '', string $size = '', string $placeholder = '') { + $this->name = $name; + $this->title = $title; + $this->type = $type; + $this->size = $size; + $this->placeholder = $placeholder; + } + + + /** + * Set the name/key of the option. + * The string should only contains alphanumerical chars and underscore. + * The key can be retrieve when using ISearchRequest::getOption + * + * @see ISearchRequest::getOption + * + * @since 15.0.0 + * + * @param string $name + * + * @return SearchOption + */ + public function setName(string $name): SearchOption { + $this->name = $name; + + return $this; + } + + /** + * Get the name/key of the option. + * + * @since 15.0.0 + * + * @return string + */ + public function getName(): string { + return $this->name; + } + + + /** + * Set the title/display name of the option. + * + * @since 15.0.0 + * + * @param string $title + * + * @return SearchOption + */ + public function setTitle(string $title): SearchOption { + $this->title = $title; + + return $this; + } + + /** + * Get the title of the option. + * + * @since 15.0.0 + * + * @return string + */ + public function getTitle(): string { + return $this->title; + } + + + /** + * Set the type of the option. + * $type can be SearchOption::CHECKBOX or SearchOption::INPUT + * + * @since 15.0.0 + * + * @param string $type + * + * @return SearchOption + */ + public function setType(string $type): SearchOption { + $this->type = $type; + + return $this; + } + + /** + * Get the type of the option. + * + * @since 15.0.0 + * + * @return string + */ + public function getType(): string { + return $this->type; + } + + + /** + * In case of Type is INPUT, set the size of the input field. + * Value can be SearchOption::INPUT_SMALL or not defined. + * + * @since 15.0.0 + * + * @param string $size + * + * @return SearchOption + */ + public function setSize(string $size): SearchOption { + $this->size = $size; + + return $this; + } + + /** + * Get the size of the INPUT. + * + * @since 15.0.0 + * + * @return string + */ + public function getSize(): string { + return $this->size; + } + + + /** + * In case of Type is , set the placeholder to be displayed in the input + * field. + * + * @since 15.0.0 + * + * @param string $placeholder + * + * @return SearchOption + */ + public function setPlaceholder(string $placeholder): SearchOption { + $this->placeholder = $placeholder; + + return $this; + } + + /** + * Get the placeholder. + * + * @since 15.0.0 + * + * @return string + */ + public function getPlaceholder(): string { + return $this->placeholder; + } + + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize(): array { + return [ + 'name' => $this->getName(), + 'title' => $this->getTitle(), + 'type' => $this->getType(), + 'size' => $this->getSize(), + 'placeholder' => $this->getPlaceholder() + ]; + } +} diff --git a/lib/public/FullTextSearch/Model/SearchTemplate.php b/lib/public/FullTextSearch/Model/SearchTemplate.php new file mode 100644 index 00000000000..7d9159190ea --- /dev/null +++ b/lib/public/FullTextSearch/Model/SearchTemplate.php @@ -0,0 +1,258 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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 OCP\FullTextSearch\Model; + + +use JsonSerializable; +use OCP\FullTextSearch\IFullTextSearchProvider; + + +/** + * Class SearchTemplate + * + * This is a data transfer object that should be created by Content Provider + * when the getSearchTemplate() method is called. + * + * The object will contain templates to be displayed, and the list of the different + * options to be available to the user when he start a new search. + * + * The display of the Options is generated by the FullTextSearch app and Options + * can be displayed in 2 places: + * + * - the navigation page of the app that generate the indexed content. + * (files, bookmarks, deck, mails, ...) + * - the navigation page of the FullTextSearch app. + * + * Both pages will have different Options, and only the first one can integrate + * a specific template. + * + * @see IFullTextSearchProvider::getSearchTemplate + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +final class SearchTemplate implements JsonSerializable { + + + /** @var string */ + private $icon = ''; + + /** @var string */ + private $css = ''; + + /** @var string */ + private $template = ''; + + /** @var SearchOption[] */ + private $panelOptions = []; + + /** @var SearchOption[] */ + private $navigationOptions = []; + + + /** + * SearchTemplate constructor. + * + * the class of the icon and the css file to be loaded can be set during the + * creation of the object. + * + * @since 15.0.0 + * + * @param string $icon + * @param string $css + */ + public function __construct(string $icon = '', string $css = '') { + $this->icon = $icon; + $this->css = $css; + } + + + /** + * Set the class of the icon to be displayed in the left panel of the + * FullTextSearch navigation page, in front of the related Content Provider. + * + * @since 15.0.0 + * + * @param string $class + * + * @return SearchTemplate + */ + public function setIcon(string $class): SearchTemplate { + $this->icon = $class; + + return $this; + } + + /** + * Get the class of the icon. + * + * @since 15.0.0 + * + * @return string + */ + public function getIcon(): string { + return $this->icon; + } + + + /** + * Set the path of a CSS file that will be loaded when needed. + * + * @since 15.0.0 + * + * @param string $css + * + * @return SearchTemplate + */ + public function setCss(string $css): SearchTemplate { + $this->css = $css; + + return $this; + } + + /** + * Get the path of the CSS file. + * + * @since 15.0.0 + * + * @return string + */ + public function getCss(): string { + return $this->css; + } + + + /** + * Set the path of the file of a template that the HTML will be displayed + * below the Options. + * This should only be used if your Content Provider needs to set options in + * a way not generated by FullTextSearch + * + * @since 15.0.0 + * + * @param string $template + * + * @return SearchTemplate + */ + public function setTemplate(string $template): SearchTemplate { + $this->template = $template; + + return $this; + } + + /** + * Get the path of the template file. + * + * @since 15.0.0 + * + * @return string + */ + public function getTemplate(): string { + return $this->template; + } + + + /** + * Add an option in the Panel that is displayed when the user start a search + * within the app that generate the content. + * + * @see SearchOption + * + * @since 15.0.0 + * + * @param SearchOption $option + * + * @return SearchTemplate + */ + public function addPanelOption(SearchOption $option): SearchTemplate { + $this->panelOptions[] = $option; + + return $this; + } + + /** + * Get all options to be displayed in the Panel. + * + * @since 15.0.0 + * + * @return SearchOption[] + */ + public function getPanelOptions(): array { + return $this->panelOptions; + } + + + /** + * Add an option in the left panel of the FullTextSearch navigation page. + * + * @see SearchOption + * + * @since 15.0.0 + * + * @param SearchOption $option + * + * @return SearchTemplate + */ + public function addNavigationOption(SearchOption $option): SearchTemplate { + $this->navigationOptions[] = $option; + + return $this; + } + + /** + * Get all options to be displayed in the FullTextSearch navigation page. + * + * @since 15.0.0 + * + * @return array + */ + public function getNavigationOptions(): array { + return $this->navigationOptions; + } + + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize(): array { + return [ + 'icon' => $this->getIcon(), + 'css' => $this->getCss(), + 'template' => $this->getTemplate(), + 'panel' => $this->getPanelOptions(), + 'navigation' => $this->getNavigationOptions() + ]; + } +} + diff --git a/lib/public/FullTextSearch/Service/IIndexService.php b/lib/public/FullTextSearch/Service/IIndexService.php new file mode 100644 index 00000000000..c5d1b9b3bcf --- /dev/null +++ b/lib/public/FullTextSearch/Service/IIndexService.php @@ -0,0 +1,99 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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 OCP\FullTextSearch\Service; + + +use OCP\FullTextSearch\Model\IIndex; + + +/** + * Interface IIndexService + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Service + */ +interface IIndexService { + + + /** + * Retrieve an Index from the database, based on the Id of the Provider + * and the Id of the Document + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * + * @return IIndex + */ + public function getIndex(string $providerId, string $documentId): IIndex; + + + /** + * Update the status of an Index. status is a bit flag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * @param int $status + * @param bool $reset + */ + public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false); + + + /** + * Update the status of an array of Index. status is a bit flag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param array $documentIds + * @param int $status + * @param bool $reset + */ + public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false); + + + /** + * Update an array of Index. + * + * @since 15.0.0 + * + * @param array $indexes + */ + public function updateIndexes(array $indexes); + +} + diff --git a/lib/public/FullTextSearch/Service/IProviderService.php b/lib/public/FullTextSearch/Service/IProviderService.php new file mode 100644 index 00000000000..64153c13965 --- /dev/null +++ b/lib/public/FullTextSearch/Service/IProviderService.php @@ -0,0 +1,65 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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 OCP\FullTextSearch\Service; + + +/** + * Interface IProviderService + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Service + */ +interface IProviderService { + + + /** + * Check if the provider $providerId is already indexed. + * + * @since 15.0.0 + * + * @param string $providerId + * + * @return bool + */ + public function isProviderIndexed(string $providerId); + + + /** + * Add the Javascript API in the navigation page of an app. + * + * @since 15.0.0 + */ + public function addJavascriptAPI(); + + +} + diff --git a/lib/public/FullTextSearch/Service/ISearchService.php b/lib/public/FullTextSearch/Service/ISearchService.php new file mode 100644 index 00000000000..7da38e44f5c --- /dev/null +++ b/lib/public/FullTextSearch/Service/ISearchService.php @@ -0,0 +1,89 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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 OCP\FullTextSearch\Service; + + +use OCP\FullTextSearch\Model\ISearchRequest; +use OCP\FullTextSearch\Model\ISearchResult; + + +/** + * Interface ISearchService + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Service + */ +interface ISearchService { + + + /** + * generate a search request, based on an array: + * + * $request = + * [ + * 'providers' => (string/array) 'all' + * 'author' => (string) owner of the document. + * 'search' => (string) search string, + * 'size' => (int) number of items to be return + * 'page' => (int) page + * 'parts' => (array) parts of document to search within, + * 'options' = (array) search options, + * 'tags' => (array) tags, + * 'metatags' => (array) metatags, + * 'subtags' => (array) subtags + * ] + * + * 'providers' can be an array of providerIds + * + * @since 15.0.0 + * + * @param array $request + * + * @return ISearchRequest + */ + public function generateSearchRequest(array $request): ISearchRequest; + + + /** + * Search documents + * + * @since 15.0.0 + * + * @param string $userId + * @param ISearchRequest $searchRequest + * + * @return ISearchResult[] + */ + public function search(string $userId, ISearchRequest $searchRequest): array; + +} + diff --git a/lib/public/IAddressBook.php b/lib/public/IAddressBook.php index 67c34c9e8c9..4739e6f0c5b 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/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index 43543fdad47..dcd5fdecbea 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -418,4 +418,25 @@ interface IShare { * @since 11.0.0 */ public function getNodeCacheEntry(); + + /** + * Sets a shares hide download state + * This is mainly for public shares. It will signal that the share page should + * hide download buttons etc. + * + * @param bool $ro + * @return IShare + * @since 15.0.0 + */ + public function setHideDownload(bool $hide): IShare; + + /** + * Gets a shares hide download state + * This is mainly for public shares. It will signal that the share page should + * hide download buttons etc. + * + * @return bool + * @since 15.0.0 + */ + public function getHideDownload(): bool; } diff --git a/resources/app-info.xsd b/resources/app-info.xsd index fa06752c01d..287ed6b9913 100644 --- a/resources/app-info.xsd +++ b/resources/app-info.xsd @@ -63,6 +63,8 @@ maxOccurs="1" /> <xs:element name="trash" type="trash" minOccurs="0" maxOccurs="1" /> + <xs:element name="versions" type="versions" minOccurs="0" + maxOccurs="1" /> </xs:sequence> </xs:complexType> <xs:unique name="uniqueNameL10n"> @@ -670,6 +672,21 @@ </xs:simpleContent> </xs:complexType> + <xs:complexType name="versions"> + <xs:sequence> + <xs:element name="backend" type="versions-backend" minOccurs="1" + maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="versions-backend"> + <xs:simpleContent> + <xs:extension base="php-class"> + <xs:attribute name="for" type="php-class" use="required"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:simpleType name="php-class"> <xs:restriction base="xs:string"> <xs:pattern diff --git a/settings/BackgroundJobs/VerifyUserData.php b/settings/BackgroundJobs/VerifyUserData.php index b4a60ec8405..56ebadff9c3 100644 --- a/settings/BackgroundJobs/VerifyUserData.php +++ b/settings/BackgroundJobs/VerifyUserData.php @@ -63,6 +63,9 @@ class VerifyUserData extends Job { /** @var string */ private $lookupServerUrl; + /** @var IConfig */ + private $config; + /** * VerifyUserData constructor. * @@ -85,6 +88,7 @@ class VerifyUserData extends Job { $lookupServerUrl = $config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com'); $this->lookupServerUrl = rtrim($lookupServerUrl, '/'); + $this->config = $config; } /** diff --git a/settings/js/admin.js b/settings/js/admin.js index 35f3d949ab6..56bbaead520 100644 --- a/settings/js/admin.js +++ b/settings/js/admin.js @@ -66,11 +66,8 @@ $(document).ready(function(){ }); }); - $('#shareapiExpireAfterNDays').change(function() { - var value = $(this).val(); - if (value <= 0) { - $(this).val("1"); - } + $('#shareapiExpireAfterNDays').on('input', function() { + this.value = this.value.replace(/\D/g, ''); }); $('#shareAPI input:not(.noJSAutoUpdate)').change(function() { diff --git a/tests/Core/Controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php index f2e8d112b64..efe85d81e1c 100644 --- a/tests/Core/Controller/LoginControllerTest.php +++ b/tests/Core/Controller/LoginControllerTest.php @@ -199,6 +199,7 @@ class LoginControllerTest extends TestCase { 'alt_login' => [], 'resetPasswordLink' => null, 'throttle_delay' => 1000, + 'login_form_autocomplete' => 'off', ], 'guest' ); @@ -223,6 +224,7 @@ class LoginControllerTest extends TestCase { 'alt_login' => [], 'resetPasswordLink' => null, 'throttle_delay' => 1000, + 'login_form_autocomplete' => 'off', ], 'guest' ); @@ -255,10 +257,12 @@ class LoginControllerTest extends TestCase { ->method('isLoggedIn') ->willReturn(false); $this->config - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('getSystemValue') - ->with('lost_password_link') - ->willReturn(false); + ->will($this->returnValueMap([ + ['login_form_autocomplete', true, true], + ['lost_password_link', '', false], + ])); $user = $this->createMock(IUser::class); $user ->expects($this->once()) @@ -281,6 +285,7 @@ class LoginControllerTest extends TestCase { 'alt_login' => [], 'resetPasswordLink' => false, 'throttle_delay' => 1000, + 'login_form_autocomplete' => 'on', ], 'guest' ); @@ -338,10 +343,12 @@ class LoginControllerTest extends TestCase { ->method('isLoggedIn') ->willReturn(false); $this->config - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('getSystemValue') - ->with('lost_password_link') - ->willReturn(false); + ->will($this->returnValueMap([ + ['login_form_autocomplete', true, true], + ['lost_password_link', '', false], + ])); $user = $this->createMock(IUser::class); $user->expects($this->once()) ->method('canChangePassword') @@ -363,6 +370,7 @@ class LoginControllerTest extends TestCase { 'alt_login' => [], 'resetPasswordLink' => false, 'throttle_delay' => 1000, + 'login_form_autocomplete' => 'on', ], 'guest' ); diff --git a/tests/acceptance/features/app-files.feature b/tests/acceptance/features/app-files.feature index 74490180ad3..70e085ca665 100644 --- a/tests/acceptance/features/app-files.feature +++ b/tests/acceptance/features/app-files.feature @@ -121,6 +121,32 @@ Feature: app-files And I open the Share menu Then I see that the Share menu is shown + Scenario: hide download in a public shared link + Given I act as John + And I am logged in + And I share the link for "welcome.txt" + And I set the download of the shared link as hidden + And I write down the shared link + When I act as Jane + And I visit the shared link I wrote down + And I see that the current page is the shared link I wrote down + Then I see that the download button is not shown + And I see that the Share menu button is not shown + + Scenario: show download again in a public shared link + Given I act as John + And I am logged in + And I share the link for "welcome.txt" + And I set the download of the shared link as hidden + And I set the download of the shared link as shown + And I write down the shared link + When I act as Jane + And I visit the shared link I wrote down + And I see that the current page is the shared link I wrote down + Then I see that the download button is shown + And I open the Share menu + And I see that the Share menu is shown + Scenario: creation is not possible by default in a public shared folder Given I act as John And I am logged in diff --git a/tests/acceptance/features/bootstrap/FilesAppContext.php b/tests/acceptance/features/bootstrap/FilesAppContext.php index 408995b9a83..4b648bfc544 100644 --- a/tests/acceptance/features/bootstrap/FilesAppContext.php +++ b/tests/acceptance/features/bootstrap/FilesAppContext.php @@ -235,6 +235,27 @@ class FilesAppContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function hideDownloadCheckbox() { + // forThe()->checkbox("Hide download") can not be used here; that would + // return the checkbox itself, but the element that the user interacts + // with is the label. + return Locator::forThe()->xpath("//label[normalize-space() = 'Hide download']")-> + descendantOf(self::shareLinkMenu())-> + describedAs("Hide download checkbox in the details view in Files app"); + } + + /** + * @return Locator + */ + public static function hideDownloadCheckboxInput() { + return Locator::forThe()->checkbox("Hide download")-> + descendantOf(self::shareLinkMenu())-> + describedAs("Hide download checkbox input in the details view in Files app"); + } + + /** + * @return Locator + */ public static function allowUploadAndEditingRadioButton() { // forThe()->radio("Allow upload and editing") can not be used here; // that would return the radio button itself, but the element that the @@ -335,6 +356,28 @@ class FilesAppContext implements Context, ActorAwareInterface { } /** + * @When I set the download of the shared link as hidden + */ + public function iSetTheDownloadOfTheSharedLinkAsHidden() { + $this->showShareLinkMenuIfNeeded(); + + $this->iSeeThatTheDownloadOfTheLinkShareIsShown(); + + $this->actor->find(self::hideDownloadCheckbox(), 2)->click(); + } + + /** + * @When I set the download of the shared link as shown + */ + public function iSetTheDownloadOfTheSharedLinkAsShown() { + $this->showShareLinkMenuIfNeeded(); + + $this->iSeeThatTheDownloadOfTheLinkShareIsHidden(); + + $this->actor->find(self::hideDownloadCheckbox(), 2)->click(); + } + + /** * @When I set the shared link as editable */ public function iSetTheSharedLinkAsEditable() { @@ -461,6 +504,24 @@ class FilesAppContext implements Context, ActorAwareInterface { } /** + * @Then I see that the download of the link share is hidden + */ + public function iSeeThatTheDownloadOfTheLinkShareIsHidden() { + $this->showShareLinkMenuIfNeeded(); + + PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::hideDownloadCheckboxInput(), 10)->isChecked()); + } + + /** + * @Then I see that the download of the link share is shown + */ + public function iSeeThatTheDownloadOfTheLinkShareIsShown() { + $this->showShareLinkMenuIfNeeded(); + + PHPUnit_Framework_Assert::assertFalse($this->actor->find(self::hideDownloadCheckboxInput(), 10)->isChecked()); + } + + /** * @Then I see that the working icon for password protect is shown */ public function iSeeThatTheWorkingIconForPasswordProtectIsShown() { diff --git a/tests/acceptance/features/bootstrap/FilesSharingAppContext.php b/tests/acceptance/features/bootstrap/FilesSharingAppContext.php index 1fe12d5f42d..531184442dd 100644 --- a/tests/acceptance/features/bootstrap/FilesSharingAppContext.php +++ b/tests/acceptance/features/bootstrap/FilesSharingAppContext.php @@ -104,6 +104,14 @@ class FilesSharingAppContext implements Context, ActorAwareInterface { } /** + * @return Locator + */ + public static function downloadButton() { + return Locator::forThe()->id("downloadFile")-> + describedAs("Download button in Shared file page"); + } + + /** * @When I visit the shared link I wrote down */ public function iVisitTheSharedLinkIWroteDown() { @@ -199,10 +207,42 @@ class FilesSharingAppContext implements Context, ActorAwareInterface { } /** + * @Then I see that the Share menu button is not shown + */ + public function iSeeThatTheShareMenuButtonIsNotShown() { + try { + PHPUnit_Framework_Assert::assertFalse( + $this->actor->find(self::shareMenuButton())->isVisible()); + } catch (NoSuchElementException $exception) { + } + } + + /** * @Then I see that the shared file preview shows the text :text */ public function iSeeThatTheSharedFilePreviewShowsTheText($text) { PHPUnit_Framework_Assert::assertContains($text, $this->actor->find(self::textPreview(), 10)->getText()); } + /** + * @Then I see that the download button is shown + */ + public function iSeeThatTheDownloadButtonIsShown() { + if (!WaitFor::elementToBeEventuallyShown( + $this->actor, self::downloadButton(), $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) { + PHPUnit_Framework_Assert::fail("The download button is not visible yet after $timeout seconds"); + } + } + + /** + * @Then I see that the download button is not shown + */ + public function iSeeThatTheDownloadButtonIsNotShown() { + try { + PHPUnit_Framework_Assert::assertFalse( + $this->actor->find(self::downloadButton())->isVisible()); + } catch (NoSuchElementException $exception) { + } + } + } diff --git a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php index 8b005bd8bdb..57144d0f00d 100644 --- a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php +++ b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php @@ -22,18 +22,17 @@ namespace Test\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Token\DefaultToken; use OC\Authentication\Token\DefaultTokenMapper; use OC\Authentication\Token\DefaultTokenProvider; -use OC\Authentication\Token\ExpiredTokenException; use OC\Authentication\Token\IToken; use OC\Authentication\Token\PublicKeyToken; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\ILogger; -use OCP\IUser; use OCP\Security\ICrypto; use Test\TestCase; diff --git a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php index 02ec62d3d77..ce64878bf5e 100644 --- a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php +++ b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php @@ -23,19 +23,17 @@ namespace Test\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; -use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Token\DefaultToken; use OC\Authentication\Token\PublicKeyToken; use OC\Authentication\Token\PublicKeyTokenMapper; use OC\Authentication\Token\PublicKeyTokenProvider; -use OC\Authentication\Token\ExpiredTokenException; use OC\Authentication\Token\IToken; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\ILogger; -use OCP\IUser; use OCP\Security\ICrypto; use Test\TestCase; diff --git a/tests/lib/Collaboration/Collaborators/MailPluginTest.php b/tests/lib/Collaboration/Collaborators/MailPluginTest.php index 775941bd440..a9d0244d38c 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 aa009a7134b..aff68185767 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', diff --git a/tests/lib/Files/Storage/Storage.php b/tests/lib/Files/Storage/Storage.php index 04aafece2e3..a25a3f74f9e 100644 --- a/tests/lib/Files/Storage/Storage.php +++ b/tests/lib/Files/Storage/Storage.php @@ -23,6 +23,7 @@ namespace Test\Files\Storage; use OC\Files\Cache\Watcher; +use OCP\Files\Storage\IWriteStreamStorage; abstract class Storage extends \Test\TestCase { /** @@ -628,4 +629,20 @@ abstract class Storage extends \Test\TestCase { $this->instance->rename('bar.txt.part', 'bar.txt'); $this->assertEquals('bar', $this->instance->file_get_contents('bar.txt')); } + + public function testWriteStream() { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + + if (!$this->instance->instanceOfStorage(IWriteStreamStorage::class)) { + $this->markTestSkipped('Not a WriteSteamStorage'); + } + /** @var IWriteStreamStorage $storage */ + $storage = $this->instance; + + $source = fopen($textFile, 'r'); + + $storage->writeStream('test.txt', $source); + $this->assertTrue($storage->file_exists('test.txt')); + $this->assertEquals(file_get_contents($textFile), $storage->file_get_contents('test.txt')); + } } diff --git a/tests/lib/Files/Stream/CountReadStreamTest.php b/tests/lib/Files/Stream/CountReadStreamTest.php new file mode 100644 index 00000000000..99291d1644f --- /dev/null +++ b/tests/lib/Files/Stream/CountReadStreamTest.php @@ -0,0 +1,49 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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 Test\Files\Stream; + +use OC\Files\Stream\CountReadStream; +use Test\TestCase; + +class CountReadStreamTest extends TestCase { + private function getStream($data) { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, $data); + rewind($handle); + return $handle; + } + + public function testBasicCount() { + $source = $this->getStream('foo'); + $stream = CountReadStream::wrap($source, function ($size) { + $this->assertEquals(3, $size); + }); + stream_get_contents($stream); + } + + public function testLarger() { + $stream = CountReadStream::wrap(fopen(__DIR__ . '/../../../data/testimage.mp4', 'r'), function ($size) { + $this->assertEquals(383631, $size); + }); + stream_get_contents($stream); + } +} diff --git a/tests/lib/Preview/GeneratorTest.php b/tests/lib/Preview/GeneratorTest.php index 64786fa9fe8..565b526b659 100644 --- a/tests/lib/Preview/GeneratorTest.php +++ b/tests/lib/Preview/GeneratorTest.php @@ -104,7 +104,7 @@ class GeneratorTest extends \Test\TestCase { $previewFile = $this->createMock(ISimpleFile::class); $previewFolder->method('getFile') - ->with($this->equalTo('128-128.png')) + ->with($this->equalTo('256-256.png')) ->willReturn($previewFile); $this->eventDispatcher->expects($this->once()) @@ -212,7 +212,7 @@ class GeneratorTest extends \Test\TestCase { ->will($this->returnCallback(function($filename) use ($maxPreview, $previewFile) { if ($filename === '2048-2048-max.png') { return $maxPreview; - } else if ($filename === '128-128.png') { + } else if ($filename === '256-256.png') { return $previewFile; } $this->fail('Unexpected file'); @@ -223,7 +223,7 @@ class GeneratorTest extends \Test\TestCase { ->with($this->equalTo('my data')); $previewFolder->method('getFile') - ->with($this->equalTo('128-128.png')) + ->with($this->equalTo('256-256.png')) ->willThrowException(new NotFoundException()); $image = $this->createMock(IImage::class); @@ -233,7 +233,7 @@ class GeneratorTest extends \Test\TestCase { $image->expects($this->once()) ->method('resize') - ->with(128); + ->with(256); $image->method('data') ->willReturn('my resized data'); $image->method('valid')->willReturn(true); @@ -328,8 +328,8 @@ class GeneratorTest extends \Test\TestCase { return [ [1024, 2048, 512, 512, false, IPreview::MODE_FILL, 256, 512], [1024, 2048, 512, 512, false, IPreview::MODE_COVER, 512, 1024], - [1024, 2048, 512, 512, true, IPreview::MODE_FILL, 512, 512], - [1024, 2048, 512, 512, true, IPreview::MODE_COVER, 512, 512], + [1024, 2048, 512, 512, true, IPreview::MODE_FILL, 1024, 1024], + [1024, 2048, 512, 512, true, IPreview::MODE_COVER, 1024, 1024], [1024, 2048, -1, 512, false, IPreview::MODE_COVER, 256, 512], [1024, 2048, 512, -1, false, IPreview::MODE_FILL, 512, 1024], @@ -343,14 +343,20 @@ class GeneratorTest extends \Test\TestCase { [2048, 1024, 512, 512, false, IPreview::MODE_FILL, 512, 256], [2048, 1024, 512, 512, false, IPreview::MODE_COVER, 1024, 512], - [2048, 1024, 512, 512, true, IPreview::MODE_FILL, 512, 512], - [2048, 1024, 512, 512, true, IPreview::MODE_COVER, 512, 512], + [2048, 1024, 512, 512, true, IPreview::MODE_FILL, 1024, 1024], + [2048, 1024, 512, 512, true, IPreview::MODE_COVER, 1024, 1024], [2048, 1024, -1, 512, false, IPreview::MODE_FILL, 1024, 512], [2048, 1024, 512, -1, false, IPreview::MODE_COVER, 512, 256], [2048, 1024, 4096, 1024, true, IPreview::MODE_FILL, 2048, 512], [2048, 1024, 4096, 1024, true, IPreview::MODE_COVER, 2048, 512], + + //Test minimum size + [2048, 1024, 32, 32, false, IPreview::MODE_FILL, 64, 32], + [2048, 1024, 32, 32, false, IPreview::MODE_COVER, 64, 32], + [2048, 1024, 32, 32, true, IPreview::MODE_FILL, 64, 64], + [2048, 1024, 32, 32, true, IPreview::MODE_COVER, 64, 64], ]; } diff --git a/tests/lib/Repair/SetVcardDatabaseUIDTest.php b/tests/lib/Repair/SetVcardDatabaseUIDTest.php index fe1a7481d7b..97da3c6a901 100644 --- a/tests/lib/Repair/SetVcardDatabaseUIDTest.php +++ b/tests/lib/Repair/SetVcardDatabaseUIDTest.php @@ -118,4 +118,4 @@ class SetVcardDatabaseUIDTest extends TestCase { $this->assertEquals($expected, $this->invokePrivate($this->repair, 'shouldRun')); } -}
\ No newline at end of file +} |