summaryrefslogtreecommitdiffstats
path: root/apps/files_external
diff options
context:
space:
mode:
authormbi <knox@users.noreply.github.com>2015-12-08 21:02:52 +0100
committermbi <knox@users.noreply.github.com>2015-12-08 21:02:52 +0100
commit508c46a112d3d53b4b0668efcbe1403eb2e143b8 (patch)
tree29ef86459abae1dcaadf75203851ab9b39ec43bd /apps/files_external
parent27f420e0a797f8a56b5e83e8dd8e19df289c766b (diff)
parent13993c4a6db83c0a637fc7c20da0470acae47208 (diff)
downloadnextcloud-server-508c46a112d3d53b4b0668efcbe1403eb2e143b8.tar.gz
nextcloud-server-508c46a112d3d53b4b0668efcbe1403eb2e143b8.zip
Merge branch 'master' into master
Diffstat (limited to 'apps/files_external')
-rw-r--r--apps/files_external/command/listcommand.php1
-rw-r--r--apps/files_external/css/external.css8
-rw-r--r--apps/files_external/js/app.js37
-rw-r--r--apps/files_external/js/rollingqueue.js137
-rw-r--r--apps/files_external/js/statusmanager.js539
-rw-r--r--apps/files_external/l10n/es.js14
-rw-r--r--apps/files_external/l10n/es.json14
-rw-r--r--apps/files_external/l10n/fr.js1
-rw-r--r--apps/files_external/l10n/fr.json1
-rw-r--r--apps/files_external/l10n/lt_LT.js1
-rw-r--r--apps/files_external/l10n/lt_LT.json1
-rw-r--r--apps/files_external/l10n/nl.js1
-rw-r--r--apps/files_external/l10n/nl.json1
-rw-r--r--apps/files_external/l10n/th_TH.js1
-rw-r--r--apps/files_external/l10n/th_TH.json1
-rw-r--r--apps/files_external/lib/api.php6
-rw-r--r--apps/files_external/lib/smb.php1
-rw-r--r--apps/files_external/lib/storageconfig.php4
-rw-r--r--apps/files_external/lib/swift.php11
-rw-r--r--apps/files_external/list.php5
-rw-r--r--apps/files_external/tests/amazons3migration.php3
-rw-r--r--apps/files_external/tests/controller/storagescontrollertest.php6
-rw-r--r--apps/files_external/tests/service/backendservicetest.php5
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()