diff options
author | mbi <knox@users.noreply.github.com> | 2015-12-08 21:02:52 +0100 |
---|---|---|
committer | mbi <knox@users.noreply.github.com> | 2015-12-08 21:02:52 +0100 |
commit | 508c46a112d3d53b4b0668efcbe1403eb2e143b8 (patch) | |
tree | 29ef86459abae1dcaadf75203851ab9b39ec43bd /apps/files_external | |
parent | 27f420e0a797f8a56b5e83e8dd8e19df289c766b (diff) | |
parent | 13993c4a6db83c0a637fc7c20da0470acae47208 (diff) | |
download | nextcloud-server-508c46a112d3d53b4b0668efcbe1403eb2e143b8.tar.gz nextcloud-server-508c46a112d3d53b4b0668efcbe1403eb2e143b8.zip |
Merge branch 'master' into master
Diffstat (limited to 'apps/files_external')
23 files changed, 788 insertions, 11 deletions
diff --git a/apps/files_external/command/listcommand.php b/apps/files_external/command/listcommand.php index 4c027ffcb8e..baba9be59f5 100644 --- a/apps/files_external/command/listcommand.php +++ b/apps/files_external/command/listcommand.php @@ -29,7 +29,6 @@ use OCP\IUserManager; use OCP\IUserSession; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; -use Symfony\Component\Console\Helper\TableHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; diff --git a/apps/files_external/css/external.css b/apps/files_external/css/external.css new file mode 100644 index 00000000000..bf57ec88053 --- /dev/null +++ b/apps/files_external/css/external.css @@ -0,0 +1,8 @@ +#filestable tbody tr.externalDisabledRow { + background-color: #CCC; +} + + +#filestable tbody tr.externalErroredRow { + background-color: #F2DEDE; +} diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js index 1bff3014bd6..d3ce2010ecd 100644 --- a/apps/files_external/js/app.js +++ b/apps/files_external/js/app.js @@ -73,5 +73,42 @@ $(document).ready(function() { $('#app-content-extstoragemounts').on('hide', function() { OCA.External.App.removeList(); }); + + /* Status Manager */ + if ($('#filesApp').val()) { + + $('#app-content-files') + .add('#app-content-extstoragemounts') + .on('changeDirectory', function(e){ + 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); + }); + } + }) + .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)) { + // Will be the very first check when the files view will be loaded + OCA.External.StatusManager.launchFullConnectivityCheckOneByOne(); + } else { + // When we change between general files view and external files view + OCA.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); + }); + } + } + }); + } + /* End Status Manager */ }); diff --git a/apps/files_external/js/rollingqueue.js b/apps/files_external/js/rollingqueue.js new file mode 100644 index 00000000000..58cb0fb22f0 --- /dev/null +++ b/apps/files_external/js/rollingqueue.js @@ -0,0 +1,137 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos <jvillafanez@owncloud.com> + * @author Jesus Macias Portela <jesus@owncloud.com> + * @copyright (C) 2014 ownCloud, Inc. + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function(){ +/** + * Launch several functions at thee same time. The number of functions + * running at the same time is controlled by the queueWindow param + * + * The function list come in the following format: + * + * var flist = [ + * { + * funcName: function () { + * var d = $.Deferred(); + * setTimeout(function(){d.resolve();}, 1000); + * return d; + * } + * }, + * { + * funcName: $.get, + * funcArgs: [ + * OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), + * {}, + * function () { + * console.log('titoooo'); + * } + * ] + * }, + * { + * funcName: $.get, + * funcArgs: [ + * OC.filePath('files_external', 'ajax', 'connectivityCheck.php') + * ], + * done: function () { + * console.log('yuupi'); + * }, + * always: function () { + * console.log('always done'); + * } + * } + *]; + * + * functions MUST implement the deferred interface + * + * @param functionList list of functions that the queue will run + * (check example above for the expected format) + * @param queueWindow specify the number of functions that will + * be executed at the same time + */ +var RollingQueue = function (functionList, queueWindow, callback) { + this.queueWindow = queueWindow || 1; + this.functionList = functionList; + this.callback = callback; + this.counter = 0; + this.runQueue = function() { + this.callbackCalled = false; + this.deferredsList = []; + if (!$.isArray(this.functionList)) { + throw "functionList must be an array"; + } + + for (i = 0; i < this.queueWindow; i++) { + this.launchNext(); + } + }; + + this.hasNext = function() { + return (this.counter in this.functionList); + }; + + this.launchNext = function() { + var currentCounter = this.counter++; + if (currentCounter in this.functionList) { + var funcData = this.functionList[currentCounter]; + if ($.isFunction(funcData.funcName)) { + var defObj = funcData.funcName.apply(funcData.funcName, funcData.funcArgs); + this.deferredsList.push(defObj); + if ($.isFunction(funcData.done)) { + defObj.done(funcData.done); + } + + if ($.isFunction(funcData.fail)) { + defObj.fail(funcData.fail); + } + + if ($.isFunction(funcData.always)) { + defObj.always(funcData.always); + } + + if (this.hasNext()) { + var self = this; + defObj.always(function(){ + _.defer($.proxy(function(){ + self.launchNext(); + }, self)); + }); + } else { + if (!this.callbackCalled) { + this.callbackCalled = true; + if ($.isFunction(this.callback)) { + $.when.apply($, this.deferredsList) + .always($.proxy(function(){ + this.callback(); + }, this) + ); + } + } + } + return defObj; + } + } + return false; + }; +}; + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager.RollingQueue = RollingQueue; + +})();
\ No newline at end of file diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js new file mode 100644 index 00000000000..4048bfc31bc --- /dev/null +++ b/apps/files_external/js/statusmanager.js @@ -0,0 +1,539 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos <jvillafanez@owncloud.com> + * @author Jesus Macias Portela <jesus@owncloud.com> + * @copyright (C) 2014 ownCloud, Inc. + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager = { + + mountStatus : null, + mountPointList : null, + + /** + * Function + * @param {callback} afterCallback + */ + + getMountStatus : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return; + } + + if (self.mountStatus) { + afterCallback(self.mountStatus); + } + }, + + /** + * Function Check mount point status from cache + * @param {string} mount_point + */ + + getMountPointListElement : function(mount_point) { + var element; + $.each(this.mountPointList, function(key, value){ + if (value.mount_point === mount_point) { + element = value; + return false; + } + }); + return element; + }, + + /** + * Function Check mount point status from cache + * @param {string} mount_point + * @param {string} mount_point + */ + + getMountStatusForMount : function(mountData, afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return $.Deferred().resolve(); + } + + var defObj; + if (self.mountStatus[mountData.mount_point]) { + defObj = $.Deferred(); + afterCallback(mountData, self.mountStatus[mountData.mount_point]); + defObj.resolve(); // not really useful, but it'll keep the same behaviour + } else { + defObj = $.ajax({ + type : 'GET', + url: OC.webroot + '/index.php/apps/files_external/' + ((mountData.type === 'personal') ? 'userstorages' : 'globalstorages') + '/' + mountData.id, + success : function(response) { + if (response && response.status === 0) { + self.mountStatus[mountData.mount_point] = response; + } else { + if (response && response.statusMessage) { + // failure response with error message + self.mountStatus[mountData.mount_point] = { type: mountData.type, + status: 1, + error: response.statusMessage}; + } else { + self.mountStatus[mountData.mount_point] = { type: mountData.type, + status: 1, + error: t('files_external', 'Empty response from the server')}; + } + } + afterCallback(mountData, self.mountStatus[mountData.mount_point]); + }, + error : function(jqxhr, state, error) { + var message; + if(mountData.location === 3){ + // In this case the error is because mount point use Login credentials and don't exist in the session + message = t('files_external', 'Couldn\'t access. Please logout and login to activate this mount point'); + } else { + message = t('files_external', 'Couldn\'t get the information from the ownCloud server: {code} {type}', {code: jqxhr.status, type: error}); + } + self.mountStatus[mountData.mount_point] = { type: mountData.type, + status: 1, + location: mountData.location, + error: message}; + afterCallback(mountData, self.mountStatus[mountData.mount_point]); + } + }); + } + return defObj; + }, + + /** + * Function to get external mount point list from the files_external API + * @param {function} afterCallback function to be executed + */ + + getMountPointList : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountPointListRunning) { + return; + } + + if (self.mountPointList) { + afterCallback(self.mountPointList); + } else { + self.isGetMountPointListRunning = true; + $.ajax({ + type : 'GET', + url : OC.linkToOCS('apps/files_external/api/v1') + 'mounts?format=json', + success : function(response) { + self.mountPointList = []; + _.each(response.ocs.data, function(mount){ + var element = {}; + element.mount_point = mount.name; + element.type = mount.scope; + element.location = ""; + element.id = mount.id; + element.backendText = mount.backend; + element.backend = mount.class; + + self.mountPointList.push(element); + }); + afterCallback(self.mountPointList); + }, + error : function(jqxhr, state, error) { + self.mountPointList = []; + OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the list of external mount points: {type}', {type : error})); + }, + complete : function() { + self.isGetMountPointListRunning = false; + } + }); + } + }, + + /** + * Function to manage action when a mountpoint status = 1 (Errored). Show a dialog to be redirected to settings page. + * @param {string} name MountPoint Name + */ + + manageMountPointError : function(name) { + var self = this; + this.getMountStatus($.proxy(function(allMountStatus) { + if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 1) { + var mountData = allMountStatus[name]; + if (mountData.type === "system") { + OC.dialogs.confirm(t('files_external', 'There was an error with message: ') + mountData.error + '. Do you want to review mount point config in admin settings page?', t('files_external', 'External mount error'), function(e){ + if(e === true) { + window.location.href = OC.generateUrl('/settings/admin#files_external'); + } + }); + } else { + OC.dialogs.confirm(t('files_external', 'There was an error with message: ') + mountData.error + '. Do you want to review mount point config in personal settings page?', t('files_external', 'External mount error'), function(e){ + if(e === true) { + window.location.href = OC.generateUrl('/settings/personal#' + t('files_external', 'goto-external-storage')); + } + }); + } + } + }, this)); + }, + + /** + * Function to process a mount point in relation with their status, Called from Async Queue. + * @param {object} mountData + * @param {object} mountStatus + */ + + processMountStatusIndividual : function(mountData, mountStatus) { + + var mountPoint = mountData.mount_point; + if (mountStatus.status === 1) { + var trElement = FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(mountPoint)); + + route = OCA.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); + } + return false; + } else { + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + } + return true; + } + }, + + /** + * Function to process a mount point in relation with their status + * @param {object} mountData + * @param {object} mountStatus + */ + + 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)); + trElement.attr('data-external-backend', value.backend); + if (elementList) { + elementList = elementList.add(trElement); + } else { + elementList = trElement; + } + }); + + if (elementList instanceof $) { + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + // Put their custom icon + OCA.External.StatusManager.Utils.changeFolderIcon(elementList); + // Save default view + OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); + // Disable row until check status + elementList.addClass('externalDisabledRow'); + OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); + } + } + }, + + /** + * Function to process the whole mount point list in relation with their status (Async queue) + */ + + launchFullConnectivityCheckOneByOne : function() { + var self = this; + this.getMountPointList(function(list){ + // check if we have a list first + if (list === undefined && !self.emptyWarningShown) { + self.emptyWarningShown = true; + OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the list of Windows network drive mount points: empty response from the server')); + return; + } + if (list && list.length > 0) { + self.processMountList(list); + + if (!self.mountStatus) { + self.mountStatus = {}; + } + + var ajaxQueue = []; + $.each(list, function(key, value){ + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); + + var rolQueue = new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4, function(){ + if (!self.notificationHasShown) { + var showNotification = false; + $.each(self.mountStatus, function(key, value){ + if (value.status === 1) { + self.notificationHasShown = true; + showNotification = true; + } + }); + if (showNotification) { + OC.Notification.showTemporary(t('files_external', 'Some of the configured external mount points are not connected. Please click on the red row(s) for more information')); + } + } + }); + rolQueue.runQueue(); + } + }); + }, + + + /** + * Function to process a mount point list in relation with their status (Async queue) + * @param {object} mountListData + * @param {boolean} recheck delete cached info and force api call to check mount point status + */ + + launchPartialConnectivityCheck : function(mountListData, recheck) { + if (mountListData.length === 0) { + return; + } + + var self = this; + var ajaxQueue = []; + $.each(mountListData, function(key, value){ + if (recheck && value.mount_point in self.mountStatus) { + delete self.mountStatus[value.mount_point]; + } + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); + new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue(); + }, + + + /** + * Function to relaunch some mount point status check + * @param {string} mountListNames + * @param {boolean} recheck delete cached info and force api call to check mount point status + */ + + recheckConnectivityForMount : function(mountListNames, recheck) { + if (mountListNames.length === 0) { + return; + } + + var self = this; + var mountListData = []; + var recheckPersonalGlobal = false; + var recheckAdminGlobal = false; + + if (!self.mountStatus) { + self.mountStatus = {}; + } + + $.each(mountListNames, function(key, value){ + var mountData = self.getMountPointListElement(value); + if (mountData) { + mountListData.push(mountData); + } + }); + + // for all mounts in the list, delete the cached status values + if (recheck) { + $.each(mountListData, function(key, value){ + if (value.mount_point in self.mountStatus) { + delete self.mountStatus[value.mount_point]; + } + }); + } + + self.processMountList(mountListData); + self.launchPartialConnectivityCheck(mountListData, recheck); + } +}; + +OCA.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)); + this.changeFolderIcon(folder, imageUrl); + this.toggleLink(folder, false, clickAction); + trFolder.addClass('externalErroredRow'); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the tr element + */ + storeDefaultFolderIconAndBgcolor: function(folder) { + var trFolder; + 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.each(function(){ + var thisElement = $(this); + if (thisElement.data('oldbgcolor') === undefined) { + thisElement.data('oldbgcolor', thisElement.css('background-color')); + } + }); + + var icon = trFolder.find('td:first-child div.thumbnail'); + icon.each(function(){ + var thisElement = $(this); + if (thisElement.data('oldImage') === undefined) { + thisElement.data('oldImage', thisElement.css('background-image')); + } + }); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the tr element + */ + restoreFolder: function(folder) { + var trFolder; + if (folder instanceof $) { + trFolder = folder; + } else { + // cant 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) + '\"]'); + } + trFolder.removeClass('externalErroredRow').removeClass('externalDisabledRow'); + tdChilds = trFolder.find("td:first-child div.thumbnail"); + tdChilds.each(function(){ + var thisElement = $(this); + thisElement.css('background-image', thisElement.data('oldImage')); + }); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the first td element + * of the tr matching the folder name + */ + changeFolderIcon: function(filename) { + var file; + var route; + if (filename instanceof $) { + //trElementList + $.each(filename, function(index){ + route = OCA.External.StatusManager.Utils.getIconRoute($(this)); + $(this).attr("data-icon", route); + $(this).find('td:first-child div.thumbnail').css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline'); + }); + } else { + file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail"); + parentTr = file.parents('tr:first'); + route = OCA.External.StatusManager.Utils.getIconRoute(parentTr); + parentTr.attr("data-icon", route); + file.css('background-image', "url(" + route + ")").css('display', 'none').css('display', 'inline'); + } + }, + + /** + * @param backend string with the name of the external storage backend + * of the tr matching the folder name + */ + getIconRoute: function(tr) { + var icon = OC.imagePath('core', 'filetypes/folder-external'); + var backend = null; + + if (tr instanceof $) { + backend = tr.attr('data-external-backend'); + } + + switch (backend) { + case 'smb': + icon = OC.imagePath('windows_network_drive', 'folder-windows'); + break; + case 'sharepoint': + icon = OC.imagePath('sharepoint', 'folder-sharepoint'); + break; + case 'amazons3': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'dav': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'dropbox': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'ftp': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'google': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'owncloud': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'sftp': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + case 'swift': + icon = OC.imagePath('core', 'filetypes/folder-external'); + break; + } + + return icon; + }, + + toggleLink: function(filename, active, action) { + var link; + if (filename instanceof $) { + link = filename; + } else { + link = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child a.name"); + } + if (active) { + link.off('click.connectivity'); + OCA.Files.App.fileList.fileActions.display(link.parent(), true, OCA.Files.App.fileList); + } else { + link.find('.fileactions, .nametext .action').remove(); // from files/js/fileactions (display) + link.off('click.connectivity'); + link.on('click.connectivity', function(e){ + if (action && $.isFunction(action)) { + action(filename); + } + e.preventDefault(); + return false; + }); + } + }, + + isCorrectViewAndRootFolder: function() { + // correct views = files & extstoragemounts + if (OCA.Files.App.getActiveView() === 'files' || OCA.Files.App.getActiveView() === 'extstoragemounts') { + return OCA.Files.App.getCurrentAppContainer().find('#dir').val() === '/'; + } + return false; + }, + + /* escape a selector expression for jQuery */ + jqSelEscape: function(expression) { + if(expression){ + return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); + } + return null; + }, + + /* Copied from http://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key */ + checkNested: function(cobj /*, level1, level2, ... levelN*/) { + var args = Array.prototype.slice.call(arguments), + obj = args.shift(); + + for (var i = 0; i < args.length; i++) { + if (!obj || !obj.hasOwnProperty(args[i])) { + return false; + } + obj = obj[args[i]]; + } + return true; + } +}; diff --git a/apps/files_external/l10n/es.js b/apps/files_external/l10n/es.js index 1d49d7b13b8..6d8bf0d3139 100644 --- a/apps/files_external/l10n/es.js +++ b/apps/files_external/l10n/es.js @@ -1,13 +1,23 @@ OC.L10N.register( "files_external", { + "Fetching request tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Fetching access tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Please provide a valid app key and secret." : "Por favor facilite una clave de app y una clave secreta válidas.", "Step 1 failed. Exception: %s" : "El paso 1 falló. Excepción: %s", "Step 2 failed. Exception: %s" : "El paso 2 falló. Excepción: %s", "External storage" : "Almacenamiento externo", "Storage with id \"%i\" not found" : "No se ha encontrado almacenamiento con id \"%i\"", + "Invalid backend or authentication mechanism class" : "Sistema o mecanismo de autentificación inválido", "Invalid mount point" : "Punto de montaje no válido", + "Objectstore forbidden" : "Objeto de almacenaje prohibido", "Invalid storage backend \"%s\"" : "Motor de almacenamiento no válido «%s»", - "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autenticación \"%s\"", + "Not permitted to use backend \"%s\"" : "No se permite usar el mecanismo \"%s\"", + "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autentificación \"%s\"", + "Unsatisfied backend parameters" : "Los parámetros del sistema no son válidos", + "Unsatisfied authentication mechanism parameters" : "Los parámetros del mecanismo de autentificación no son válidos", + "Insufficient data: %s" : "Datos insuficientes: %s", + "%s" : "%s", "Personal" : "Personal", "System" : "Sistema", "Grant access" : "Conceder acceso", @@ -84,7 +94,7 @@ OC.L10N.register( "Scope" : "Ámbito", "External Storage" : "Almacenamiento externo", "Folder name" : "Nombre de la carpeta", - "Authentication" : "Autenticación", + "Authentication" : "Autentificación", "Configuration" : "Configuración", "Available for" : "Disponible para", "Add storage" : "Añadir almacenamiento", diff --git a/apps/files_external/l10n/es.json b/apps/files_external/l10n/es.json index 1c60cd5fdea..bf0624e96db 100644 --- a/apps/files_external/l10n/es.json +++ b/apps/files_external/l10n/es.json @@ -1,11 +1,21 @@ { "translations": { + "Fetching request tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Fetching access tokens failed. Verify that your app key and secret are correct." : "Fallo al acceder a los tokens solicitados. Verfique que su clave de app y la clave secreta son correctas.", + "Please provide a valid app key and secret." : "Por favor facilite una clave de app y una clave secreta válidas.", "Step 1 failed. Exception: %s" : "El paso 1 falló. Excepción: %s", "Step 2 failed. Exception: %s" : "El paso 2 falló. Excepción: %s", "External storage" : "Almacenamiento externo", "Storage with id \"%i\" not found" : "No se ha encontrado almacenamiento con id \"%i\"", + "Invalid backend or authentication mechanism class" : "Sistema o mecanismo de autentificación inválido", "Invalid mount point" : "Punto de montaje no válido", + "Objectstore forbidden" : "Objeto de almacenaje prohibido", "Invalid storage backend \"%s\"" : "Motor de almacenamiento no válido «%s»", - "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autenticación \"%s\"", + "Not permitted to use backend \"%s\"" : "No se permite usar el mecanismo \"%s\"", + "Not permitted to use authentication mechanism \"%s\"" : "No está permitido usar el mecanismo de autentificación \"%s\"", + "Unsatisfied backend parameters" : "Los parámetros del sistema no son válidos", + "Unsatisfied authentication mechanism parameters" : "Los parámetros del mecanismo de autentificación no son válidos", + "Insufficient data: %s" : "Datos insuficientes: %s", + "%s" : "%s", "Personal" : "Personal", "System" : "Sistema", "Grant access" : "Conceder acceso", @@ -82,7 +92,7 @@ "Scope" : "Ámbito", "External Storage" : "Almacenamiento externo", "Folder name" : "Nombre de la carpeta", - "Authentication" : "Autenticación", + "Authentication" : "Autentificación", "Configuration" : "Configuración", "Available for" : "Disponible para", "Add storage" : "Añadir almacenamiento", diff --git a/apps/files_external/l10n/fr.js b/apps/files_external/l10n/fr.js index 8ff4fcdfdd9..8d5f7e911b7 100644 --- a/apps/files_external/l10n/fr.js +++ b/apps/files_external/l10n/fr.js @@ -17,6 +17,7 @@ OC.L10N.register( "Unsatisfied backend parameters" : "Paramètres manquants pour le service", "Unsatisfied authentication mechanism parameters" : "Paramètres manquants pour la méthode d'authentification", "Insufficient data: %s" : "Données insuffisantes : %s", + "%s" : "%s", "Personal" : "Personnel", "System" : "Système", "Grant access" : "Autoriser l'accès", diff --git a/apps/files_external/l10n/fr.json b/apps/files_external/l10n/fr.json index 9a610bd964b..cae66119a4f 100644 --- a/apps/files_external/l10n/fr.json +++ b/apps/files_external/l10n/fr.json @@ -15,6 +15,7 @@ "Unsatisfied backend parameters" : "Paramètres manquants pour le service", "Unsatisfied authentication mechanism parameters" : "Paramètres manquants pour la méthode d'authentification", "Insufficient data: %s" : "Données insuffisantes : %s", + "%s" : "%s", "Personal" : "Personnel", "System" : "Système", "Grant access" : "Autoriser l'accès", diff --git a/apps/files_external/l10n/lt_LT.js b/apps/files_external/l10n/lt_LT.js index dabdeb8bd32..3a871070f45 100644 --- a/apps/files_external/l10n/lt_LT.js +++ b/apps/files_external/l10n/lt_LT.js @@ -3,6 +3,7 @@ OC.L10N.register( { "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.", "Step 1 failed. Exception: %s" : "1 žingsnio klaida: %s", + "Step 2 failed. Exception: %s" : "2 žingsnio klaida: %s", "External storage" : "Išorinė saugykla", "Personal" : "Asmeniniai", "Grant access" : "Suteikti priėjimą", diff --git a/apps/files_external/l10n/lt_LT.json b/apps/files_external/l10n/lt_LT.json index 2b05c277ee6..854f753acaf 100644 --- a/apps/files_external/l10n/lt_LT.json +++ b/apps/files_external/l10n/lt_LT.json @@ -1,6 +1,7 @@ { "translations": { "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.", "Step 1 failed. Exception: %s" : "1 žingsnio klaida: %s", + "Step 2 failed. Exception: %s" : "2 žingsnio klaida: %s", "External storage" : "Išorinė saugykla", "Personal" : "Asmeniniai", "Grant access" : "Suteikti priėjimą", diff --git a/apps/files_external/l10n/nl.js b/apps/files_external/l10n/nl.js index 05d1a3f6de5..5051689216f 100644 --- a/apps/files_external/l10n/nl.js +++ b/apps/files_external/l10n/nl.js @@ -17,6 +17,7 @@ OC.L10N.register( "Unsatisfied backend parameters" : "Onvoldoende backend parameters", "Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters", "Insufficient data: %s" : "Onvoldoende gegevens: %s", + "%s" : "%s", "Personal" : "Persoonlijk", "System" : "Systeem", "Grant access" : "Sta toegang toe", diff --git a/apps/files_external/l10n/nl.json b/apps/files_external/l10n/nl.json index e30870e4ae1..d8a254bad1b 100644 --- a/apps/files_external/l10n/nl.json +++ b/apps/files_external/l10n/nl.json @@ -15,6 +15,7 @@ "Unsatisfied backend parameters" : "Onvoldoende backend parameters", "Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters", "Insufficient data: %s" : "Onvoldoende gegevens: %s", + "%s" : "%s", "Personal" : "Persoonlijk", "System" : "Systeem", "Grant access" : "Sta toegang toe", diff --git a/apps/files_external/l10n/th_TH.js b/apps/files_external/l10n/th_TH.js index 6c1efa5aacd..bb9c2dc909d 100644 --- a/apps/files_external/l10n/th_TH.js +++ b/apps/files_external/l10n/th_TH.js @@ -17,6 +17,7 @@ OC.L10N.register( "Unsatisfied backend parameters" : "พารามิเตอร์แบ็กเอนด์ไม่ได้รับอนุญาต", "Unsatisfied authentication mechanism parameters" : "การรับรองความถูกต้องไม่เพียงพอ", "Insufficient data: %s" : "ข้อมูลไม่เพียงพอ: %s", + "%s" : "%s", "Personal" : "ส่วนตัว", "System" : "ระบบ", "Grant access" : "อนุญาตให้เข้าถึงได้", diff --git a/apps/files_external/l10n/th_TH.json b/apps/files_external/l10n/th_TH.json index 3de48d733d3..f38d99ae88b 100644 --- a/apps/files_external/l10n/th_TH.json +++ b/apps/files_external/l10n/th_TH.json @@ -15,6 +15,7 @@ "Unsatisfied backend parameters" : "พารามิเตอร์แบ็กเอนด์ไม่ได้รับอนุญาต", "Unsatisfied authentication mechanism parameters" : "การรับรองความถูกต้องไม่เพียงพอ", "Insufficient data: %s" : "ข้อมูลไม่เพียงพอ: %s", + "%s" : "%s", "Personal" : "ส่วนตัว", "System" : "ระบบ", "Grant access" : "อนุญาตให้เข้าถึงได้", diff --git a/apps/files_external/lib/api.php b/apps/files_external/lib/api.php index af9b802e522..f0c9e568c9e 100644 --- a/apps/files_external/lib/api.php +++ b/apps/files_external/lib/api.php @@ -28,7 +28,7 @@ class Api { /** * Formats the given mount config to a mount entry. - * + * * @param string $mountPoint mount point name, relative to the data dir * @param array $mountConfig mount config to format * @@ -59,7 +59,9 @@ class Api { 'type' => 'dir', 'backend' => $mountConfig['backend'], 'scope' => ( $isSystemMount ? 'system' : 'personal' ), - 'permissions' => $permissions + 'permissions' => $permissions, + 'id' => $mountConfig['id'], + 'class' => $mountConfig['class'] ); return $entry; } diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index f58cd9849f2..a94840ead59 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -33,7 +33,6 @@ use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\NativeServer; use Icewind\SMB\Server; -use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Filesystem; diff --git a/apps/files_external/lib/storageconfig.php b/apps/files_external/lib/storageconfig.php index 97e0386be73..49a40a9a5d7 100644 --- a/apps/files_external/lib/storageconfig.php +++ b/apps/files_external/lib/storageconfig.php @@ -163,7 +163,7 @@ class StorageConfig implements \JsonSerializable { } /** - * @param Backend + * @param Backend $backend */ public function setBackend(Backend $backend) { $this->backend= $backend; @@ -177,7 +177,7 @@ class StorageConfig implements \JsonSerializable { } /** - * @param AuthMechanism + * @param AuthMechanism $authMechanism */ public function setAuthMechanism(AuthMechanism $authMechanism) { $this->authMechanism = $authMechanism; diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index e946e7feb77..a64a02a4ed9 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -354,9 +354,18 @@ class Swift extends \OC\Files\Storage\Common { } $tmpFile = \OCP\Files::tmpFile($ext); \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - if ($this->file_exists($path)) { + // Fetch existing file if required + if ($mode[0] !== 'w' && $this->file_exists($path)) { + if ($mode[0] === 'x') { + // File cannot already exist + return false; + } $source = $this->fopen($path, 'r'); file_put_contents($tmpFile, $source); + // Seek to end if required + if ($mode[0] === 'a') { + fseek($tmpFile, 0, SEEK_END); + } } self::$tmpFiles[$tmpFile] = $path; diff --git a/apps/files_external/list.php b/apps/files_external/list.php index b98db79de89..4bbe5588c26 100644 --- a/apps/files_external/list.php +++ b/apps/files_external/list.php @@ -23,6 +23,11 @@ OCP\User::checkLoggedIn(); $tmpl = new OCP\Template('files_external', 'list', ''); +/* Load Status Manager */ +\OCP\Util::addStyle('files_external', 'external'); +\OCP\Util::addScript('files_external', 'statusmanager'); +\OCP\Util::addScript('files_external', 'rollingqueue'); + OCP\Util::addScript('files_external', 'app'); OCP\Util::addScript('files_external', 'mountsfilelist'); diff --git a/apps/files_external/tests/amazons3migration.php b/apps/files_external/tests/amazons3migration.php index 33fb6119a92..cc47107c7fe 100644 --- a/apps/files_external/tests/amazons3migration.php +++ b/apps/files_external/tests/amazons3migration.php @@ -130,6 +130,9 @@ class AmazonS3Migration extends \Test\TestCase { return $storages; } + /** + * @param string $id + */ public function deleteStorage($id) { $stmt = \OC::$server->getDatabaseConnection()->prepare( 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?' diff --git a/apps/files_external/tests/controller/storagescontrollertest.php b/apps/files_external/tests/controller/storagescontrollertest.php index 8a7acf81009..747bcd46e17 100644 --- a/apps/files_external/tests/controller/storagescontrollertest.php +++ b/apps/files_external/tests/controller/storagescontrollertest.php @@ -48,6 +48,9 @@ abstract class StoragesControllerTest extends \Test\TestCase { \OC_Mount_Config::$skipTest = false; } + /** + * @return \OCA\Files_External\Lib\Backend\Backend + */ protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') { $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') ->disableOriginalConstructor() @@ -59,6 +62,9 @@ abstract class StoragesControllerTest extends \Test\TestCase { return $backend; } + /** + * @return \OCA\Files_External\Lib\Auth\AuthMechanism + */ protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') { $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism') ->disableOriginalConstructor() diff --git a/apps/files_external/tests/service/backendservicetest.php b/apps/files_external/tests/service/backendservicetest.php index 5097b479a5f..e9cb0e2c368 100644 --- a/apps/files_external/tests/service/backendservicetest.php +++ b/apps/files_external/tests/service/backendservicetest.php @@ -35,6 +35,11 @@ class BackendServiceTest extends \Test\TestCase { $this->l10n = $this->getMock('\OCP\IL10N'); } + /** + * @param string $class + * + * @return \OCA\Files_External\Lib\Backend\Backend + */ protected function getBackendMock($class) { $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend') ->disableOriginalConstructor() |