diff options
46 files changed, 513 insertions, 152 deletions
diff --git a/3rdparty b/3rdparty -Subproject 5ce8de19b67296cc03957d4483ae8ddacc1d4f8 +Subproject e2a142cf866b30318c0bd71a78e9aa659deccad diff --git a/apps/files/js/detailsview.js b/apps/files/js/detailsview.js index bad4be4ceef..f04adcf1292 100644 --- a/apps/files/js/detailsview.js +++ b/apps/files/js/detailsview.js @@ -140,16 +140,14 @@ } return orderA - orderB; }); - if (this._tabViews.length > 1) { - // only render headers if there is more than one available - templateVars.tabHeaders = _.map(this._tabViews, function(tabView, i) { - return { - tabId: tabView.id, - tabIndex: i, - label: tabView.getLabel() - }; - }); - } + + templateVars.tabHeaders = _.map(this._tabViews, function(tabView, i) { + return { + tabId: tabView.id, + tabIndex: i, + label: tabView.getLabel() + }; + }); this.$el.html(this.template(templateVars)); @@ -166,6 +164,8 @@ this.selectTab(this._currentTabId); + this._updateTabVisibilities(); + this._dirty = false; }, @@ -224,6 +224,8 @@ if (this._dirty) { this.render(); + } else { + this._updateTabVisibilities(); } if (this._currentTabId) { @@ -241,6 +243,37 @@ }, /** + * Update tab headers based on the current model + */ + _updateTabVisibilities: function() { + // update tab header visibilities + var self = this; + var deselect = false; + var countVisible = 0; + var $tabHeaders = this.$el.find('.tabHeaders li'); + _.each(this._tabViews, function(tabView) { + var isVisible = tabView.canDisplay(self.model); + if (isVisible) { + countVisible += 1; + } + if (!isVisible && self._currentTabId === tabView.id) { + deselect = true; + } + $tabHeaders.filterAttr('data-tabid', tabView.id).toggleClass('hidden', !isVisible); + }); + + // hide the whole container if there is only one tab + this.$el.find('.tabHeaders').toggleClass('hidden', countVisible <= 1); + + if (deselect) { + // select the first visible tab instead + var visibleTabId = this.$el.find('.tabHeader:not(.hidden):first').attr('data-tabid'); + this.selectTab(visibleTabId); + } + + }, + + /** * Returns the file info. * * @return {OCA.Files.FileInfoModel} file info diff --git a/apps/files/js/detailtabview.js b/apps/files/js/detailtabview.js index d885e47b15e..0bd34a88188 100644 --- a/apps/files/js/detailtabview.js +++ b/apps/files/js/detailtabview.js @@ -95,6 +95,17 @@ */ nextPage: function() { // load the next page, if applicable + }, + + /** + * Returns whether the current tab is able to display + * the given file info, for example based on mime type. + * + * @param {OCA.Files.FileInfoModel} fileInfo file info model + * @return {bool} whether to display this tab + */ + canDisplay: function(fileInfo) { + return true; } }); DetailTabView._TAB_COUNT = 0; diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 17f0f777169..03330ad7c5d 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -18,7 +18,7 @@ * - TODO music upload button */ -/* global Files, FileList, jQuery, oc_requesttoken, humanFileSize, getUniqueName */ +/* global jQuery, oc_requesttoken, humanFileSize */ /** * Function that will allow us to know if Ajax uploads are supported @@ -139,6 +139,9 @@ OC.Upload = { if (data.data) { data.data.append('resolution', 'replace'); } else { + if (!data.formData) { + data.formData = []; + } data.formData.push({name:'resolution', value:'replace'}); //hack for ie8 } data.submit(); @@ -152,6 +155,9 @@ OC.Upload = { if (data.data) { data.data.append('resolution', 'autorename'); } else { + if (!data.formData) { + data.formData = []; + } data.formData.push({name:'resolution', value:'autorename'}); //hack for ie8 } data.submit(); @@ -164,8 +170,9 @@ OC.Upload = { } }, /** - * TODO checks the list of existing files prior to uploading and shows a simple dialog to choose + * checks the list of existing files prior to uploading and shows a simple dialog to choose * skip all, replace all or choose which files to keep + * * @param {array} selection of files to upload * @param {object} callbacks - object with several callback methods * @param {function} callbacks.onNoConflicts @@ -175,14 +182,34 @@ OC.Upload = { * @param {function} callbacks.onCancel */ checkExistingFiles: function (selection, callbacks) { - /* - $.each(selection.uploads, function(i, upload) { - var $row = OCA.Files.App.fileList.findFileEl(upload.files[0].name); - if ($row) { - // TODO check filelist before uploading and show dialog on conflicts, use callbacks + var fileList = OCA.Files.App.fileList; + var conflicts = []; + // only keep non-conflicting uploads + selection.uploads = _.filter(selection.uploads, function(upload) { + var fileInfo = fileList.findFile(upload.files[0].name); + if (fileInfo) { + conflicts.push([ + // original + _.extend(fileInfo, { + directory: fileInfo.directory || fileInfo.path || fileList.getCurrentDirectory() + }), + // replacement (File object) + upload + ]); + return false; } + return true; }); - */ + if (conflicts.length) { + _.each(conflicts, function(conflictData) { + OC.dialogs.fileexists(conflictData[1], conflictData[0], conflictData[1].files[0], OC.Upload); + }); + } + + // upload non-conflicting files + // note: when reaching the server they might still meet conflicts + // if the folder was concurrently modified, these will get added + // to the already visible dialog, if applicable callbacks.onNoConflicts(selection); }, @@ -368,18 +395,18 @@ OC.Upload = { }, submit: function(e, data) { OC.Upload.rememberUpload(data); - if ( ! data.formData ) { - var fileDirectory = ''; - if(typeof data.files[0].relativePath !== 'undefined') { - fileDirectory = data.files[0].relativePath; - } - // noone set update parameters, we set the minimum - data.formData = { - requesttoken: oc_requesttoken, - dir: data.targetDir || FileList.getCurrentDirectory(), - file_directory: fileDirectory - }; + if (!data.formData) { + data.formData = []; + } + + var fileDirectory = ''; + if(typeof data.files[0].relativePath !== 'undefined') { + fileDirectory = data.files[0].relativePath; } + // FIXME: prevent re-adding the same + data.formData.push({name: 'requesttoken', value: oc_requesttoken}); + data.formData.push({name: 'dir', value: data.targetDir || FileList.getCurrentDirectory()}); + data.formData.push({name: 'file_directory', value: fileDirectory}); }, fail: function(e, data) { OC.Upload.log('fail', e, data); diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 82d510f900d..b4cc71e2d3b 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -723,8 +723,23 @@ return true; }, /** - * Returns the tr element for a given file name - * @param fileName file name + * Returns the file info for the given file name from the internal collection. + * + * @param {string} fileName file name + * @return {OCA.Files.FileInfo} file info or null if it was not found + * + * @since 8.2 + */ + findFile: function(fileName) { + return _.find(this.files, function(aFile) { + return (aFile.name === fileName); + }) || null; + }, + /** + * Returns the tr element for a given file name, but only if it was already rendered. + * + * @param {string} fileName file name + * @return {Object} jQuery object of the matching row */ findFileEl: function(fileName){ // use filterAttr to avoid escaping issues @@ -1892,7 +1907,7 @@ * @return {bool} true if the file exists in the list, false otherwise */ inList:function(file) { - return this.findFileEl(file).length; + return this.findFile(file); }, /** diff --git a/apps/files/l10n/oc.js b/apps/files/l10n/oc.js index 30b51c8f5f8..bd44479b285 100644 --- a/apps/files/l10n/oc.js +++ b/apps/files/l10n/oc.js @@ -40,6 +40,7 @@ OC.L10N.register( "Download" : "Telecargar", "Rename" : "Renomenar", "Delete" : "Suprimir", + "Details" : "Detalhs", "Select" : "Seleccionar", "Pending" : "En espèra", "Unable to determine date" : "Impossible de determinar la data", diff --git a/apps/files/l10n/oc.json b/apps/files/l10n/oc.json index 895400b3ae2..89843ea85c2 100644 --- a/apps/files/l10n/oc.json +++ b/apps/files/l10n/oc.json @@ -38,6 +38,7 @@ "Download" : "Telecargar", "Rename" : "Renomenar", "Delete" : "Suprimir", + "Details" : "Detalhs", "Select" : "Seleccionar", "Pending" : "En espèra", "Unable to determine date" : "Impossible de determinar la data", diff --git a/apps/files/tests/js/detailsviewSpec.js b/apps/files/tests/js/detailsviewSpec.js index f02e419434f..26a16b31530 100644 --- a/apps/files/tests/js/detailsviewSpec.js +++ b/apps/files/tests/js/detailsviewSpec.js @@ -144,14 +144,76 @@ describe('OCA.Files.DetailsView tests', function() { expect(detailsView.$el.find('.tab').eq(0).hasClass('hidden')).toEqual(true); expect(detailsView.$el.find('.tab').eq(1).hasClass('hidden')).toEqual(false); }); - it('does not render tab headers when only one tab exists', function() { - detailsView.remove(); - detailsView = new OCA.Files.DetailsView(); - testView = new OCA.Files.DetailTabView({id: 'test1'}); - detailsView.addTabView(testView); - detailsView.render(); - - expect(detailsView.$el.find('.tabHeader').length).toEqual(0); + describe('tab visibility', function() { + beforeEach(function() { + detailsView.remove(); + detailsView = new OCA.Files.DetailsView(); + }); + it('does not display tab headers when only one tab exists', function() { + testView = new OCA.Files.DetailTabView({id: 'test1'}); + detailsView.addTabView(testView); + detailsView.render(); + + expect(detailsView.$el.find('.tabHeaders').hasClass('hidden')).toEqual(true); + expect(detailsView.$el.find('.tabHeader').length).toEqual(1); + }); + it('does not display tab that do not pass visibility check', function() { + testView = new OCA.Files.DetailTabView({id: 'test1'}); + testView.canDisplay = sinon.stub().returns(false); + testView2 = new OCA.Files.DetailTabView({id: 'test2'}); + var testView3 = new OCA.Files.DetailTabView({id: 'test3'}); + detailsView.addTabView(testView); + detailsView.addTabView(testView2); + detailsView.addTabView(testView3); + + var fileInfo = {id: 5, name: 'test.txt'}; + detailsView.setFileInfo(fileInfo); + + expect(testView.canDisplay.calledOnce).toEqual(true); + expect(testView.canDisplay.calledWith(fileInfo)).toEqual(true); + + expect(detailsView.$el.find('.tabHeaders').hasClass('hidden')).toEqual(false); + expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('hidden')).toEqual(true); + expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('hidden')).toEqual(false); + expect(detailsView.$el.find('.tabHeader[data-tabid=test3]').hasClass('hidden')).toEqual(false); + }); + it('does not show tab headers if only one header is visible due to visibility check', function() { + testView = new OCA.Files.DetailTabView({id: 'test1'}); + testView.canDisplay = sinon.stub().returns(false); + testView2 = new OCA.Files.DetailTabView({id: 'test2'}); + detailsView.addTabView(testView); + detailsView.addTabView(testView2); + + var fileInfo = {id: 5, name: 'test.txt'}; + detailsView.setFileInfo(fileInfo); + + expect(testView.canDisplay.calledOnce).toEqual(true); + expect(testView.canDisplay.calledWith(fileInfo)).toEqual(true); + + expect(detailsView.$el.find('.tabHeaders').hasClass('hidden')).toEqual(true); + expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('hidden')).toEqual(true); + expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('hidden')).toEqual(false); + }); + it('deselects the current tab if a model update does not pass the visibility check', function() { + testView = new OCA.Files.DetailTabView({id: 'test1'}); + testView.canDisplay = function(fileInfo) { + return fileInfo.mimetype !== 'httpd/unix-directory'; + }; + testView2 = new OCA.Files.DetailTabView({id: 'test2'}); + detailsView.addTabView(testView); + detailsView.addTabView(testView2); + + var fileInfo = {id: 5, name: 'test.txt', mimetype: 'text/plain'}; + detailsView.setFileInfo(fileInfo); + + expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('selected')).toEqual(true); + expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('selected')).toEqual(false); + + detailsView.setFileInfo({id: 10, name: 'folder', mimetype: 'httpd/unix-directory'}); + + expect(detailsView.$el.find('.tabHeader[data-tabid=test1]').hasClass('selected')).toEqual(false); + expect(detailsView.$el.find('.tabHeader[data-tabid=test2]').hasClass('selected')).toEqual(true); + }); }); it('sorts by order and then label', function() { detailsView.remove(); diff --git a/apps/files_external/l10n/cs_CZ.js b/apps/files_external/l10n/cs_CZ.js index f48cf407681..59b3f9b148c 100644 --- a/apps/files_external/l10n/cs_CZ.js +++ b/apps/files_external/l10n/cs_CZ.js @@ -30,6 +30,7 @@ OC.L10N.register( "Saved" : "Uloženo", "Access key" : "Přístupový klíč", "Secret key" : "Tajný klíč", + "Builtin" : "Zabudované", "None" : "Žádné", "OAuth1" : "OAuth1", "App key" : "Klíč aplikace", @@ -69,9 +70,11 @@ OC.L10N.register( "SFTP with secret key login" : "SFTP login s tajným klíčem", "SMB / CIFS" : "SMB / CIFS", "Share" : "Sdílet", + "Domain" : "Doména", "SMB / CIFS using OC login" : "SMB / CIFS za použití přihlašovacího jména OC", "Username as share" : "Uživatelské jméno jako sdílený adresář", "OpenStack Object Storage" : "OpenStack Object Storage", + "Request timeout (seconds)" : "Čas vypršení požadavku (sekundy)", "<b>Note:</b> " : "<b>Poznámka:</b>", "<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Poznámka:</b> cURL podpora v PHP není povolena nebo nainstalována. Není možné připojení %s. Prosím požádejte svého správce systému ať ji nainstaluje.", "<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Poznámka:</b> FTP podpora v PHP není povolena nebo nainstalována. Není možné připojení %s. Prosím požádejte svého správce systému ať ji nainstaluje.", diff --git a/apps/files_external/l10n/cs_CZ.json b/apps/files_external/l10n/cs_CZ.json index d1f05174f47..08837e76a83 100644 --- a/apps/files_external/l10n/cs_CZ.json +++ b/apps/files_external/l10n/cs_CZ.json @@ -28,6 +28,7 @@ "Saved" : "Uloženo", "Access key" : "Přístupový klíč", "Secret key" : "Tajný klíč", + "Builtin" : "Zabudované", "None" : "Žádné", "OAuth1" : "OAuth1", "App key" : "Klíč aplikace", @@ -67,9 +68,11 @@ "SFTP with secret key login" : "SFTP login s tajným klíčem", "SMB / CIFS" : "SMB / CIFS", "Share" : "Sdílet", + "Domain" : "Doména", "SMB / CIFS using OC login" : "SMB / CIFS za použití přihlašovacího jména OC", "Username as share" : "Uživatelské jméno jako sdílený adresář", "OpenStack Object Storage" : "OpenStack Object Storage", + "Request timeout (seconds)" : "Čas vypršení požadavku (sekundy)", "<b>Note:</b> " : "<b>Poznámka:</b>", "<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Poznámka:</b> cURL podpora v PHP není povolena nebo nainstalována. Není možné připojení %s. Prosím požádejte svého správce systému ať ji nainstaluje.", "<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." : "<b>Poznámka:</b> FTP podpora v PHP není povolena nebo nainstalována. Není možné připojení %s. Prosím požádejte svého správce systému ať ji nainstaluje.", diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 66e4f9dc273..30a803f3207 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -103,11 +103,20 @@ name: 'Share', displayName: '', mime: 'all', - permissions: OC.PERMISSION_SHARE, + permissions: OC.PERMISSION_ALL, icon: OC.imagePath('core', 'actions/share'), type: OCA.Files.FileActions.TYPE_INLINE, actionHandler: function(fileName) { fileList.showDetailsView(fileName, 'shareTabView'); + }, + render: function(actionSpec, isDefault, context) { + var permissions = parseInt(context.$file.attr('data-permissions'), 10); + // if no share permissions but share owner exists, still show the link + if ((permissions & OC.PERMISSION_SHARE) !== 0 || context.$file.attr('data-share-owner')) { + return fileActions._defaultRenderAction.call(fileActions, actionSpec, isDefault, context); + } + // don't render anything + return null; } }); @@ -157,26 +166,7 @@ // if the statuses are loaded already, use them for the icon // (needed when scrolling to the next page) if (hasUserShares || hasLinkShare || $tr.attr('data-share-recipients') || $tr.attr('data-share-owner')) { - var permissions = $tr.data('permissions'); OC.Share.markFileAsShared($tr, true, hasLinkShare); - if ((permissions & OC.PERMISSION_SHARE) === 0 && $tr.attr('data-share-owner')) { - // if no share action exists because the admin disabled sharing for this user - // we create a share notification action to inform the user about files - // shared with him otherwise we just update the existing share action. - // TODO: make this work like/with OC.Share.markFileAsShared() - $tr.find('.fileactions .action-share-notification').remove(); - var shareNotification = '<a class="action action-share-notification permanent"' + - ' data-action="Share-Notification" href="#" original-title="">' + - ' <img class="svg" src="' + OC.imagePath('core', 'actions/share') + '"></img>'; - $tr.find('.fileactions').append(function() { - var shareBy = escapeHTML($tr.attr('data-share-owner')); - var $result = $(shareNotification + '<span> ' + shareBy + '</span></span>'); - $result.on('click', function() { - return false; - }); - return $result; - }); - } return true; } return false; diff --git a/apps/files_sharing/l10n/cs_CZ.js b/apps/files_sharing/l10n/cs_CZ.js index f6b43cf4fa3..be924134ae2 100644 --- a/apps/files_sharing/l10n/cs_CZ.js +++ b/apps/files_sharing/l10n/cs_CZ.js @@ -38,6 +38,9 @@ OC.L10N.register( "Public shared file %1$s was downloaded" : "Byl stažen veřejně sdílený soubor %1$s ", "You shared %1$s with %2$s" : "Sdílíte %1$s s %2$s", "You shared %1$s with group %2$s" : "Sdílíte %1$s se skupinou %2$s", + "%2$s shared %1$s with %3$s" : "%2$s nasdílel(a) %1$s s %3$s", + "%2$s shared %1$s with group %3$s" : "%2$s nasdílel(a) %1$s se skupinou %3$s", + "%2$s shared %1$s via link" : "%2$s nasdílel(a) %1$s jako odkaz", "%2$s shared %1$s with you" : "%2$s s vámi sdílí %1$s", "You shared %1$s via link" : "Sdílíte %1$s přes odkaz", "Shares" : "Sdílení", diff --git a/apps/files_sharing/l10n/cs_CZ.json b/apps/files_sharing/l10n/cs_CZ.json index f5822c627ae..a889bbc1235 100644 --- a/apps/files_sharing/l10n/cs_CZ.json +++ b/apps/files_sharing/l10n/cs_CZ.json @@ -36,6 +36,9 @@ "Public shared file %1$s was downloaded" : "Byl stažen veřejně sdílený soubor %1$s ", "You shared %1$s with %2$s" : "Sdílíte %1$s s %2$s", "You shared %1$s with group %2$s" : "Sdílíte %1$s se skupinou %2$s", + "%2$s shared %1$s with %3$s" : "%2$s nasdílel(a) %1$s s %3$s", + "%2$s shared %1$s with group %3$s" : "%2$s nasdílel(a) %1$s se skupinou %3$s", + "%2$s shared %1$s via link" : "%2$s nasdílel(a) %1$s jako odkaz", "%2$s shared %1$s with you" : "%2$s s vámi sdílí %1$s", "You shared %1$s via link" : "Sdílíte %1$s přes odkaz", "Shares" : "Sdílení", diff --git a/apps/files_sharing/publicwebdav.php b/apps/files_sharing/publicwebdav.php index 773a15c888e..fbf9d22cf76 100644 --- a/apps/files_sharing/publicwebdav.php +++ b/apps/files_sharing/publicwebdav.php @@ -46,7 +46,8 @@ $serverFactory = new \OC\Connector\Sabre\ServerFactory( $requestUri = \OC::$server->getRequest()->getRequestUri(); $server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, function () use ($authBackend) { - if (OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled() === false) { + $isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'); + if (OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled() === false && !$isAjax) { // this is what is thrown when trying to access a non-existing share throw new \Sabre\DAV\Exception\NotAuthenticated(); } diff --git a/apps/files_sharing/tests/js/shareSpec.js b/apps/files_sharing/tests/js/shareSpec.js index 96a96f1b814..fd8e36d71ad 100644 --- a/apps/files_sharing/tests/js/shareSpec.js +++ b/apps/files_sharing/tests/js/shareSpec.js @@ -179,7 +179,7 @@ describe('OCA.Sharing.Util tests', function() { expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg'); expect($action.find('img').length).toEqual(1); }); - it('shows static share text when file shared with user that has no share permission', function() { + it('shows share action when shared with user who has no share permission', function() { var $action, $tr; fileList.setFiles([{ id: 1, @@ -193,14 +193,9 @@ describe('OCA.Sharing.Util tests', function() { shareOwner: 'User One' }]); $tr = fileList.$el.find('tbody tr:first'); - expect($tr.find('.action-share').length).toEqual(0); - $action = $tr.find('.action-share-notification'); - expect($action.find('>span').text().trim()).toEqual('User One'); - expect(OC.basename($action.find('img').attr('src'))).toEqual('share.svg'); - expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg'); - expect($action.find('img').length).toEqual(1); + expect($tr.find('.action-share').length).toEqual(1); }); - it('do not show static share text when share exists but neither permission nor owner is available', function() { + it('do not show share action when share exists but neither permission nor owner is available', function() { var $action, $tr; fileList.setFiles([{ id: 1, @@ -214,8 +209,6 @@ describe('OCA.Sharing.Util tests', function() { }]); $tr = fileList.$el.find('tbody tr:first'); expect($tr.find('.action-share').length).toEqual(0); - $action = $tr.find('.action-share-notification'); - expect($action.length).toEqual(0); }); }); describe('Share action', function() { diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index 0c0f955cf40..b5c1c622156 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -23,7 +23,7 @@ <tr> <th id='headerName' class="hidden column-name"> <div id="headerName-container"> - <input type="checkbox" id="select_all_trash" class="select-all"/> + <input type="checkbox" id="select_all_trash" class="select-all checkbox"/> <label for="select_all_trash"> <span class="hidden-visually"><?php p($l->t('Select all'))?></span> </label> diff --git a/apps/files_versions/js/versionstabview.js b/apps/files_versions/js/versionstabview.js index 6dab8014229..55f24868196 100644 --- a/apps/files_versions/js/versionstabview.js +++ b/apps/files_versions/js/versionstabview.js @@ -189,6 +189,18 @@ this.$el.find('.has-tooltip').tooltip(); this.$versionsContainer = this.$el.find('ul.versions'); this.delegateEvents(); + }, + + /** + * Returns true for files, false for folders. + * + * @return {bool} true for files, false for folders + */ + canDisplay: function(fileInfo) { + if (!fileInfo) { + return false; + } + return !fileInfo.isDirectory(); } }); diff --git a/build/integration/.gitignore b/build/integration/.gitignore new file mode 100644 index 00000000000..18b981bf7ed --- /dev/null +++ b/build/integration/.gitignore @@ -0,0 +1,3 @@ +vendor +output +composer.lock diff --git a/build/integration/composer.json b/build/integration/composer.json new file mode 100644 index 00000000000..98b2f294c7a --- /dev/null +++ b/build/integration/composer.json @@ -0,0 +1,7 @@ +{ + "require-dev": { + "phpunit/phpunit": "~4.6", + "guzzlehttp/guzzle": "~5.0", + "behat/behat": "2.4.*@stable" + } +} diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml new file mode 100644 index 00000000000..01ca0d18790 --- /dev/null +++ b/build/integration/config/behat.yml @@ -0,0 +1,17 @@ +default: + paths: + features: ../features + bootstrap: %behat.paths.features%/bootstrap + + context: + parameters: + baseUrl: http://localhost:8080/ocs/ + admin: + - admin + - admin + +ci: + formatter: + name: pretty,junit + parameters: + output_path: null,./output diff --git a/build/integration/features/bootstrap/FeatureContext.php b/build/integration/features/bootstrap/FeatureContext.php new file mode 100644 index 00000000000..b7a04e1ca76 --- /dev/null +++ b/build/integration/features/bootstrap/FeatureContext.php @@ -0,0 +1,142 @@ +<?php + +use Behat\Behat\Context\BehatContext; +use GuzzleHttp\Client; +use GuzzleHttp\Message\ResponseInterface; + +require __DIR__ . '/../../vendor/autoload.php'; + +/** + * Features context. + */ +class FeatureContext extends BehatContext { + + /** @var string */ + private $baseUrl = ''; + + /** @var ResponseInterface */ + private $response = null; + + /** @var string */ + private $currentUser = ''; + + /** @var int */ + private $apiVersion = 1; + + /** + * Initializes context. + * Every scenario gets it's own context object. + * + * @param array $parameters context parameters (set them up through behat.yml) + */ + public function __construct(array $parameters) { + + // Initialize your context here + $this->baseUrl = $parameters['baseUrl']; + $this->adminUser = $parameters['admin']; + + // in case of ci deployment we take the server url from the environment + $testServerUrl = getenv('TEST_SERVER_URL'); + if ($testServerUrl !== false) { + $this->baseUrl = $testServerUrl; + } + } + + /** + * @When /^sending "([^"]*)" to "([^"]*)"$/ + */ + public function sendingTo($verb, $url) { + $this->sendingToWith($verb, $url, null); + } + + /** + * @Then /^the status code should be "([^"]*)"$/ + */ + public function theStatusCodeShouldBe($statusCode) { + PHPUnit_Framework_Assert::assertEquals($statusCode, $this->response->getStatusCode()); + } + + /** + * @Given /^As an "([^"]*)"$/ + */ + public function asAn($user) { + $this->currentUser = $user; + } + + /** + * @Given /^using api version "([^"]*)"$/ + */ + public function usingApiVersion($version) { + $this->apiVersion = $version; + } + + /** + * @Given /^user "([^"]*)" exists$/ + */ + public function userExists($user) { + $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user"; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } + + $this->response = $client->get($fullUrl, $options); + PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode()); + } + + /** + * @Given /^user "([^"]*)" does not exist$/ + */ + public function userDoesNotExist($user) { + try { + $this->userExists($user); + } catch (\GuzzleHttp\Exception\ClientException $ex) { + PHPUnit_Framework_Assert::assertEquals(404, $ex->getResponse()->getStatusCode()); + } + } + + /** + * @When /^creating the user "([^"]*)r"$/ + */ + public function creatingTheUser($user) { + $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user"; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } + + $this->response = $client->post($fullUrl, [ + 'form_params' => [ + 'userid' => $user, + 'password' => '123456' + ] + ]); + PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode()); + } + + /** + * @When /^sending "([^"]*)" to "([^"]*)" with$/ + * @param \Behat\Gherkin\Node\TableNode|null $formData + */ + public function sendingToWith($verb, $url, $body) { + $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } + if ($body instanceof \Behat\Gherkin\Node\TableNode) { + $fd = $body->getRowsHash(); + $options['body'] = $fd; + } + + try { + $this->response = $client->send($client->createRequest($verb, $fullUrl, $options)); + } catch (\GuzzleHttp\Exception\ClientException $ex) { + $this->response = $ex->getResponse(); + } + } + +} diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature new file mode 100644 index 00000000000..9e3d2df50bb --- /dev/null +++ b/build/integration/features/provisioning-v1.feature @@ -0,0 +1,32 @@ +Feature: provisioning + Background: + Given using api version "1" + + Scenario: Getting an not existing user + Given As an "admin" + When sending "GET" to "/cloud/users/test" + Then the status code should be "200" + + Scenario: Listing all users + Given As an "admin" + When sending "GET" to "/cloud/users" + Then the status code should be "200" + + Scenario: Create a user + Given As an "admin" + And user "brand-new-user" does not exist + When sending "POST" to "/cloud/users" with + | userid | brand-new-user | + | password | 123456 | + + Then the status code should be "200" + And user "brand-new-user" exists + + + Scenario: Delete a user + Given As an "admin" + And user "brand-new-user" exists + When sending "POST" to "/cloud/users" with + | userid | brand-new-user | + Then the status code should be "200" + And user "brand-new-user" does not exist diff --git a/build/integration/features/provisioning-v2.feature b/build/integration/features/provisioning-v2.feature new file mode 100644 index 00000000000..72ceed5d6a5 --- /dev/null +++ b/build/integration/features/provisioning-v2.feature @@ -0,0 +1,9 @@ +Feature: provisioning + Background: + Given using api version "2" + + Scenario: Getting an not existing user + Given As an "admin" + When sending "GET" to "/cloud/users/test" + Then the status code should be "404" + diff --git a/build/integration/run.sh b/build/integration/run.sh new file mode 100755 index 00000000000..08f10b86c5f --- /dev/null +++ b/build/integration/run.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +composer install + +# TODO: avoid port collision on jenkins - use $EXECUTOR_NUMBER +if [ -z "$EXECUTOR_NUMBER" ]; then + EXECUTOR_NUMBER=0 +fi +PORT=$((8080 + $EXECUTOR_NUMBER)) +#PORT=8080 +echo $PORT +php -S localhost:$PORT -t ../.. & +PHPPID=$! +echo $PHPPID + +export TEST_SERVER_URL="http://localhost:$PORT/ocs/" +vendor/bin/behat --profile ci + +kill $PHPPID diff --git a/core/js/js.js b/core/js/js.js index b5971bfc579..397fea8e3c5 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -1773,9 +1773,7 @@ OC.Util.History = { params = OC.parseQueryString(this._decodeQuery(query)); } // else read from query attributes - if (!params) { - params = OC.parseQueryString(this._decodeQuery(location.search)); - } + params = _.extend(params || {}, OC.parseQueryString(this._decodeQuery(location.search))); return params || {}; }, diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 57743118f28..ee31ed33132 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -14,7 +14,7 @@ } var TEMPLATE_BASE = - '<div class="resharerInfoView"></div>' + + '<div class="resharerInfoView subView"></div>' + '{{#if isSharingAllowed}}' + '<label for="shareWith" class="hidden-visually">{{shareLabel}}</label>' + '<div class="oneline">' + @@ -23,10 +23,10 @@ '{{{remoteShareInfo}}}' + '</div>' + '{{/if}}' + - '<div class="shareeListView"></div>' + - '<div class="linkShareView"></div>' + - '<div class="expirationView"></div>' - ; + '<div class="shareeListView subView"></div>' + + '<div class="linkShareView subView"></div>' + + '<div class="expirationView subView"></div>' + + '<div class="loading hidden" style="height: 50px"></div>'; var TEMPLATE_REMOTE_SHARE_INFO = '<a target="_blank" class="icon-info svg shareWithRemoteInfo hasTooltip" href="{{docLink}}" ' + @@ -87,6 +87,9 @@ view.render(); }); + this.model.on('request', this._onRequest, this); + this.model.on('sync', this._onEndRequest, this); + var subViewOptions = { model: this.model, configModel: this.configModel @@ -161,6 +164,24 @@ this.model.addShare(s.item.value); }, + _toggleLoading: function(state) { + this._loading = state; + this.$el.find('.subView').toggleClass('hidden', state); + this.$el.find('.loading').toggleClass('hidden', !state); + }, + + _onRequest: function() { + // only show the loading spinner for the first request (for now) + if (!this._loadingOnce) { + this._toggleLoading(true); + this._loadingOnce = true; + } + }, + + _onEndRequest: function() { + this._toggleLoading(false); + }, + render: function() { var baseTemplate = this._getTemplate('base', TEMPLATE_BASE); diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index 13396670aae..328d291b778 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -624,7 +624,9 @@ fetch: function() { var model = this; + this.trigger('request', this); OC.Share.loadItem(this.get('itemType'), this.get('itemSource'), function(data) { + model.trigger('sync', 'GET', this); model.set(model.parse(data)); }); }, diff --git a/core/l10n/cs_CZ.js b/core/l10n/cs_CZ.js index bcbc2527dec..6661318154b 100644 --- a/core/l10n/cs_CZ.js +++ b/core/l10n/cs_CZ.js @@ -150,6 +150,7 @@ OC.L10N.register( "Share with users or groups …" : "Sdílet s uživateli nebo skupinami", "Share with users, groups or remote users …" : "Sdílet s uživateli, skupinami nebo vzdálenými uživateli", "Warning" : "Varování", + "Error while sending notification" : "Chyba při odesílání upozornění", "The object type is not specified." : "Není určen typ objektu.", "Enter new" : "Zadat nový", "Delete" : "Smazat", @@ -179,6 +180,7 @@ OC.L10N.register( "New Password" : "Nové heslo", "Reset password" : "Obnovit heslo", "Searching other places" : "Prohledávání ostatních umístění", + "No search results in other folders" : "V ostatních adresářích nebylo nic nalezeno", "Personal" : "Osobní", "Users" : "Uživatelé", "Apps" : "Aplikace", diff --git a/core/l10n/cs_CZ.json b/core/l10n/cs_CZ.json index f384b772679..bb7e050231c 100644 --- a/core/l10n/cs_CZ.json +++ b/core/l10n/cs_CZ.json @@ -148,6 +148,7 @@ "Share with users or groups …" : "Sdílet s uživateli nebo skupinami", "Share with users, groups or remote users …" : "Sdílet s uživateli, skupinami nebo vzdálenými uživateli", "Warning" : "Varování", + "Error while sending notification" : "Chyba při odesílání upozornění", "The object type is not specified." : "Není určen typ objektu.", "Enter new" : "Zadat nový", "Delete" : "Smazat", @@ -177,6 +178,7 @@ "New Password" : "Nové heslo", "Reset password" : "Obnovit heslo", "Searching other places" : "Prohledávání ostatních umístění", + "No search results in other folders" : "V ostatních adresářích nebylo nic nalezeno", "Personal" : "Osobní", "Users" : "Uživatelé", "Apps" : "Aplikace", diff --git a/core/l10n/el.js b/core/l10n/el.js index 59490289bfd..79f6725e776 100644 --- a/core/l10n/el.js +++ b/core/l10n/el.js @@ -182,6 +182,8 @@ OC.L10N.register( "New Password" : "Νέος Κωδικός", "Reset password" : "Επαναφορά συνθηματικού", "Searching other places" : "Έρευνα σε άλλα σημεία.", + "No search results in other folders" : "Δεν υπάρχουν αποτελέσματα αναζήτησης σε άλλους φακέλους", + "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} αποτέλεσμα αναζήτησης σε άλλο φάκελο","{count} αποτελέσματα αναζήτησης σε άλλους φακέλους"], "Personal" : "Προσωπικά", "Users" : "Χρήστες", "Apps" : "Εφαρμογές", diff --git a/core/l10n/el.json b/core/l10n/el.json index 66f177d11b6..3fb2fbae8a5 100644 --- a/core/l10n/el.json +++ b/core/l10n/el.json @@ -180,6 +180,8 @@ "New Password" : "Νέος Κωδικός", "Reset password" : "Επαναφορά συνθηματικού", "Searching other places" : "Έρευνα σε άλλα σημεία.", + "No search results in other folders" : "Δεν υπάρχουν αποτελέσματα αναζήτησης σε άλλους φακέλους", + "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} αποτέλεσμα αναζήτησης σε άλλο φάκελο","{count} αποτελέσματα αναζήτησης σε άλλους φακέλους"], "Personal" : "Προσωπικά", "Users" : "Χρήστες", "Apps" : "Εφαρμογές", diff --git a/lib/l10n/oc.js b/lib/l10n/oc.js index c61eaae5f22..2e6bfe56fe6 100644 --- a/lib/l10n/oc.js +++ b/lib/l10n/oc.js @@ -13,6 +13,7 @@ OC.L10N.register( "last year" : "an passat", "seconds ago" : "segonda a", "web services under your control" : "Services web jos ton contraròtle", + "File name contains at least one invalid character" : "Lo nom de fichièr conten al mens un caractèr invalid", "Authentication error" : "Error d'autentificacion", "Apps" : "Aplicacions", "A valid username must be provided" : "Un nom d'utilizaire valid deu èsser picat", diff --git a/lib/l10n/oc.json b/lib/l10n/oc.json index ea9f41c419d..3ac8367f556 100644 --- a/lib/l10n/oc.json +++ b/lib/l10n/oc.json @@ -11,6 +11,7 @@ "last year" : "an passat", "seconds ago" : "segonda a", "web services under your control" : "Services web jos ton contraròtle", + "File name contains at least one invalid character" : "Lo nom de fichièr conten al mens un caractèr invalid", "Authentication error" : "Error d'autentificacion", "Apps" : "Aplicacions", "A valid username must be provided" : "Un nom d'utilizaire valid deu èsser picat", diff --git a/lib/private/assetic/separatorfilter.php b/lib/private/assetic/separatorfilter.php deleted file mode 100644 index ee6d5c11c20..00000000000 --- a/lib/private/assetic/separatorfilter.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin McCorkell <rmccorkell@karoshi.org.uk> - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @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 OC\Assetic; - -use Assetic\Filter\FilterInterface; -use Assetic\Asset\AssetInterface; - -/** - * Inserts a separator between assets to prevent merge failures - * e.g. missing semicolon at the end of a JS file - */ -class SeparatorFilter implements FilterInterface -{ - /** - * @var string - */ - private $separator; - - /** - * Constructor. - * - * @param string $separator Separator to use between assets - */ - public function __construct($separator = ';') - { - $this->separator = $separator; - } - - public function filterLoad(AssetInterface $asset) - { - } - - public function filterDump(AssetInterface $asset) - { - $asset->setContent($asset->getContent() . $this->separator); - } -} diff --git a/lib/private/lock/dblockingprovider.php b/lib/private/lock/dblockingprovider.php index a08357a6024..8f017a713c1 100644 --- a/lib/private/lock/dblockingprovider.php +++ b/lib/private/lock/dblockingprovider.php @@ -102,10 +102,6 @@ class DBLockingProvider extends AbstractLockingProvider { * @throws \OCP\Lock\LockedException */ public function acquireLock($path, $type) { - if ($this->connection->inTransaction()) { - $this->logger->warning("Trying to acquire a lock for '$path' while inside a transition"); - } - $expire = $this->getExpireTime(); if ($type === self::LOCK_SHARED) { $result = $this->initLockField($path,1); diff --git a/lib/private/response.php b/lib/private/response.php index f1a429463f2..14ee92972a9 100644 --- a/lib/private/response.php +++ b/lib/private/response.php @@ -247,7 +247,7 @@ class OC_Response { . 'script-src \'self\' \'unsafe-eval\'; ' . 'style-src \'self\' \'unsafe-inline\'; ' . 'frame-src *; ' - . 'img-src *; ' + . 'img-src * data:; ' . 'font-src \'self\' data:; ' . 'media-src *; ' . 'connect-src *'; diff --git a/lib/private/session/cryptowrapper.php b/lib/private/session/cryptowrapper.php index 261514d683e..70c1dab7404 100644 --- a/lib/private/session/cryptowrapper.php +++ b/lib/private/session/cryptowrapper.php @@ -39,7 +39,7 @@ use OCP\Security\ISecureRandom; * it as an additional small security obfuscation layer to comply with compliance * guidelines. * - * TODO: Remove this in a future relase with an approach such as + * TODO: Remove this in a future release with an approach such as * https://github.com/owncloud/core/pull/17866 * * @package OC\Session diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php index 8ee21272104..e10999ec48f 100644 --- a/lib/private/session/internal.php +++ b/lib/private/session/internal.php @@ -106,7 +106,7 @@ class Internal extends Session { private function validateSession() { if ($this->sessionClosed) { - throw new \Exception('Session has been closed - no further changes to the session as allowed'); + throw new \Exception('Session has been closed - no further changes to the session are allowed'); } } } diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php index 1cae62e44d3..0fc9165c7cd 100644 --- a/lib/private/session/memory.php +++ b/lib/private/session/memory.php @@ -93,7 +93,7 @@ class Memory extends Session { */ private function validateSession() { if ($this->sessionClosed) { - throw new \Exception('Session has been closed - no further changes to the session as allowed'); + throw new \Exception('Session has been closed - no further changes to the session are allowed'); } } } diff --git a/lib/private/templatelayout.php b/lib/private/templatelayout.php index ae3c1093b20..43c83dea815 100644 --- a/lib/private/templatelayout.php +++ b/lib/private/templatelayout.php @@ -38,8 +38,8 @@ use Assetic\AssetWriter; use Assetic\Filter\CssImportFilter; use Assetic\Filter\CssMinFilter; use Assetic\Filter\CssRewriteFilter; -use Assetic\Filter\JSMinFilter; -use OC\Assetic\SeparatorFilter; // waiting on upstream +use Assetic\Filter\JSqueezeFilter; +use Assetic\Filter\SeparatorFilter; /** * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> @@ -225,7 +225,7 @@ class OC_TemplateLayout extends OC_Template { ), $root, $file); } return new FileAsset($root . '/' . $file, array( - new JSMinFilter(), + new JSqueezeFilter(), new SeparatorFilter(';') ), $root, $file); }, $jsFiles); diff --git a/settings/l10n/el.js b/settings/l10n/el.js index e1ca38deeee..363758011e1 100644 --- a/settings/l10n/el.js +++ b/settings/l10n/el.js @@ -149,6 +149,7 @@ OC.L10N.register( "Allow users to send mail notification for shared files to other users" : "Να επιτρέπεται η αποστολή ειδοποιήσεων σε άλλους χρήστες, μέσω αλληλογραφίας για κοινόχρηστα αρχεία", "Exclude groups from sharing" : "Εξαίρεση ομάδων από τον διαμοιρασμό", "These groups will still be able to receive shares, but not to initiate them." : "Αυτές οι ομάδες θα συνεχίσουν να λαμβάνουν διαμοιρασμούς, αλλά δεν θα είναι δυνατό να τους δημιουργήσουν.", + "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Να επιτρέπεται η χρήση αυτόματης συμπλήρωσης στο διάλογο διαμοιρασμού. Αν αυτό είναι απενεργοποιημένο θα πρέπει να εισαχθεί το πλήρες όνομα χρήστη.", "Last cron job execution: %s." : "Τελευταία εκτέλεση cron job: %s.", "Last cron job execution: %s. Something seems wrong." : "Τελευταία εκτέλεση cron job: %s. Κάτι πήγε στραβά.", "Cron was not executed yet!" : "Η διεργασία cron δεν έχει εκτελεστεί ακόμα!", diff --git a/settings/l10n/el.json b/settings/l10n/el.json index 92873fb1675..12d2436fc92 100644 --- a/settings/l10n/el.json +++ b/settings/l10n/el.json @@ -147,6 +147,7 @@ "Allow users to send mail notification for shared files to other users" : "Να επιτρέπεται η αποστολή ειδοποιήσεων σε άλλους χρήστες, μέσω αλληλογραφίας για κοινόχρηστα αρχεία", "Exclude groups from sharing" : "Εξαίρεση ομάδων από τον διαμοιρασμό", "These groups will still be able to receive shares, but not to initiate them." : "Αυτές οι ομάδες θα συνεχίσουν να λαμβάνουν διαμοιρασμούς, αλλά δεν θα είναι δυνατό να τους δημιουργήσουν.", + "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Να επιτρέπεται η χρήση αυτόματης συμπλήρωσης στο διάλογο διαμοιρασμού. Αν αυτό είναι απενεργοποιημένο θα πρέπει να εισαχθεί το πλήρες όνομα χρήστη.", "Last cron job execution: %s." : "Τελευταία εκτέλεση cron job: %s.", "Last cron job execution: %s. Something seems wrong." : "Τελευταία εκτέλεση cron job: %s. Κάτι πήγε στραβά.", "Cron was not executed yet!" : "Η διεργασία cron δεν έχει εκτελεστεί ακόμα!", diff --git a/settings/l10n/fr.js b/settings/l10n/fr.js index b11e361f921..a7c389aab1e 100644 --- a/settings/l10n/fr.js +++ b/settings/l10n/fr.js @@ -125,7 +125,7 @@ OC.L10N.register( "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Votre serveur fonctionne actuellement sur une plateforme Microsoft Windows. Nous vous recommandons fortement d'utiliser une plateforme Linux pour une expérience utilisateur optimale.", "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Une version de %1$s plus ancienne que %2$s est installée. Pour améliorer la stabilité et les performances, nous recommandons de mettre %1$s à jour.", "The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Le module PHP 'fileinfo' est manquant. Il est vivement recommandé de l'activer afin d'obtenir de meilleurs résultats de détection mime-type.", - "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Le verrouillage transactionnel de fichiers est désactivé, cela peut conduire à des conflits d'accès. Activer 'filelocking.enabled' dans config.php pour éviter ces problèmes. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.", + "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Le verrouillage transactionnel de fichiers est désactivé, cela peut conduire à des conflits en cas d'accès concurrents. Activez 'filelocking.enabled' dans config.php pour éviter ces problèmes. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.", "System locale can not be set to a one which supports UTF-8." : "Les paramètres régionaux n'ont pu être configurés avec prise en charge d'UTF-8.", "This means that there might be problems with certain characters in file names." : "Cela signifie qu'il pourrait y avoir des problèmes avec certains caractères dans les noms de fichier.", "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nous vous recommandons d'installer sur votre système les paquets nécessaires à la prise en charge de l'un des paramètres régionaux suivants : %s", @@ -149,7 +149,7 @@ OC.L10N.register( "Allow users to send mail notification for shared files to other users" : "Autoriser les utilisateurs à envoyer des notifications de partage par e-mail", "Exclude groups from sharing" : "Empêcher certains groupes de partager", "These groups will still be able to receive shares, but not to initiate them." : "Ces groupes ne pourront plus initier de partage, mais ils pourront toujours rejoindre les partages faits par d'autres. ", - "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Autoriser la complétion du nom d'utilisateur dans les champs de partage. Sinon le nom complet d'utilisateur doit être indiqué.", + "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Autoriser la complétion du nom d'utilisateur dans la fenêtre de partage. Sinon le nom complet d'utilisateur doit être indiqué.", "Last cron job execution: %s." : "Dernière tâche cron exécutée : %s.", "Last cron job execution: %s. Something seems wrong." : "Dernière tâche cron exécutée : %s. Quelque chose s'est mal passé.", "Cron was not executed yet!" : "Le cron n'a pas encore été exécuté !", diff --git a/settings/l10n/fr.json b/settings/l10n/fr.json index 327801cf0e9..81011944298 100644 --- a/settings/l10n/fr.json +++ b/settings/l10n/fr.json @@ -123,7 +123,7 @@ "Your server is running on Microsoft Windows. We highly recommend Linux for optimal user experience." : "Votre serveur fonctionne actuellement sur une plateforme Microsoft Windows. Nous vous recommandons fortement d'utiliser une plateforme Linux pour une expérience utilisateur optimale.", "%1$s below version %2$s is installed, for stability and performance reasons we recommend to update to a newer %1$s version." : "Une version de %1$s plus ancienne que %2$s est installée. Pour améliorer la stabilité et les performances, nous recommandons de mettre %1$s à jour.", "The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." : "Le module PHP 'fileinfo' est manquant. Il est vivement recommandé de l'activer afin d'obtenir de meilleurs résultats de détection mime-type.", - "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Le verrouillage transactionnel de fichiers est désactivé, cela peut conduire à des conflits d'accès. Activer 'filelocking.enabled' dans config.php pour éviter ces problèmes. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.", + "Transactional file locking is disabled, this might lead to issues with race conditions. Enable 'filelocking.enabled' in config.php to avoid these problems. See the <a target=\"_blank\" href=\"%s\">documentation ↗</a> for more information." : "Le verrouillage transactionnel de fichiers est désactivé, cela peut conduire à des conflits en cas d'accès concurrents. Activez 'filelocking.enabled' dans config.php pour éviter ces problèmes. Consultez la <a target=\"_blank\" href=\"%s\">documentation ↗</a> pour plus d'informations.", "System locale can not be set to a one which supports UTF-8." : "Les paramètres régionaux n'ont pu être configurés avec prise en charge d'UTF-8.", "This means that there might be problems with certain characters in file names." : "Cela signifie qu'il pourrait y avoir des problèmes avec certains caractères dans les noms de fichier.", "We strongly suggest installing the required packages on your system to support one of the following locales: %s." : "Nous vous recommandons d'installer sur votre système les paquets nécessaires à la prise en charge de l'un des paramètres régionaux suivants : %s", @@ -147,7 +147,7 @@ "Allow users to send mail notification for shared files to other users" : "Autoriser les utilisateurs à envoyer des notifications de partage par e-mail", "Exclude groups from sharing" : "Empêcher certains groupes de partager", "These groups will still be able to receive shares, but not to initiate them." : "Ces groupes ne pourront plus initier de partage, mais ils pourront toujours rejoindre les partages faits par d'autres. ", - "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Autoriser la complétion du nom d'utilisateur dans les champs de partage. Sinon le nom complet d'utilisateur doit être indiqué.", + "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "Autoriser la complétion du nom d'utilisateur dans la fenêtre de partage. Sinon le nom complet d'utilisateur doit être indiqué.", "Last cron job execution: %s." : "Dernière tâche cron exécutée : %s.", "Last cron job execution: %s. Something seems wrong." : "Dernière tâche cron exécutée : %s. Quelque chose s'est mal passé.", "Cron was not executed yet!" : "Le cron n'a pas encore été exécuté !", diff --git a/settings/l10n/th_TH.js b/settings/l10n/th_TH.js index 62f0164c787..5757116f68d 100644 --- a/settings/l10n/th_TH.js +++ b/settings/l10n/th_TH.js @@ -149,6 +149,7 @@ OC.L10N.register( "Allow users to send mail notification for shared files to other users" : "อนุญาตให้ผู้ใช้ส่งการแจ้งเตือนอีเมลสำหรับไฟล์ที่แชร์กับผู้ใช้อื่นๆ", "Exclude groups from sharing" : "ไม่รวมกลุ่มที่แชร์", "These groups will still be able to receive shares, but not to initiate them." : "กลุ่มนี้จะยังคงสามารถได้รับการแชร์ แต่พวกเขาจะไม่รู้จักมัน", + "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "อนุญาตให้เติมชื่อผู้ใช้ในกล่องตอบโต้อัตโนมัติ ถ้านี้ถูกปิดใช้งานชื่อผู้ใช้จะต้องกรอกเอง", "Last cron job execution: %s." : "การดำเนินการ cron job ล่าสุด: %s", "Last cron job execution: %s. Something seems wrong." : "การดำเนินการ cron job ล่าสุด: %s ดูเหมือนมีบางสิ่งไม่ถูกต้อง", "Cron was not executed yet!" : "Cron ไม่ได้ถูกดำเนินการ!", diff --git a/settings/l10n/th_TH.json b/settings/l10n/th_TH.json index 92670ee82d8..b2ef07d5e29 100644 --- a/settings/l10n/th_TH.json +++ b/settings/l10n/th_TH.json @@ -147,6 +147,7 @@ "Allow users to send mail notification for shared files to other users" : "อนุญาตให้ผู้ใช้ส่งการแจ้งเตือนอีเมลสำหรับไฟล์ที่แชร์กับผู้ใช้อื่นๆ", "Exclude groups from sharing" : "ไม่รวมกลุ่มที่แชร์", "These groups will still be able to receive shares, but not to initiate them." : "กลุ่มนี้จะยังคงสามารถได้รับการแชร์ แต่พวกเขาจะไม่รู้จักมัน", + "Allow username autocompletion in share dialog. If this is disabled the full username needs to be entered." : "อนุญาตให้เติมชื่อผู้ใช้ในกล่องตอบโต้อัตโนมัติ ถ้านี้ถูกปิดใช้งานชื่อผู้ใช้จะต้องกรอกเอง", "Last cron job execution: %s." : "การดำเนินการ cron job ล่าสุด: %s", "Last cron job execution: %s. Something seems wrong." : "การดำเนินการ cron job ล่าสุด: %s ดูเหมือนมีบางสิ่งไม่ถูกต้อง", "Cron was not executed yet!" : "Cron ไม่ได้ถูกดำเนินการ!", |