From 3c53a0da279ec167c0a8e64dc8c92bc700daf770 Mon Sep 17 00:00:00 2001 From: Renaud Fortier Date: Tue, 11 Aug 2015 11:55:38 -0400 Subject: [PATCH 01/69] if define, check the userfilter if the user is still allowed --- apps/user_ldap/lib/access.php | 2 +- apps/user_ldap/user_ldap.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index a2eb834b49..f32d3feacd 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -175,7 +175,7 @@ class Access extends LDAPUtility implements user\IUserTools { //in case an error occurs , e.g. object does not exist return false; } - if (empty($attr)) { + if (empty($attr) && ($filter === 'objectclass=*' || $this->ldap->countEntries($cr, $rr) === 1)) { \OCP\Util::writeLog('user_ldap', 'readAttribute: '.$dn.' found', \OCP\Util::DEBUG); return array(); } diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index a2f4b4ee9e..204995198b 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -176,8 +176,12 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn } $dn = $user->getDN(); + $userFilter = 'objectclass=*'; + if ($this->access->connection->ldapUserFilter !== '') { + $userFilter = $this->access->connection->ldapUserFilter; + } //check if user really still exists by reading its entry - if(!is_array($this->access->readAttribute($dn, ''))) { + if(!is_array($this->access->readAttribute($dn, '', $userFilter))) { $lcr = $this->access->connection->getConnectionResource(); if(is_null($lcr)) { throw new \Exception('No LDAP Connection to server ' . $this->access->connection->ldapHost); From 394d3eb0cd7448be3c7efc42c4012ecfdf99e654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Thu, 12 Nov 2015 13:40:28 +0100 Subject: [PATCH 02/69] First working approach to show mount status --- apps/files_external/js/app.js | 132 +++-- apps/files_external/js/rollingqueue.js | 137 ++++++ apps/files_external/js/statusmanager.js | 486 +++++++++++++++++++ apps/files_external/js/statusmanagerutils.js | 158 ++++++ apps/files_external/lib/api.php | 6 +- apps/files_external/list.php | 5 + 6 files changed, 874 insertions(+), 50 deletions(-) create mode 100644 apps/files_external/js/rollingqueue.js create mode 100644 apps/files_external/js/statusmanager.js create mode 100644 apps/files_external/js/statusmanagerutils.js diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js index bf853f926d..411d5fc343 100644 --- a/apps/files_external/js/app.js +++ b/apps/files_external/js/app.js @@ -9,69 +9,105 @@ */ if (!OCA.External) { - /** - * @namespace - */ - OCA.External = {}; + /** + * @namespace + */ + OCA.External = {}; } /** * @namespace */ OCA.External.App = { - fileList: null, + fileList: null, - initList: function($el) { - if (this.fileList) { - return this.fileList; - } + initList: function($el) { + if (this.fileList) { + return this.fileList; + } - this.fileList = new OCA.External.FileList( - $el, - { - scrollContainer: $('#app-content'), - fileActions: this._createFileActions() - } - ); + this.fileList = new OCA.External.FileList( + $el, + { + scrollContainer: $('#app-content'), + fileActions: this._createFileActions() + } + ); - this._extendFileList(this.fileList); - this.fileList.appName = t('files_external', 'External storage'); - return this.fileList; - }, + this._extendFileList(this.fileList); + this.fileList.appName = t('files_external', 'External storage'); + return this.fileList; + }, - removeList: function() { - if (this.fileList) { - this.fileList.$fileList.empty(); - } - }, + removeList: function() { + if (this.fileList) { + this.fileList.$fileList.empty(); + } + }, - _createFileActions: function() { - // inherit file actions from the files app - var fileActions = new OCA.Files.FileActions(); - fileActions.registerDefaultActions(); + _createFileActions: function() { + // inherit file actions from the files app + var fileActions = new OCA.Files.FileActions(); + fileActions.registerDefaultActions(); - // when the user clicks on a folder, redirect to the corresponding - // folder in the files app instead of opening it directly - fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { - OCA.Files.App.setActiveView('files', {silent: true}); - OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); - }); - fileActions.setDefault('dir', 'Open'); - return fileActions; - }, + // when the user clicks on a folder, redirect to the corresponding + // folder in the files app instead of opening it directly + fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { + OCA.Files.App.setActiveView('files', {silent: true}); + OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); + }); + fileActions.setDefault('dir', 'Open'); + return fileActions; + }, - _extendFileList: function(fileList) { - // remove size column from summary - fileList.fileSummary.$el.find('.filesize').remove(); - } + _extendFileList: function(fileList) { + // remove size column from summary + fileList.fileSummary.$el.find('.filesize').remove(); + } }; $(document).ready(function() { - $('#app-content-extstoragemounts').on('show', function(e) { - OCA.External.App.initList($(e.target)); - }); - $('#app-content-extstoragemounts').on('hide', function() { - OCA.External.App.removeList(); - }); + $('#app-content-extstoragemounts').on('show', function(e) { + OCA.External.App.initList($(e.target)); + }); + $('#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]; + // make sure we have a mount point list + OCA.External.StatusManager.getMountPointList(function() { + OCA.External.StatusManager.recheckConnectivityForMount([mount_point], true, 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)) { + // we don't have the data cached, so we'll get it one by one + OCA.External.StatusManager.launchFullConnectivityCheckOneByOne(); + } else { + // make sure we have a mount point list + OCA.External.StatusManager.getMountPointList(function(){ + var fileNames = []; + $.each(e.$files, function(key, value){ + fileNames.push(value.attr('data-file')); + }); + OCA.External.StatusManager.recheckConnectivityForMount(fileNames, false, 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 0000000000..7e6570a2a7 --- /dev/null +++ b/apps/files_external/js/rollingqueue.js @@ -0,0 +1,137 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos + * @author Jesus Macias Portela + * @copyright (C) 2014 ownCloud, Inc. + * + * This code is covered by the ownCloud Commercial License. + * + * You should have received a copy of the ownCloud Commercial License + * along with this program. If not, see . + * + */ + +(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 0000000000..f3e0832ad6 --- /dev/null +++ b/apps/files_external/js/statusmanager.js @@ -0,0 +1,486 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos + * @author Jesus Macias Portela + * @copyright (C) 2014 ownCloud, Inc. + * + * This code is covered by the ownCloud Commercial License. + * + * You should have received a copy of the ownCloud Commercial License + * along with this program. If not, see . + * + */ + +if (!OCA.External) { + OCA.External = {}; +} + +OCA.External.StatusManager = { + mountStatus : null, + mountPointList : null, + + getMountStatus : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return; + } + + if (self.mountStatus) { + afterCallback(self.mountStatus); + } else { + self.isGetMountStatusRunning = true; + $.ajax({ + type : 'GET', + url : OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), + success : function(response) { + self.mountStatus = response.data; + afterCallback(self.mountStatus); + }, + error : function(jqxhr, state, error) { + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the external mounts: {type}', {type : error})); + if (!self.mountStatus) { + self.mountStatus = {}; + } + $.each(self.mountPointList, function(name, value){ + if (!self.mountStatus[value.mount_point]) { + self.mountStatus[value.mount_point] = {}; + } + self.mountStatus[value.mount_point].status = 'ok'; + OCA.External.StatusManager.Utils.restoreFolder(value); + OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); + }); + }, + complete : function() { + self.isGetMountStatusRunning = false; + } + }); + } + }, + + getMountPointListElement : function(mount_point) { + var element; + $.each(this.mountPointList, function(key, value){ + if (value.mount_point === mount_point) { + element = value; + return false; + } + }); + return element; + }, + + 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.mount_point, 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/globalstorages/' + mountData.id, + success : function(response) { + if (response && response.status === 0) { + self.mountStatus[mountData.mount_point] = response; + } else { + if (response && response.data) { + // failure response with error message + self.mountStatus[mountData.mount_point] = {code: 'GE', + status: 'fail', + error: response.data.message}; + } else { + self.mountStatus[mountData.mount_point] = {code: 'GE', + status: 'fail', + error: t('files_external', 'Empty response from the server')}; + } + } + afterCallback(mountData.mount_point, 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] = {code: 'GE', + status: 'fail', + location: mountData.location, + error: message}; + afterCallback(mountData.mount_point, self.mountStatus[mountData.mount_point]); + } + }); + } + return defObj; + }, + + 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.backend = mount.backend; + element.class = mount.class; + + self.mountPointList.push(element); + }); + afterCallback(self.mountPointList); + }, + error : function(jqxhr, state, error) { + self.mountPointList = []; + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of external mount points: {type}', {type : error})); + }, + complete : function() { + self.isGetMountPointListRunning = false; + } + }); + } + }, + + setMountPointAsGood : function(mountPoint) { + OCA.External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + delete this.mountStatus[mountPoint].code; + delete this.mountStatus[mountPoint].error; + this.mountStatus[mountPoint].status = 'ok'; + }, + + manageMountPointError : function(name) { + var self = this; + this.getMountStatus($.proxy(function(allMountStatus) { + if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 'fail') { + var mountData = allMountStatus[name]; + if ((mountData.code === 'CNP' || mountData.code === 'AD') && mountData.type === 'global' && mountData.location === 1) { + // admin set up mount point and let users use their credentials. Credentials + // aren't stored yet or are wrong (handled by the same ajax request) + this.showCredentialsDialog(name, mountData, null, 'saveCredential.php', + null, this.setMountPointAsGood, this); + + } else if (mountData.code === 'AD' && mountData.type === 'personal' && mountData.location === 0) { + // personal set up mount point and let users use their credentials. + // Credentials are wrong so they need to be updated + // the "type 0" is a required parameter in the target ajax call + this.showCredentialsDialog(name, mountData, {type: 0}, 'updatePersonalMountPoint.php', + null, this.setMountPointAsGood, this); + + } else if (mountData.code === 'AD' && mountData.type === 'personal' && mountData.location === 2) { + this.showCredentialsDialog(name, mountData, null, 'saveGlobalCredentials.php', + t('files_external', 'WARNING: This mount point uses global credentials.\n\nChanging the credentials might affect to other mount points'), + function() { + this.recheckConnectivityForMount([name], true, true); + }, + this); + + } else if (mountData.code === 'AD' && mountData.type === 'global' && (mountData.location === 0 || mountData.location === 2)) { + OC.dialogs.message(t('files_external', 'The credentials for this mount point are wrong. This mount point was set by the administrator, please contact him / her to provide suitable credentials'), t('files_external', 'Credentials error')); + + } else if ((mountData.code === 'CE' || mountData.code === 'IH')) { + OC.dialogs.message(mountData.error, t('files_external', 'Connectivity error')); + + } else if ((mountData.code === 'GE' && mountData.location === 3)) { + OC.dialogs.message(mountData.error, t('files_external', 'Login credentials error')); + + } else { + OC.dialogs.message(mountData.error, t('files_external', 'Unknown error')); + } + } + }, this)); + }, + + showCredentialsDialog : function(mountPoint, mountData, extraParams, target, extraInfo, successCallback, callbackCtx) { + var self = this; + var baseParams = {target: target, + m: mountData.mid, + name: mountPoint, + url: mountData.url, + share: mountData.share, + extra: extraInfo}; + var sendParams = ($.isPlainObject(extraParams)) ? $.extend(baseParams, extraParams) : baseParams; + $.get(OC.filePath('files_external', 'ajax', 'dialog.php'), + sendParams, + function(data) { + if (typeof data.status !== 'undefined' && data.status === 'success') { + $('body').append(data.form); + var wnd_send_button_click_func = function () { + $('.oc-dialog-close').hide(); + var dataToSend = {}; + $('#wnd_div_form').find('input').each(function(){ + var thisElement = $(this); + if (thisElement.is('[type="checkbox"]')) { + dataToSend[thisElement.attr('name')] = thisElement.prop('checked'); + } else { + dataToSend[thisElement.attr('name')] = thisElement.val(); + } + }); + $.ajax({type: 'POST', + url: $('#wnd_div_form form').attr('action'), + data: dataToSend, + success: function (data) { + var dialog = $('#wnd_div_form'); + if (typeof(data.status) !== 'undefined' && data.status === 'success') { + dialog.ocdialog('close'); + + if (successCallback && $.isFunction(successCallback)) { + successCallback.call(callbackCtx || this, mountPoint); + } + } else { + $('.oc-dialog-close').show(); + dialog.ocdialog('option', 'title', 'Windows Network Drive credentials validation failed'); + var title = $('.oc-dialog-title'); + var color = title.css('background-color'); + title.css('background-color', 'red'); + title.animate({backgroundColor: color}, 5000); + } + }, + error: function (){ + $('.oc-dialog-close').show(); + }}); + }; + + var buttonList = [{text : t('files_external', 'Save'), + click : wnd_send_button_click_func, + closeOnEscape : true}]; + + var ocdialogParams = {modal: true, buttons : buttonList, + closeOnExcape : true}; + $('#wnd_div_form').ocdialog(ocdialogParams) + .bind('ocdialogclose', function(){ + $('#wnd_div_form').ocdialog('destroy').remove(); + }); + } + }); + }, + + processMountStatus : function(mounts) { + var hasErrors = false; + var self = this; + $.each(mounts, function(mountPoint, values){ + hasErrors = !self.processMountStatusIndividual(mountPoint, values) || hasErrors; + }); + + if (!this.notificationHasShown) { + this.notificationHasShown = true; + if (hasErrors) { + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured Windows network drive(s) are not connected. Please click on the red row(s) for more information')); + } + } + }, + + processMountStatusIndividual : function(mountPoint, mountData) { + if (mountData.status === 'fail') { + var errorImage = 'folder-windows'; + if (mountData.code === 'AD' || mountData.code === 'CNP') { + errorImage += '-credentials'; + } else if (mountData.code === 'IH' || mountData.code === 'CE') { + errorImage += '-timeout'; + } else { + errorImage += '-error'; + } + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), OC.imagePath('files_external', errorImage)); + } + 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; + } + }, + + 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) + '\"]'); + 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.find('td:first-child div.thumbnail'), "url(" + OC.imagePath('windows_network_drive', 'folder-windows') + ")"); + // Save default view + OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); + // Disable row until check status + elementList.css('background-color', '#CCC'); + OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); + } + } + }, + + launchFullConnectivityCheck : function() { + var self = this; + this.getMountPointList(function(list){ + // check if we have a list first + if (list === undefined && !self.emptyWarningShown) { + self.emptyWarningShown = true; + OCA.External.StatusManager.Utils.showAlert(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); + self.getMountStatus(function(mountStatus){ + if (mountStatus === undefined && !self.notificationNoProcessListDone) { + self.notificationNoProcessListDone = true; + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the Windows network drive mounts: empty response from the server')); + if (!self.mountStatus) { + self.mountStatus = {}; + } + $.each(list, function(name, value){ + if (!self.mountStatus[value.mount_point]) { + self.mountStatus[value.mount_point] = {}; + } + self.mountStatus[value.mount_point].status = 'ok'; + OCA.External.StatusManager.Utils.restoreFolder(value.mount_point); + OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); + }); + return; + } + self.processMountStatus(mountStatus); + }); + } + }); + }, + + launchFullConnectivityCheckOneByOne : function() { + var self = this; + this.getMountPointList(function(list){ + // check if we have a list first + if (list === undefined && !self.emptyWarningShown) { + self.emptyWarningShown = true; + OCA.External.StatusManager.Utils.showAlert(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 === 'fail') { + self.notificationHasShown = true; + showNotification = true; + } + }); + if (showNotification) { + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured Windows network drive(s) are not connected. Please click on the red row(s) for more information')); + } + } + }); + rolQueue.runQueue(); + } + }); + }, + + 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(); + }, + + recheckConnectivityForMount : function(mountListNames, recheck, checkGlobal) { + 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) { + if (mountData.type === 'personal' && mountData.location === 2) { + recheckPersonalGlobal = true; + } + if (mountData.type === 'admin' && mountData.location === 2) { + recheckAdminGlobal = true; + } + mountListData.push(mountData); + } + }); + + // we might need to check more mounts if a personal mount with global credentials is affected + if (checkGlobal && (recheckPersonalGlobal || recheckAdminGlobal)) { + $.each(self.mountPointList, function(key, value){ + if (((recheckPersonalGlobal && value.type === 'personal') || (recheckAdminGlobal && value.type === 'admin')) && + value.location === 2 && + $.inArray(value, mountListData) === -1) { + // personal mount using global credentials, not present in the mountListData + mountListData.push(value); + } + }); + } + + // 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); + } +}; diff --git a/apps/files_external/js/statusmanagerutils.js b/apps/files_external/js/statusmanagerutils.js new file mode 100644 index 0000000000..e8e8265f9e --- /dev/null +++ b/apps/files_external/js/statusmanagerutils.js @@ -0,0 +1,158 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos + * @author Jesus Macias Portela + * @copyright (C) 2014 ownCloud, Inc. + * + * This code is covered by the ownCloud Commercial License. + * + * You should have received a copy of the ownCloud Commercial License + * along with this program. If not, see . + * + */ + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager.Utils = { + + showAlert: function(message){ + if (!OC.Notification.isHidden()) { + OC.Notification.hide(); + OC.Notification.showHtml(message); + } else { + OC.Notification.showHtml(message); + } + setTimeout(function() { + if ($("#notification").text() === message) { + OC.Notification.hide(); + } + }, 10000); + }, + + showIconError: function(folder, clickAction, errorImageUrl) { + var bgColor = '#F2DEDE'; + var imageUrl = "url(" + errorImageUrl + ")"; + var trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + this.changeFolderIcon(folder, imageUrl); + this.toggleLink(folder, false, clickAction); + trFolder.css('background-color', bgColor); + }, + + /** + * @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=\"' + this.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 { + trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + } + trFolder.css('background-color', ''); + 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, route) { + var file; + if (filename instanceof $) { + file = filename; + } else { + file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail"); + } + file.css('background-image', route).hide().show(0); + // previous line is required in Chrome to force the css update so the image url + // is stored correctly later + //file.css('background-image', route).height(); + }, + + 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) { + return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); + }, + + /* 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/lib/api.php b/apps/files_external/lib/api.php index af9b802e52..f0c9e568c9 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/list.php b/apps/files_external/list.php index b98db79de8..831107c9c3 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::addScript('files_external', 'statusmanager'); +\OCP\Util::addScript('files_external', 'statusmanagerutils'); +\OCP\Util::addScript('files_external', 'rollingqueue'); + OCP\Util::addScript('files_external', 'app'); OCP\Util::addScript('files_external', 'mountsfilelist'); From a413f8eccccfdd0bdc9bf970801568a8f27743d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Fri, 13 Nov 2015 12:57:33 +0100 Subject: [PATCH 03/69] Add icon management capabilities (error icon) --- apps/files_external/js/statusmanager.js | 33 ++++++++++---------- apps/files_external/js/statusmanagerutils.js | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index f3e0832ad6..266a11b0de 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -88,14 +88,14 @@ OCA.External.StatusManager = { if (response && response.status === 0) { self.mountStatus[mountData.mount_point] = response; } else { - if (response && response.data) { + if (response && response.statusMessage) { // failure response with error message self.mountStatus[mountData.mount_point] = {code: 'GE', - status: 'fail', - error: response.data.message}; + status: 1, + error: response.statusMessage}; } else { self.mountStatus[mountData.mount_point] = {code: 'GE', - status: 'fail', + status: 1, error: t('files_external', 'Empty response from the server')}; } } @@ -110,7 +110,7 @@ OCA.External.StatusManager = { 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] = {code: 'GE', - status: 'fail', + status: 1, location: mountData.location, error: message}; afterCallback(mountData.mount_point, self.mountStatus[mountData.mount_point]); @@ -171,7 +171,7 @@ OCA.External.StatusManager = { manageMountPointError : function(name) { var self = this; this.getMountStatus($.proxy(function(allMountStatus) { - if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 'fail') { + if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 1) { var mountData = allMountStatus[name]; if ((mountData.code === 'CNP' || mountData.code === 'AD') && mountData.type === 'global' && mountData.location === 1) { // admin set up mount point and let users use their credentials. Credentials @@ -204,7 +204,7 @@ OCA.External.StatusManager = { OC.dialogs.message(mountData.error, t('files_external', 'Login credentials error')); } else { - OC.dialogs.message(mountData.error, t('files_external', 'Unknown error')); + OC.dialogs.message(mountData.error, t('files_external', 'External mount error')); } } }, this)); @@ -222,7 +222,7 @@ OCA.External.StatusManager = { $.get(OC.filePath('files_external', 'ajax', 'dialog.php'), sendParams, function(data) { - if (typeof data.status !== 'undefined' && data.status === 'success') { + if (typeof data.status !== 'undefined' && data.status === 0) { $('body').append(data.form); var wnd_send_button_click_func = function () { $('.oc-dialog-close').hide(); @@ -240,7 +240,7 @@ OCA.External.StatusManager = { data: dataToSend, success: function (data) { var dialog = $('#wnd_div_form'); - if (typeof(data.status) !== 'undefined' && data.status === 'success') { + if (typeof(data.status) !== 'undefined' && data.status === 0) { dialog.ocdialog('close'); if (successCallback && $.isFunction(successCallback)) { @@ -284,23 +284,24 @@ OCA.External.StatusManager = { if (!this.notificationHasShown) { this.notificationHasShown = true; if (hasErrors) { - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured Windows network drive(s) are not connected. Please click on the red row(s) for more information')); + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured external mount points are not connected. Please click on the red row(s) for more information')); } } }, processMountStatusIndividual : function(mountPoint, mountData) { - if (mountData.status === 'fail') { - var errorImage = 'folder-windows'; + if (mountData.status === 1) { + var errorImage = 'folder-windows-error'; + /* if (mountData.code === 'AD' || mountData.code === 'CNP') { errorImage += '-credentials'; } else if (mountData.code === 'IH' || mountData.code === 'CE') { errorImage += '-timeout'; } else { errorImage += '-error'; - } + }*/ if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { - OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), OC.imagePath('files_external', errorImage)); + OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), OC.imagePath('core', 'filetypes/' + errorImage)); } return false; } else { @@ -398,13 +399,13 @@ OCA.External.StatusManager = { if (!self.notificationHasShown) { var showNotification = false; $.each(self.mountStatus, function(key, value){ - if (value.status === 'fail') { + if (value.status === 1) { self.notificationHasShown = true; showNotification = true; } }); if (showNotification) { - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured Windows network drive(s) are not connected. Please click on the red row(s) for more information')); + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured external mount points are not connected. Please click on the red row(s) for more information')); } } }); diff --git a/apps/files_external/js/statusmanagerutils.js b/apps/files_external/js/statusmanagerutils.js index e8e8265f9e..0ee6bc2a17 100644 --- a/apps/files_external/js/statusmanagerutils.js +++ b/apps/files_external/js/statusmanagerutils.js @@ -100,7 +100,7 @@ OCA.External.StatusManager.Utils = { } else { file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail"); } - file.css('background-image', route).hide().show(0); + // file.css('background-image', route).hide().show(0); // previous line is required in Chrome to force the css update so the image url // is stored correctly later //file.css('background-image', route).height(); From fab13b7ca55c02b15c237bd57d5a9de23f0d014e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Wed, 18 Nov 2015 12:12:32 +0100 Subject: [PATCH 04/69] Add method to show custom icon and icon-error for each storage backend --- apps/files_external/js/statusmanager.js | 252 +++++++++++++++---- apps/files_external/js/statusmanagerutils.js | 158 ------------ apps/files_external/list.php | 1 - 3 files changed, 200 insertions(+), 211 deletions(-) delete mode 100644 apps/files_external/js/statusmanagerutils.js diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 266a11b0de..244f5b6bd5 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -16,6 +16,10 @@ if (!OCA.External) { OCA.External = {}; } +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + OCA.External.StatusManager = { mountStatus : null, mountPointList : null, @@ -90,16 +94,16 @@ OCA.External.StatusManager = { } else { if (response && response.statusMessage) { // failure response with error message - self.mountStatus[mountData.mount_point] = {code: 'GE', + self.mountStatus[mountData.mount_point] = { type: mountData.type, status: 1, error: response.statusMessage}; } else { - self.mountStatus[mountData.mount_point] = {code: 'GE', + self.mountStatus[mountData.mount_point] = { type: mountData.type, status: 1, error: t('files_external', 'Empty response from the server')}; } } - afterCallback(mountData.mount_point, self.mountStatus[mountData.mount_point]); + afterCallback(mountData, self.mountStatus[mountData.mount_point]); }, error : function(jqxhr, state, error) { var message; @@ -109,7 +113,7 @@ OCA.External.StatusManager = { } 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] = {code: 'GE', + self.mountStatus[mountData.mount_point] = { type: mountData.type, status: 1, location: mountData.location, error: message}; @@ -142,8 +146,8 @@ OCA.External.StatusManager = { element.type = mount.scope; element.location = ""; element.id = mount.id; - element.backend = mount.backend; - element.class = mount.class; + element.backendText = mount.backend; + element.backend = mount.class; self.mountPointList.push(element); }); @@ -173,38 +177,18 @@ OCA.External.StatusManager = { this.getMountStatus($.proxy(function(allMountStatus) { if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 1) { var mountData = allMountStatus[name]; - if ((mountData.code === 'CNP' || mountData.code === 'AD') && mountData.type === 'global' && mountData.location === 1) { - // admin set up mount point and let users use their credentials. Credentials - // aren't stored yet or are wrong (handled by the same ajax request) - this.showCredentialsDialog(name, mountData, null, 'saveCredential.php', - null, this.setMountPointAsGood, this); - - } else if (mountData.code === 'AD' && mountData.type === 'personal' && mountData.location === 0) { - // personal set up mount point and let users use their credentials. - // Credentials are wrong so they need to be updated - // the "type 0" is a required parameter in the target ajax call - this.showCredentialsDialog(name, mountData, {type: 0}, 'updatePersonalMountPoint.php', - null, this.setMountPointAsGood, this); - - } else if (mountData.code === 'AD' && mountData.type === 'personal' && mountData.location === 2) { - this.showCredentialsDialog(name, mountData, null, 'saveGlobalCredentials.php', - t('files_external', 'WARNING: This mount point uses global credentials.\n\nChanging the credentials might affect to other mount points'), - function() { - this.recheckConnectivityForMount([name], true, true); - }, - this); - - } else if (mountData.code === 'AD' && mountData.type === 'global' && (mountData.location === 0 || mountData.location === 2)) { - OC.dialogs.message(t('files_external', 'The credentials for this mount point are wrong. This mount point was set by the administrator, please contact him / her to provide suitable credentials'), t('files_external', 'Credentials error')); - - } else if ((mountData.code === 'CE' || mountData.code === 'IH')) { - OC.dialogs.message(mountData.error, t('files_external', 'Connectivity error')); - - } else if ((mountData.code === 'GE' && mountData.location === 3)) { - OC.dialogs.message(mountData.error, t('files_external', 'Login credentials error')); - + 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.message(mountData.error, t('files_external', 'External mount error')); + 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)); @@ -289,19 +273,15 @@ OCA.External.StatusManager = { } }, - processMountStatusIndividual : function(mountPoint, mountData) { - if (mountData.status === 1) { - var errorImage = 'folder-windows-error'; - /* - if (mountData.code === 'AD' || mountData.code === 'CNP') { - errorImage += '-credentials'; - } else if (mountData.code === 'IH' || mountData.code === 'CE') { - errorImage += '-timeout'; - } else { - errorImage += '-error'; - }*/ + processMountStatusIndividual : function(mountData, mountStatus) { + var mountPoint = mountData.mount_point; + if (mountStatus.status === 1) { + var trElement = $('#fileList tr[data-file=\"' + 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), OC.imagePath('core', 'filetypes/' + errorImage)); + OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), route); } return false; } else { @@ -317,6 +297,7 @@ OCA.External.StatusManager = { var elementList = null; $.each(mountList, function(name, value){ var trElement = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point) + '\"]'); + trElement.attr('data-external-backend', value.backend); if (elementList) { elementList = elementList.add(trElement); } else { @@ -327,7 +308,7 @@ OCA.External.StatusManager = { if (elementList instanceof $) { if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { // Put their custom icon - // OCA.External.StatusManager.Utils.changeFolderIcon(elementList.find('td:first-child div.thumbnail'), "url(" + OC.imagePath('windows_network_drive', 'folder-windows') + ")"); + OCA.External.StatusManager.Utils.changeFolderIcon(elementList); // Save default view OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); // Disable row until check status @@ -343,7 +324,7 @@ OCA.External.StatusManager = { // check if we have a list first if (list === undefined && !self.emptyWarningShown) { self.emptyWarningShown = true; - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of Windows network drive mount points: empty response from the server')); + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of external mount points: empty response from the server')); return; } if (list && list.length > 0) { @@ -351,7 +332,7 @@ OCA.External.StatusManager = { self.getMountStatus(function(mountStatus){ if (mountStatus === undefined && !self.notificationNoProcessListDone) { self.notificationNoProcessListDone = true; - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the Windows network drive mounts: empty response from the server')); + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the external mounts: empty response from the server')); if (!self.mountStatus) { self.mountStatus = {}; } @@ -485,3 +466,170 @@ OCA.External.StatusManager = { self.launchPartialConnectivityCheck(mountListData, recheck); } }; + +OCA.External.StatusManager.Utils = { + + showAlert: function(message){ + if (!OC.Notification.isHidden()) { + OC.Notification.hide(); + OC.Notification.showHtml(message); + } else { + OC.Notification.showHtml(message); + } + setTimeout(function() { + if ($("#notification").text() === message) { + OC.Notification.hide(); + } + }, 10000); + }, + + showIconError: function(folder, clickAction, errorImageUrl) { + var bgColor = '#F2DEDE'; + var imageUrl = "url(" + errorImageUrl + ")"; + var trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + this.changeFolderIcon(folder, imageUrl); + this.toggleLink(folder, false, clickAction); + trFolder.css('background-color', bgColor); + }, + + /** + * @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=\"' + this.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 { + trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + } + trFolder.css('background-color', ''); + 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; + } + + 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) { + return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); + }, + + /* 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/js/statusmanagerutils.js b/apps/files_external/js/statusmanagerutils.js deleted file mode 100644 index 0ee6bc2a17..0000000000 --- a/apps/files_external/js/statusmanagerutils.js +++ /dev/null @@ -1,158 +0,0 @@ -/** - * ownCloud - * - * @author Juan Pablo Villafañez Ramos - * @author Jesus Macias Portela - * @copyright (C) 2014 ownCloud, Inc. - * - * This code is covered by the ownCloud Commercial License. - * - * You should have received a copy of the ownCloud Commercial License - * along with this program. If not, see . - * - */ - -if (!OCA.External) { - OCA.External = {}; -} - -if (!OCA.External.StatusManager) { - OCA.External.StatusManager = {}; -} - -OCA.External.StatusManager.Utils = { - - showAlert: function(message){ - if (!OC.Notification.isHidden()) { - OC.Notification.hide(); - OC.Notification.showHtml(message); - } else { - OC.Notification.showHtml(message); - } - setTimeout(function() { - if ($("#notification").text() === message) { - OC.Notification.hide(); - } - }, 10000); - }, - - showIconError: function(folder, clickAction, errorImageUrl) { - var bgColor = '#F2DEDE'; - var imageUrl = "url(" + errorImageUrl + ")"; - var trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); - this.changeFolderIcon(folder, imageUrl); - this.toggleLink(folder, false, clickAction); - trFolder.css('background-color', bgColor); - }, - - /** - * @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=\"' + this.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 { - trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); - } - trFolder.css('background-color', ''); - 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, route) { - var file; - if (filename instanceof $) { - file = filename; - } else { - file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail"); - } - // file.css('background-image', route).hide().show(0); - // previous line is required in Chrome to force the css update so the image url - // is stored correctly later - //file.css('background-image', route).height(); - }, - - 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) { - return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); - }, - - /* 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/list.php b/apps/files_external/list.php index 831107c9c3..0a994e147f 100644 --- a/apps/files_external/list.php +++ b/apps/files_external/list.php @@ -25,7 +25,6 @@ $tmpl = new OCP\Template('files_external', 'list', ''); /* Load Status Manager */ \OCP\Util::addScript('files_external', 'statusmanager'); -\OCP\Util::addScript('files_external', 'statusmanagerutils'); \OCP\Util::addScript('files_external', 'rollingqueue'); OCP\Util::addScript('files_external', 'app'); From ee87f12c092776b3dfc33e5af6cd1e4697406866 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 18 Nov 2015 16:45:19 +0100 Subject: [PATCH 05/69] Fix hidpi previews on public page --- apps/files_sharing/js/public.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index 246b639f65..9ba456e867 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -90,12 +90,12 @@ OCA.Sharing.PublicApp = { // dynamically load image previews var token = $('#sharingToken').val(); var bottomMargin = 350; - var previewWidth = Math.ceil($(window).width() * window.devicePixelRatio); - var previewHeight = Math.ceil(($(window).height() - bottomMargin) * window.devicePixelRatio); + var previewWidth = $(window).width(); + var previewHeight = $(window).height() - bottomMargin; previewHeight = Math.max(200, previewHeight); var params = { - x: previewWidth, - y: previewHeight, + x: Math.ceil(previewWidth * window.devicePixelRatio), + y: Math.ceil(previewHeight * window.devicePixelRatio), a: 'true', file: encodeURIComponent(this.initialDir + $('#filename').val()), t: token, @@ -103,6 +103,10 @@ OCA.Sharing.PublicApp = { }; var img = $(''); + img.css({ + 'max-width': previewWidth, + 'max-height': previewHeight + }); var fileSize = parseInt($('#filesize').val(), 10); var maxGifSize = parseInt($('#maxSizeAnimateGif').val(), 10); From ae061bcbed3bdaaa8526e0d442b6c77f6909a1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Wed, 18 Nov 2015 18:34:26 +0100 Subject: [PATCH 06/69] Fix code from PR comments --- apps/files_external/js/rollingqueue.js | 6 +- apps/files_external/js/statusmanager.js | 1042 +++++++++++------------ 2 files changed, 479 insertions(+), 569 deletions(-) diff --git a/apps/files_external/js/rollingqueue.js b/apps/files_external/js/rollingqueue.js index 7e6570a2a7..0bff974414 100644 --- a/apps/files_external/js/rollingqueue.js +++ b/apps/files_external/js/rollingqueue.js @@ -5,10 +5,10 @@ * @author Jesus Macias Portela * @copyright (C) 2014 ownCloud, Inc. * - * This code is covered by the ownCloud Commercial License. + * This file is licensed under the Affero General Public License version 3 + * or later. * - * You should have received a copy of the ownCloud Commercial License - * along with this program. If not, see . + * See the COPYING-README file. * */ diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 244f5b6bd5..5f88153261 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -5,631 +5,541 @@ * @author Jesus Macias Portela * @copyright (C) 2014 ownCloud, Inc. * - * This code is covered by the ownCloud Commercial License. + * This file is licensed under the Affero General Public License version 3 + * or later. * - * You should have received a copy of the ownCloud Commercial License - * along with this program. If not, see . + * See the COPYING-README file. * */ if (!OCA.External) { - OCA.External = {}; + OCA.External = {}; } if (!OCA.External.StatusManager) { - OCA.External.StatusManager = {}; + OCA.External.StatusManager = {}; } OCA.External.StatusManager = { - mountStatus : null, - mountPointList : null, + mountStatus : null, + mountPointList : null, - getMountStatus : function(afterCallback) { - var self = this; - if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { - return; - } + getMountStatus : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return; + } - if (self.mountStatus) { - afterCallback(self.mountStatus); - } else { - self.isGetMountStatusRunning = true; - $.ajax({ - type : 'GET', - url : OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), - success : function(response) { - self.mountStatus = response.data; - afterCallback(self.mountStatus); - }, - error : function(jqxhr, state, error) { - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the external mounts: {type}', {type : error})); - if (!self.mountStatus) { - self.mountStatus = {}; - } - $.each(self.mountPointList, function(name, value){ - if (!self.mountStatus[value.mount_point]) { - self.mountStatus[value.mount_point] = {}; - } - self.mountStatus[value.mount_point].status = 'ok'; - OCA.External.StatusManager.Utils.restoreFolder(value); - OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); - }); - }, - complete : function() { - self.isGetMountStatusRunning = false; - } - }); - } - }, + if (self.mountStatus) { + afterCallback(self.mountStatus); + } else { + self.isGetMountStatusRunning = true; + $.ajax({ + type : 'GET', + url : OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), + success : function(response) { + self.mountStatus = response.data; + afterCallback(self.mountStatus); + }, + error : function(jqxhr, state, error) { + OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the status of the external mounts: {type}', {type : error})); + if (!self.mountStatus) { + self.mountStatus = {}; + } + $.each(self.mountPointList, function(name, value){ + if (!self.mountStatus[value.mount_point]) { + self.mountStatus[value.mount_point] = {}; + } + self.mountStatus[value.mount_point].status = 'ok'; + OCA.External.StatusManager.Utils.restoreFolder(value); + OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); + }); + }, + complete : function() { + self.isGetMountStatusRunning = false; + } + }); + } + }, - getMountPointListElement : function(mount_point) { - var element; - $.each(this.mountPointList, function(key, value){ - if (value.mount_point === mount_point) { - element = value; - return false; - } - }); - return element; - }, + getMountPointListElement : function(mount_point) { + var element; + $.each(this.mountPointList, function(key, value){ + if (value.mount_point === mount_point) { + element = value; + return false; + } + }); + return element; + }, - getMountStatusForMount : function(mountData, afterCallback) { - var self = this; - if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { - return $.Deferred().resolve(); - } + 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.mount_point, 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/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.mount_point, self.mountStatus[mountData.mount_point]); - } - }); - } - return defObj; - }, + 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/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; + }, - getMountPointList : function(afterCallback) { - var self = this; - if (typeof afterCallback !== 'function' || self.isGetMountPointListRunning) { - return; - } + 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; + 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 = []; - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of external mount points: {type}', {type : error})); - }, - complete : function() { - self.isGetMountPointListRunning = false; - } - }); - } - }, + 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; + } + }); + } + }, - setMountPointAsGood : function(mountPoint) { - OCA.External.StatusManager.Utils.restoreFolder(mountPoint); - OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); - delete this.mountStatus[mountPoint].code; - delete this.mountStatus[mountPoint].error; - this.mountStatus[mountPoint].status = 'ok'; - }, + setMountPointAsGood : function(mountPoint) { + OCA.External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + delete this.mountStatus[mountPoint].code; + delete this.mountStatus[mountPoint].error; + this.mountStatus[mountPoint].status = 'ok'; + }, - 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)); - }, + 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)); + }, - showCredentialsDialog : function(mountPoint, mountData, extraParams, target, extraInfo, successCallback, callbackCtx) { - var self = this; - var baseParams = {target: target, - m: mountData.mid, - name: mountPoint, - url: mountData.url, - share: mountData.share, - extra: extraInfo}; - var sendParams = ($.isPlainObject(extraParams)) ? $.extend(baseParams, extraParams) : baseParams; - $.get(OC.filePath('files_external', 'ajax', 'dialog.php'), - sendParams, - function(data) { - if (typeof data.status !== 'undefined' && data.status === 0) { - $('body').append(data.form); - var wnd_send_button_click_func = function () { - $('.oc-dialog-close').hide(); - var dataToSend = {}; - $('#wnd_div_form').find('input').each(function(){ - var thisElement = $(this); - if (thisElement.is('[type="checkbox"]')) { - dataToSend[thisElement.attr('name')] = thisElement.prop('checked'); - } else { - dataToSend[thisElement.attr('name')] = thisElement.val(); - } - }); - $.ajax({type: 'POST', - url: $('#wnd_div_form form').attr('action'), - data: dataToSend, - success: function (data) { - var dialog = $('#wnd_div_form'); - if (typeof(data.status) !== 'undefined' && data.status === 0) { - dialog.ocdialog('close'); - if (successCallback && $.isFunction(successCallback)) { - successCallback.call(callbackCtx || this, mountPoint); - } - } else { - $('.oc-dialog-close').show(); - dialog.ocdialog('option', 'title', 'Windows Network Drive credentials validation failed'); - var title = $('.oc-dialog-title'); - var color = title.css('background-color'); - title.css('background-color', 'red'); - title.animate({backgroundColor: color}, 5000); - } - }, - error: function (){ - $('.oc-dialog-close').show(); - }}); - }; + processMountStatus : function(mounts) { + var hasErrors = false; + var self = this; + $.each(mounts, function(mountPoint, values){ + hasErrors = !self.processMountStatusIndividual(mountPoint, values) || hasErrors; + }); - var buttonList = [{text : t('files_external', 'Save'), - click : wnd_send_button_click_func, - closeOnEscape : true}]; + if (!this.notificationHasShown) { + this.notificationHasShown = true; + if (hasErrors) { + 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')); + } + } + }, - var ocdialogParams = {modal: true, buttons : buttonList, - closeOnExcape : true}; - $('#wnd_div_form').ocdialog(ocdialogParams) - .bind('ocdialogclose', function(){ - $('#wnd_div_form').ocdialog('destroy').remove(); - }); - } - }); - }, + processMountStatusIndividual : function(mountData, mountStatus) { - processMountStatus : function(mounts) { - var hasErrors = false; - var self = this; - $.each(mounts, function(mountPoint, values){ - hasErrors = !self.processMountStatusIndividual(mountPoint, values) || hasErrors; - }); + var mountPoint = mountData.mount_point; + if (mountStatus.status === 1) { + var trElement = FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(mountPoint)); //$('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(mountPoint) + '\"]'); - if (!this.notificationHasShown) { - this.notificationHasShown = true; - if (hasErrors) { - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured external mount points are not connected. Please click on the red row(s) for more information')); - } - } - }, + route = OCA.External.StatusManager.Utils.getIconRoute(trElement) + '-error'; - processMountStatusIndividual : function(mountData, mountStatus) { - var mountPoint = mountData.mount_point; - if (mountStatus.status === 1) { - var trElement = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(mountPoint) + '\"]'); + 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; + } + }, - route = OCA.External.StatusManager.Utils.getIconRoute(trElement) + '-error'; + 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 (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; - } - }, + 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.css('background-color', '#CCC'); + OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); + } + } + }, - 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) + '\"]'); - trElement.attr('data-external-backend', value.backend); - if (elementList) { - elementList = elementList.add(trElement); - } else { - elementList = trElement; - } - }); + launchFullConnectivityCheck : 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 external mount points: empty response from the server')); + return; + } + if (list && list.length > 0) { + self.processMountList(list); + self.getMountStatus(function(mountStatus){ + if (mountStatus === undefined && !self.notificationNoProcessListDone) { + self.notificationNoProcessListDone = true; + OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the status of the external mounts: empty response from the server')); + if (!self.mountStatus) { + self.mountStatus = {}; + } + $.each(list, function(name, value){ + if (!self.mountStatus[value.mount_point]) { + self.mountStatus[value.mount_point] = {}; + } + self.mountStatus[value.mount_point].status = 'ok'; + OCA.External.StatusManager.Utils.restoreFolder(value.mount_point); + OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); + }); + return; + } + self.processMountStatus(mountStatus); + }); + } + }); + }, - 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.css('background-color', '#CCC'); - OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); - } - } - }, + 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); - launchFullConnectivityCheck : function() { - var self = this; - this.getMountPointList(function(list){ - // check if we have a list first - if (list === undefined && !self.emptyWarningShown) { - self.emptyWarningShown = true; - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of external mount points: empty response from the server')); - return; - } - if (list && list.length > 0) { - self.processMountList(list); - self.getMountStatus(function(mountStatus){ - if (mountStatus === undefined && !self.notificationNoProcessListDone) { - self.notificationNoProcessListDone = true; - OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the external mounts: empty response from the server')); - if (!self.mountStatus) { - self.mountStatus = {}; - } - $.each(list, function(name, value){ - if (!self.mountStatus[value.mount_point]) { - self.mountStatus[value.mount_point] = {}; - } - self.mountStatus[value.mount_point].status = 'ok'; - OCA.External.StatusManager.Utils.restoreFolder(value.mount_point); - OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); - }); - return; - } - self.processMountStatus(mountStatus); - }); - } - }); - }, + if (!self.mountStatus) { + self.mountStatus = {}; + } - launchFullConnectivityCheckOneByOne : function() { - var self = this; - this.getMountPointList(function(list){ - // check if we have a list first - if (list === undefined && !self.emptyWarningShown) { - self.emptyWarningShown = true; - OCA.External.StatusManager.Utils.showAlert(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); + var ajaxQueue = []; + $.each(list, function(key, value){ + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); - if (!self.mountStatus) { - self.mountStatus = {}; - } + 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(); + } + }); + }, - var ajaxQueue = []; - $.each(list, function(key, value){ - var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), - funcArgs: [value, - $.proxy(self.processMountStatusIndividual, self)]}; - ajaxQueue.push(queueElement); - }); + launchPartialConnectivityCheck : function(mountListData, recheck) { + if (mountListData.length === 0) { + return; + } - 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) { - OCA.External.StatusManager.Utils.showAlert(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(); - } - }); - }, + 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(); + }, - launchPartialConnectivityCheck : function(mountListData, recheck) { - if (mountListData.length === 0) { - return; - } + recheckConnectivityForMount : function(mountListNames, recheck, checkGlobal) { + if (mountListNames.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(); - }, + var self = this; + var mountListData = []; + var recheckPersonalGlobal = false; + var recheckAdminGlobal = false; - recheckConnectivityForMount : function(mountListNames, recheck, checkGlobal) { - if (mountListNames.length === 0) { - return; - } + if (!self.mountStatus) { + self.mountStatus = {}; + } - var self = this; - var mountListData = []; - var recheckPersonalGlobal = false; - var recheckAdminGlobal = false; + $.each(mountListNames, function(key, value){ + var mountData = self.getMountPointListElement(value); + if (mountData) { + mountListData.push(mountData); + } + }); - if (!self.mountStatus) { - self.mountStatus = {}; - } + // 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]; + } + }); + } - $.each(mountListNames, function(key, value){ - var mountData = self.getMountPointListElement(value); - if (mountData) { - if (mountData.type === 'personal' && mountData.location === 2) { - recheckPersonalGlobal = true; - } - if (mountData.type === 'admin' && mountData.location === 2) { - recheckAdminGlobal = true; - } - mountListData.push(mountData); - } - }); - - // we might need to check more mounts if a personal mount with global credentials is affected - if (checkGlobal && (recheckPersonalGlobal || recheckAdminGlobal)) { - $.each(self.mountPointList, function(key, value){ - if (((recheckPersonalGlobal && value.type === 'personal') || (recheckAdminGlobal && value.type === 'admin')) && - value.location === 2 && - $.inArray(value, mountListData) === -1) { - // personal mount using global credentials, not present in the mountListData - mountListData.push(value); - } - }); - } - - // 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); - } + self.processMountList(mountListData); + self.launchPartialConnectivityCheck(mountListData, recheck); + } }; OCA.External.StatusManager.Utils = { - showAlert: function(message){ - if (!OC.Notification.isHidden()) { - OC.Notification.hide(); - OC.Notification.showHtml(message); - } else { - OC.Notification.showHtml(message); - } - setTimeout(function() { - if ($("#notification").text() === message) { - OC.Notification.hide(); - } - }, 10000); - }, + showIconError: function(folder, clickAction, errorImageUrl) { + var bgColor = '#F2DEDE'; + 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.css('background-color', bgColor); + }, - showIconError: function(folder, clickAction, errorImageUrl) { - var bgColor = '#F2DEDE'; - var imageUrl = "url(" + errorImageUrl + ")"; - var trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); - this.changeFolderIcon(folder, imageUrl); - this.toggleLink(folder, false, clickAction); - trFolder.css('background-color', bgColor); - }, + /** + * @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')); + } + }); - /** - * @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=\"' + this.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')); + } + }); + }, - 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.css('background-color', ''); + 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 tr element - */ - restoreFolder: function(folder) { - var trFolder; - if (folder instanceof $) { - trFolder = folder; - } else { - trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); - } - trFolder.css('background-color', ''); - 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 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; - /** - * @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'); + } - 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; + } - switch (backend) { - case 'smb': - icon = OC.imagePath('windows_network_drive', 'folder-windows'); - break; - case 'sharepoint': - icon = OC.imagePath('sharepoint', 'folder-sharepoint'); - break; - } + return icon; + }, - 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; + }); + } + }, - 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; + }, - 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; + }, - /* escape a selector expression for jQuery */ - jqSelEscape: function(expression) { - return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); - }, + /* 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(); - /* 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; - } + for (var i = 0; i < args.length; i++) { + if (!obj || !obj.hasOwnProperty(args[i])) { + return false; + } + obj = obj[args[i]]; + } + return true; + } }; From 31cfd43e8ad95bec0086409597c35294b7d19df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Fri, 20 Nov 2015 08:42:31 +0100 Subject: [PATCH 07/69] Adding logic to show custom icon for current backends, waiting for icon files --- apps/files_external/js/statusmanager.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 5f88153261..5c60c935e9 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -485,6 +485,30 @@ OCA.External.StatusManager.Utils = { case 'sharepoint': icon = OC.imagePath('sharepoint', 'folder-sharepoint'); break; + case 'amazons3': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'dav': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'dropbox': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'ftp': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'google': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'owncloud': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'sftp': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; + case 'swift': + icon = OC.imagePath('core', 'filesystem/folder-external'); + break; } return icon; From b6e8a6e64f8fca3559fe9ca0f5ecbeaa1cb3f7c6 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 16 Nov 2015 13:54:35 +0100 Subject: [PATCH 08/69] add icons for disabled checkbox, radio button, error and colored checkmark --- core/img/actions/checkbox-checked.svg | 2 +- core/img/actions/checkbox-disabled-white.png | Bin 0 -> 134 bytes core/img/actions/checkbox-disabled-white.svg | 5 +++++ core/img/actions/checkbox-disabled.png | Bin 0 -> 134 bytes core/img/actions/checkbox-disabled.svg | 5 +++++ core/img/actions/checkbox-mixed.svg | 2 +- core/img/actions/checkbox.svg | 2 +- core/img/actions/checkmark-color.png | Bin 0 -> 279 bytes core/img/actions/checkmark-color.svg | 2 ++ core/img/actions/checkmark-white.svg | 4 ++-- core/img/actions/checkmark.svg | 2 +- core/img/actions/error-color.png | Bin 0 -> 228 bytes core/img/actions/error-color.svg | 4 ++++ core/img/actions/error-white.png | Bin 0 -> 228 bytes core/img/actions/error-white.svg | 4 ++++ core/img/actions/error.png | Bin 0 -> 160 bytes core/img/actions/error.svg | 4 ++++ core/img/actions/radio-checked.png | Bin 0 -> 425 bytes core/img/actions/radio-checked.svg | 5 +++++ core/img/actions/radio-disabled.png | Bin 0 -> 317 bytes core/img/actions/radio-disabled.svg | 5 +++++ core/img/actions/radio-white.png | Bin 0 -> 336 bytes core/img/actions/radio-white.svg | 4 ++++ core/img/actions/radio.png | Bin 0 -> 321 bytes core/img/actions/radio.svg | 5 +++++ 25 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 core/img/actions/checkbox-disabled-white.png create mode 100644 core/img/actions/checkbox-disabled-white.svg create mode 100644 core/img/actions/checkbox-disabled.png create mode 100644 core/img/actions/checkbox-disabled.svg create mode 100644 core/img/actions/checkmark-color.png create mode 100644 core/img/actions/checkmark-color.svg create mode 100644 core/img/actions/error-color.png create mode 100644 core/img/actions/error-color.svg create mode 100644 core/img/actions/error-white.png create mode 100644 core/img/actions/error-white.svg create mode 100644 core/img/actions/error.png create mode 100644 core/img/actions/error.svg create mode 100644 core/img/actions/radio-checked.png create mode 100644 core/img/actions/radio-checked.svg create mode 100644 core/img/actions/radio-disabled.png create mode 100644 core/img/actions/radio-disabled.svg create mode 100644 core/img/actions/radio-white.png create mode 100644 core/img/actions/radio-white.svg create mode 100644 core/img/actions/radio.png create mode 100644 core/img/actions/radio.svg diff --git a/core/img/actions/checkbox-checked.svg b/core/img/actions/checkbox-checked.svg index c5aa3cd73b..c648957429 100644 --- a/core/img/actions/checkbox-checked.svg +++ b/core/img/actions/checkbox-checked.svg @@ -1,5 +1,5 @@ - + diff --git a/core/img/actions/checkbox-disabled-white.png b/core/img/actions/checkbox-disabled-white.png new file mode 100644 index 0000000000000000000000000000000000000000..e1f48439d270fb9ecb882ae8e5ccb94e02dd7e0c GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!P=HT}E0F#R19$G+`Tzg_%WG{3 zKv9;GAirRSOP8;RnX+F6^5s2U978G?lNHzuHXmXXj%b+5$``@Dok94}%bp_@q6{ui WnG&P2rkn>VW$<+Mb6Mw<&;$UPlPmuK literal 0 HcmV?d00001 diff --git a/core/img/actions/checkbox-disabled-white.svg b/core/img/actions/checkbox-disabled-white.svg new file mode 100644 index 0000000000..52c2fee3b1 --- /dev/null +++ b/core/img/actions/checkbox-disabled-white.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/core/img/actions/checkbox-disabled.png b/core/img/actions/checkbox-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a2ead20996562993ec08eaa551ff4a1cb68afd94 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!P=HT}E0CTI1JkBWyL0D`|7-(M zpeRd8kY6yvrOQ{uOxdpj`SPAFjv*C{$qH-+n-4GwM>MpG@EGI+ZBxvX + + + + diff --git a/core/img/actions/checkbox-mixed.svg b/core/img/actions/checkbox-mixed.svg index 7f3642912d..5f873d6a96 100644 --- a/core/img/actions/checkbox-mixed.svg +++ b/core/img/actions/checkbox-mixed.svg @@ -1,5 +1,5 @@ - + diff --git a/core/img/actions/checkbox.svg b/core/img/actions/checkbox.svg index fe8f727b89..bfb83e3708 100644 --- a/core/img/actions/checkbox.svg +++ b/core/img/actions/checkbox.svg @@ -1,5 +1,5 @@ - + diff --git a/core/img/actions/checkmark-color.png b/core/img/actions/checkmark-color.png new file mode 100644 index 0000000000000000000000000000000000000000..a8ab849cad7267e74034306dcbdb5023a801cb50 GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}RDe&2E0AVb#lWzif#E6x!+i#Z zV+;%z!R&Kj#x({8Ai54FFM-9cFfc$6Q2k{bY_NhB#`}MPhRc=&`2{mDv#@b+a`T9a zNy;ne=&snbdHb&2d-q?ueC7J9AM5; + diff --git a/core/img/actions/checkmark-white.svg b/core/img/actions/checkmark-white.svg index e6b63a4d59..964624a9ce 100644 --- a/core/img/actions/checkmark-white.svg +++ b/core/img/actions/checkmark-white.svg @@ -1,4 +1,4 @@ - - + + diff --git a/core/img/actions/checkmark.svg b/core/img/actions/checkmark.svg index 3fa2a3f1ba..e41472c8ef 100644 --- a/core/img/actions/checkmark.svg +++ b/core/img/actions/checkmark.svg @@ -1,2 +1,2 @@ - + diff --git a/core/img/actions/error-color.png b/core/img/actions/error-color.png new file mode 100644 index 0000000000000000000000000000000000000000..7d00282312ab9d50f4634201e03f97a51a59af41 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!O@L2`E0A8rz;K3v;VKfk#=rnX zS6~Pz1!P|aD*!SeTp**#etkAjzi>&AUoZnRD;tlNwvk2q(&Z~QUVifO)q8i|b*VsU z7f%<*kP60R1wMn1T+EFE);;G>=<={NAg r=^WuwVBl_B_~KfU70>0DEsPA(5$s2dI(r*|<}rA>`njxgN@xNAd<{SW literal 0 HcmV?d00001 diff --git a/core/img/actions/error-color.svg b/core/img/actions/error-color.svg new file mode 100644 index 0000000000..93cb9ffe0a --- /dev/null +++ b/core/img/actions/error-color.svg @@ -0,0 +1,4 @@ + + + + diff --git a/core/img/actions/error-white.png b/core/img/actions/error-white.png new file mode 100644 index 0000000000000000000000000000000000000000..6e15865401d6bee0f86181429c67f7ffb566187f GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!O@L2`E0F$AF1X>DAq> + + + diff --git a/core/img/actions/error.png b/core/img/actions/error.png new file mode 100644 index 0000000000000000000000000000000000000000..61df76b53ea5ef14cd1acffc997fc6d090a451c4 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPE^4e$wZ1=5&6h>>9lP?W7C$S;^d zR`Jf=2miu3+kqk`o-U3d9MQ=M2bfweUutqNSsWP^wTdZ1p^;bT30u+<2FXkXHz__g k4h8MD>~?96?M$)^3}^I3wik5mUk$Ry)78&qol`;+0GXsD{r~^~ literal 0 HcmV?d00001 diff --git a/core/img/actions/error.svg b/core/img/actions/error.svg new file mode 100644 index 0000000000..38e4053c33 --- /dev/null +++ b/core/img/actions/error.svg @@ -0,0 +1,4 @@ + + + + diff --git a/core/img/actions/radio-checked.png b/core/img/actions/radio-checked.png new file mode 100644 index 0000000000000000000000000000000000000000..94933b7b69c84c8fa356f947a281b489e95b9543 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf`~aU2S0Ei(JTo+RUSP@eu+q8V zrE|hcW<{0HjjWg#Q!y{Pa$Z8sf`pod3DpY{YZt@=88r)|E9XX6%uB3Ym;^+13nRHx4$oc-L`Q(!(BfHfRrBMj7sOYCOaQB2)HQ!s&%)h(i}u`n@Z#2k zm$x3iy#4Ui{ikmpJbm-@)rU9lzr6YI<=c;6-+%o2@$>ip|Nq78{uKh9C|45X7tA0c zDi$0X*4oz5dFRgEyZ7#W{_^GP*YDqdfWXg??~-ajm9srv978H@<@R|BH97Dw2)c*` zrnuY`4|GUKi1_q>yCj=Ufb0ET+ACddxL(Q+EV;U5|9p=K|6o~x%F^Aee6=5xCW=K& zRH + + + + diff --git a/core/img/actions/radio-disabled.png b/core/img/actions/radio-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ac7f49ed53310e48d982e01d8a95db0691054229 GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}LV!<*E0CT!bLON;lcs~gv}x0T zG*Dy)7yucwX3d%n1`q~N1PJELnFAC9D%rGY6Hq;bv3c`mAmi-Wv**vBzj5Qn&6_vx z+_`fwe_|)l4(XC0zhDLtQL*6Au-3MY&O3MR-n;kt%a^a;zyAP&pAS8f+=0ppJzX3_ zDsJVT^W(+je*h zubV|;^g@Av6Nk5^G`Lj;s5)fuSFxSZzv1riw|0^@fAFuL+qfmV?k3hA5onqA`pe40 j`?xoIb!hS4h*v+qPoVnQsgLV{mNR&|`njxgN@xNAMzEHi literal 0 HcmV?d00001 diff --git a/core/img/actions/radio-disabled.svg b/core/img/actions/radio-disabled.svg new file mode 100644 index 0000000000..6058bb73fc --- /dev/null +++ b/core/img/actions/radio-disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/core/img/actions/radio-white.png b/core/img/actions/radio-white.png new file mode 100644 index 0000000000000000000000000000000000000000..04beefdff014133e9d282f587ff57755feb12248 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}W`IwKE0F$A7w|`VZ5hxq<&q%3 zUU)Ah{-TEY)Iy3h^dQM&tSrROq?OO-^jJ$$JvFyT@>FVdQ&MBb@0A&8O^Z)<= literal 0 HcmV?d00001 diff --git a/core/img/actions/radio-white.svg b/core/img/actions/radio-white.svg new file mode 100644 index 0000000000..57611f4cdd --- /dev/null +++ b/core/img/actions/radio-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/core/img/actions/radio.png b/core/img/actions/radio.png new file mode 100644 index 0000000000000000000000000000000000000000..70ac4741b978b0071c4d672e0e7aa28c0f5709dc GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}a)3{WE0CT!bLON;lcs~gv}x0T zG*D#5j2W}QV9uO5^XAQ)J9jRS0VE-UKoKASDm!rC08k~6Jb3URko)4ri(~GP|JU5hxec^NswBuSm_bBTEI2f*wXLJ`&YipW?tT99r)5S5Q;#O|oO(6#b5eH@OvT&8oU;o#acuzAtciYmqTyg(}P0`bqEtsCJ zFxAk@Nor31wZ%L2MJ_luN;qr2J$uGr%WL6~R>v9Y5+6B#cP#wbC$fHN@VoP`e&@&w xsywy&F=4?jrp?v0uP*v0g>eTy7yS8{;nyL7Gn*?aSb^3vc)I$ztaD0e0stHBoa6ui literal 0 HcmV?d00001 diff --git a/core/img/actions/radio.svg b/core/img/actions/radio.svg new file mode 100644 index 0000000000..9df8925176 --- /dev/null +++ b/core/img/actions/radio.svg @@ -0,0 +1,5 @@ + + + + + From cebf0037eae1d799d267b5acc6c904992150b608 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 16 Nov 2015 14:01:19 +0100 Subject: [PATCH 09/69] compress action icons --- core/img/actions/add.svg | 5 ++- core/img/actions/close.svg | 2 +- core/img/actions/delete-hover.png | Bin 274 -> 208 bytes core/img/actions/delete-hover.svg | 2 +- core/img/actions/delete.png | Bin 243 -> 208 bytes core/img/actions/download.svg | 3 +- core/img/actions/logout.png | Bin 3071 -> 2993 bytes core/img/actions/logout.svg | 58 +---------------------------- core/img/actions/menu.svg | 12 +----- core/img/actions/public.svg | 4 +- core/img/actions/starred.svg | 2 +- core/img/actions/toggle.svg | 2 +- core/img/actions/view-close.png | Bin 1442 -> 1126 bytes core/img/actions/view-close.svg | 2 +- core/img/actions/view-next.png | Bin 1215 -> 959 bytes core/img/actions/view-next.svg | 2 +- core/img/actions/view-pause.png | Bin 682 -> 648 bytes core/img/actions/view-pause.svg | 6 +-- core/img/actions/view-play.png | Bin 870 -> 804 bytes core/img/actions/view-play.svg | 6 +-- core/img/actions/view-previous.png | Bin 1189 -> 984 bytes core/img/actions/view-previous.svg | 2 +- 22 files changed, 24 insertions(+), 84 deletions(-) diff --git a/core/img/actions/add.svg b/core/img/actions/add.svg index ecbab6f13a..c97431782f 100644 --- a/core/img/actions/add.svg +++ b/core/img/actions/add.svg @@ -1,5 +1,6 @@ + - - + + diff --git a/core/img/actions/close.svg b/core/img/actions/close.svg index e060da3f8b..fb49c6ac89 100644 --- a/core/img/actions/close.svg +++ b/core/img/actions/close.svg @@ -5,6 +5,6 @@ - + diff --git a/core/img/actions/delete-hover.png b/core/img/actions/delete-hover.png index 3f8cb6eff92db2d16b041818ada8b4b5f343bec0..ed12640df7133147f781bf2b0df11c6c78d71b0e 100644 GIT binary patch delta 192 zcmbQlbb)b#L_G^L0|Ud`yN`l^lx~1ei0l9V|5q_ETw`Fk%)oF3jIJ^;01=Q4B;kS( zsdqo4*8?^3l?3?(GcfD8#+6T4vE#tO!?!-)&~m#0lyUKNaSY*z?mfAXx4}Tf;b69H zo9B!vf-_bsGjN^p7uT?SFw4tt?-Rotc^lkZVkR*Z|36vsAZC;JsyB_X*A_@zTd%QY b)o+FylVwhKWcTX>4P@|i^>bP0l+XkK!BRIEiV3L_G%^0|SHn=l_X7ilx}eGlT;OYB*9lfPBsZkH}&M2Hxu+%;=;sy8hT|5}cn_Ql40p%1~Zju9umYU7Va)kgAtols@~NjTBH(zo(01h(+(wN!EPL1_CbW z4Mvuo{7!v5vaIe03Rqq^+nWd+)o%24I8|Myy}$PNL`}|crQ6jnP9B^5X-U~kZ8oQ zbp}USrtK_e{qwh@vgv?P;{s+jhPRHjyN%}W_%l^J%h1+-s(LLC&}|H!u6{1-oD!M< Dtm$Gr diff --git a/core/img/actions/delete-hover.svg b/core/img/actions/delete-hover.svg index 9583ec15b3..ecc6139a5e 100644 --- a/core/img/actions/delete-hover.svg +++ b/core/img/actions/delete-hover.svg @@ -1,4 +1,4 @@ - + diff --git a/core/img/actions/delete.png b/core/img/actions/delete.png index e891b370cca7b3d83e937863dbbc9578c5b8b1bd..20e894c7f740da793d98590fa12e998749ae2ad3 100644 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF4e$wZ{r~?zkVzysV6}MxP$^$Y zkY6wZvyN+A`Ggfa4jepu>+=mQw;Mni7f%<*5RT~HlM8tp3`86bX4|%T&X^)NW2G_! z*BO6tjR&*5{PsREypgxT%_U|ML-GHUB@bdYiLZLo7<+Aj#I^MrTUPyMxG`DgbVqi- PKFCp?u6{1-oD!M_?dBnL_G%^0|SHn=l_X7ilx}eGlT;OYB*9lfPBsZkH}&M2Hxu+%;=;sy8hT|5}cn_Ql40p%1~Zju9umYU7Va)kgAtols@~NjTBH(fv1aOh(+(&Nr7Ak6nLB` zSN{L~L$hMW+xyHZ_NPKLN`%{5>u%aj7V?TYWweEFT!`!Y2ng9#!1`#rm_L|MB^U&(t-XW|T<#w)um70$&irgv53YW{$t-il*cn XUC&$i?88QNpydpnu6{1-oD!M - + diff --git a/core/img/actions/logout.png b/core/img/actions/logout.png index bada7a12616cfc9c46081b402ae4f57afb9d7800..ad230de98f40244b1b8da5d714ca287a60530cc4 100644 GIT binary patch delta 263 zcmV+i0r>v^7qJ(R83+Ub006c6H|nt=o(g{e+(|@1R49>c(Z4PPaTLYzyNOL^DhY{# zLZ_tAsHpUWglN2gmr!iCje_XBfeOhMY8s7(c!ez_{w!v9^HKclnqhLfd%nrN_nZ(F zUFuXPRXYcHJ#b)6Q(vKJ-F_9woZ~`x_bS}sv>6*a!XFYZaL~bZ(v{uUXoqzVn)lYzArZpP1m@1ib}MEglyvrs3l5;k3e+3!4`r>ehTL$<9T-9NhWhMbLPBv zXXYkA18^y+CTZ=l3L z_+Fb5>y(odp`m$w?O$U+XC~)K8QsGKDvJl^h z*UYETm6Y81h->>e#^lC!B#q|+cuWmd!@HzWNhu#=+h3opP(0(}$G8VA`-2Js`}XH? z55_{nw&R=&wiS32#XZ;z$zx#N-LFCe3&2Up@02Z)fF|$~h<)!tj^|ihCLmx6I0Ei~ o9`FI&0*An4k)MV<=b`u>0C42f?G-3@lmGw#07*qoM6N<$f+yIbG5`Po diff --git a/core/img/actions/logout.svg b/core/img/actions/logout.svg index 1a0ee16718..96bd207284 100644 --- a/core/img/actions/logout.svg +++ b/core/img/actions/logout.svg @@ -1,58 +1,4 @@ - - - - - image/svg+xml - - - - - - - - + + diff --git a/core/img/actions/menu.svg b/core/img/actions/menu.svg index f0e33df373..24a057aac7 100644 --- a/core/img/actions/menu.svg +++ b/core/img/actions/menu.svg @@ -1,12 +1,4 @@ + - - - - image/svg+xml - - - - - - + diff --git a/core/img/actions/public.svg b/core/img/actions/public.svg index 99a71c6cb5..7721c9e340 100644 --- a/core/img/actions/public.svg +++ b/core/img/actions/public.svg @@ -1,7 +1,7 @@ - - + + diff --git a/core/img/actions/starred.svg b/core/img/actions/starred.svg index 130bab366a..07e38827b2 100644 --- a/core/img/actions/starred.svg +++ b/core/img/actions/starred.svg @@ -1,6 +1,6 @@ - + diff --git a/core/img/actions/toggle.svg b/core/img/actions/toggle.svg index 730464a72c..c426ab8099 100644 --- a/core/img/actions/toggle.svg +++ b/core/img/actions/toggle.svg @@ -1,2 +1,2 @@ - + diff --git a/core/img/actions/view-close.png b/core/img/actions/view-close.png index 0874381a5760a174529ad5278a25b4e0d211c5e2..eae9acc7a4301f25f0bdf3cda51708e51fb7d057 100644 GIT binary patch literal 1126 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0V4M-)6XFWw4kzH?;Naxs(=etw;_W6|Nr+~<9i)waeGOS zUoZnB6Eh1d8#@Ol7dHo;%SynXu)2;P7A@Zrnu%<~j*Ow+Wh`O}xGNw`O!J z1!S#E36x}aQ0c4qT{!PWOzN$}Qv@&7{rF}+(KGB?L&Gtff1e6}?$I=Q%Fy%ZU&)3a zvp6Qc<(JHmIlA|J`R<=q=VLjYeqFxz>v@*?QN!kbWx34<4}1K%m$J_D*4%C7`=_n+ z5Q_cI@JdQ2>2PMeZp+66lXo3Ay*y_wY1d@Ic1&SwCq{awm7k@Rto>6@_qH&t#&u2%-y+8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs000FaNklPp??XOlWzfP0jpfA1@r>Q0ncTeH&#+5-)#Zvq;C;>dBNo5yB8*jYQuoV zFwg+(0Gfd9a$jqB!*pYnETj(D3N#9?S;kf&he7(~c9Xhz#=d&B%cUo zMesE;`F6oH3+XCgS#ZerdOH-LER>pdW37OjySlpk!+*oWUxz}W0N@1dz#e0DTa8sW z%R4*ZJbd`@+xPF^|0Wy`9}tgdFV;{YODy8TCZHYY1kMf*5C5%{QkhI<#_#uE0WJdP zfiB=6;E{e%o}C9Sg+ifkv)SydQc8`Cj0^&2fp^7rlgwq&6YFNCO93dHJ9qBaOeQm9 zv)OhMn?d;1@WL}Fekr6wmQ=L3PjkHBXV6Gz3?9MW=iF|0-N3-W zq4xInZGve4wh5+=^3!qMw&@^@Mx&b!LUZy>r=iQ``dt(Iw`ura6e0!GyWQ^Hw|{Tn z?r}PuW+55_CfT46SymCy>DNH6G6I@O}U1Q3tKV$tsI z?i;C8>S0@3TT_33|3{%v$VKs3Z<3hM@vx>4S!929P^|Os0PhEb!7tP4^aD8&9|nWL z@5QyfzIoewRw6W`C7ZDx1yD9yxO4E8qjM>6AINxG5vB(Q!N*2n4PG zmstNeJ}&Wc(eL+PNvG2@uW}r(mSi=Q^q_TQWF+0$*=g_T>A5;MIG6;o(q|~D9DT|? z#}J;gv$Mosb zN!fpa*6&q@(Iv`d`7^_XW^Fgs)QYTH2bw9%^;WGBBzpX+KPFnXnQgrvlR^dTOIcRw pIDVDit1?~pI@mY - + diff --git a/core/img/actions/view-next.png b/core/img/actions/view-next.png index d8c749bec9b6b032342938ba6705b2baf2561a4b..be8cc15cecdf1790a32004c1fa4111fb559e0cef 100644 GIT binary patch literal 959 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0V5|-B32_B-M;g%3(9qV_4h#$g zdR$FS4ahJyHU_dGq@tptva+&@iV9FfS63Iv1_Fqnf`WpQk`hoaoS~(q1vCw)QdLzI zD0Sn;jhi=bK6vop(W6I?A3p|?4<9}Ra)IE*ix60f*yLQ-aSPHtX)L19r*QE_oeMP+4UQ)^p$duMk~ zPhVeOfB%HZvt}>beDUJVr%zwJeD(VE+js9jetPwH88A2)i#=T&Ln>~yUj7-*7%0MC zu=#|+Nrlr9w>mmBoMv3mYW-Gw-RXDRif8%xCUZZZtNc8t(!Ty&?fZM*_i{Zm3^_LQG(PxCT6Qzrr2sLk4Qe3lCf>vi)fa`m>hlH`t+SC zx3#!9Ua&je(f(hyWm0F)rbP`}7R`6=smI&LpI*eW@Y1GzGyg<(ua6hm9Junp)GdV? zHoL1XKa!rBb3>&t@O*z9_i3?GO8c$Zqv{_B9p19@?7;$xSYBFWh=HPvnomi91Ygb111CpPgg&ebxsLQ06Rf19RL6T delta 1206 zcmV;n1WEh92fqoB8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs000C$Nkl6I|0E0mJDj#hvZLN?7!h*1IrOVEB-ap)Srj;c&SvAL2=F+Iw@`-}C<7^S<}J4P0LhKqKG+ znt*1YMSi+~OW+(h15V}l3wgaNk9#eb?YvPQPo!`g;08K@4td_J{jO^Jy!U!yJ68@g z0Z)N;pj!g8$bWlIfPHySqx=mBH!klB)L7%13lZsiKa?C2Grp2zjslYawFY1juUwIGtoq=L}Xp_iy$8P_0cIiOs)0R90EfjwXwC`$;-FpP!G&CNFo zA`}V*5j{e$j#jR^=dBLZf;iP6DjGz=FpOUnL@JefCLsoaenda%K=c+z7it06Ayi2o zNr)ZkMrCz%bu%81|5hv(_kzKoCzVQl6$*ty8h?OWy3pk0LOp<55XZ>U1l|A#nM`J9 zdV2czLZNV=AR>{753vv0r33b7$DIIl2vwfyQGB8uXKQO~M^jT%f8_J|x4~f0lT0SR ziAJLyME>>Y@0^1Fyj(8()BfhNKaQQ2B35&P8d6%dqj`9ExXm=pj{|`~hhR6D+tHV5oxSq8(eM!P~vJrYC$}r-H7~l1MX-v+Pk>8_^IFTcUzWKiN#{SvXh zU5a~0l{v!hcA?BZ%P>yl9`@n9m6 zc;@wbyDiJwj>qFa=W@A%6fYwh*1nAX%qe;&0DZ%`xU#)dM&2*QLsGm)iD$Ffyc8}Y zn$#Ymah=wR9-LF4qHjj*a5p07_YvRM#P!X0!vQ;hUT%8yy+EI4`)%TfcM-1#pnu!% z2D-+_$Nh;!;)N#uT8gWj-&@=XKtbrG*E%^lIgm&szV&*&J^6foD;|%(dJJ)=Rd*~e z6bg?%mOH(gsq#}Tx5cuoza}Oo24`nyf5>LDn}`zI=Bm{0wBekVozkVbpf;d-HG3-m zRLzNd^7Hti;&8JMsK@R(qI)TaPA}!XReAjw5w&VE56-z0fIbz2Xd=h_Pp{|y0>+LQ U3w|Com;e9(07*qoM6N<$f~#pR761SM diff --git a/core/img/actions/view-next.svg b/core/img/actions/view-next.svg index 4b719842ef..713d1bc757 100644 --- a/core/img/actions/view-next.svg +++ b/core/img/actions/view-next.svg @@ -5,6 +5,6 @@ - + diff --git a/core/img/actions/view-pause.png b/core/img/actions/view-pause.png index 87a18128adec2ffa1a721eae5f4a4a1068559302..94cd1a5dc6c938962bf4d856fe056f4405bd248e 100644 GIT binary patch literal 648 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy&jWlyT!HlP0KUGy$R2TZb#-)f zw70jnv$OmE|9{d%SplH5Pf3tpFaskKGYcyl2PZc#AHRUGh=in+jI5lzf})zXzJZaM zxrLRDt)0DtkAGl9WORH|a!P7?MrK|?X?;^?cW?iM$y28-TDgAP&Ru&?p1XL{*3ycB zfsw`2#WBRf|LNq{S;rK3+7`dejNi(`w)_8UX&$$&_p1!b^0)rp9dm%m>C>+a1GP30 z<5bBA&hybt?7N*@jzwg12TtkM|81FWa6R+1Z}Ls4rb#E8mK%Hfc{(s8yt_4TCZh+V zL_#Y3_u5GEwS@-#TsdbRqkzDh>xyjoYvbfA5Ro%obwR!cg{+;o7lN_hR_kwf#LrvdaF}?bi$Iz~v;lzVI^=ntjTq!Eu@6>UEae=)0 z``S=rhUmKjhxX*K7BIww`ZH{uB*J(kKH<}2UX`r81kTUw{WouG;+1K^ mv%_+$OAD@Cyxjgh|2LzFkePwnv^~q+t delta 669 zcmV;O0%HA$1*!#*8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0006fNkl){m5QRVefC-RA>@1R;!WU8HD!zwL;)|t{O6*i6;D2DDpDgqmwFWfyf`SdN zs%x5Jru%h|G!gA?fhMw z+%2-?IWUz?^xKnY0<+}aeDVs|0;R0-Bzy-f`3#r?OO00|VgzahspLb~tz4El0$bn( zcm`G)H-4?}K!2*L=fDTxM&nW>G8eQ|psm(VMBKWTD8Y*o{{|ipbg=aVGA&*z`4`|5 za1AURfl`$`D*+-nmrWgkHSh$y(>&|Q)^!i-!~*yX+yY;LyEcNNC?0@&;Jzq|huB=; zPBCwlV`1GNdj^)Od=#6_=A(5$ehk;ZPsO%}dRIB@zkdZYu^dHJRZHN#^J7>9$#>_= zp>x2V=xHos(=-#hy*EFGDg7HVINb7JqCfpoB52z-Q$X`$@Kp~^%#c7x6IYPNd|&VD&PI~M)}0HP=Y^fq5@00000NkvXXu0mjf D_JAu# diff --git a/core/img/actions/view-pause.svg b/core/img/actions/view-pause.svg index e9ff43be0b..8945bf4565 100644 --- a/core/img/actions/view-pause.svg +++ b/core/img/actions/view-pause.svg @@ -5,10 +5,10 @@ - - + + - + diff --git a/core/img/actions/view-play.png b/core/img/actions/view-play.png index b07c6de3cfd1835fb410c37a5470828f7e322e87..a8398d5758f44f1616e3682098d90d20ec0bf6a7 100644 GIT binary patch literal 804 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0U~~!a32_B-M*%Pds;a7x!y!FA zJvTQuEiElEF)=uzI^%r|NkZ~b{#;?*(E`K!3>N{ z%q*;I>>Qk2+&sK|`~reP!Xlz#;u4ZlGO}{=ib~2VYU&!A+B&+1Mkb~fmR2^l_D;^O zZtfnQ-hm-u;SrHhF|qN9scGq%S=mL!Rn;|(?OolyeSH%qO`bAm{;EyecI>=!|Iv$= zZ{GfS#vuocMioyN#}EtuxtITDH5&*pe3&DDIV^hdn&!V7-~OGS&2JEvJZX20ZkD8T zG}B}br@EMPr)3Qqb|`ERcyzkV|4y^cc?FjDe{Gp0pQHw+oQY0P->f>}d1|Qr(+9nZ z$#?r40c^E=C_RhhT9>DUM^Iwsq=%5HAu@5aT-u9L1zbEviW+_&Gb`;bH@ zmpRKT<@fEEv;Tb2=qO|1bGPGpK3z5Dz{Lqyv<=Ul-`ebaxczzFj-?{cG%gFdPM+(@ zQd|G>mvqG91y??5v_84R)aHG>{-D!@mY^WdO?9k$elsWS`sGz5bXn!(UDh7Uud3@V zYiy}ykTAY}{(Ydw=lBU0N%K=4nFqIeO|>eGJo(zs?98pA_Zo6rV>V?@&Ydqa=gAAz cc5~Bz_Nu4W_!!8_vw-5*)78&qol`;+0IMP2asU7T delta 858 zcmV-g1Eu_=2IdBk8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs0008xNklN=ga}Y9xLDwIzyFpno(}DQIXS8!5HZB=#?X z5-SbTopOyOcZeW6pE%CPWhr)6-dudfmy1Ul-RbPxdG@{C*%=3Ij<|jA07{-I%dxJB zEfWfu0@89d017y_+zy@?#0E$MBl0XG5J=E7AdssKlNiJRnBb$pO>y&E0GwEUY5^q% zu>o!XS>QHsOMf6z5~u?l0d2WIzAlh7-Pw;x@EkBHo&)X(*r-67cg#8oyD|H|FTjX3 z`+E|2s?lhC34*|>)oKV>7Ol!C-F1=}#F0VAB={p>8kkl}eFgA+|97!itgWxF`@k-+ zBfbml0|&rg^e2k?G?Cla0A$f}KLMTsvr4JY_8&dZYkwAt#m#E9>H#hB#2}8$J_}69 z>}P@JN~ur1By(N2RVtM>tJSJ200v~I56Gznav`Z1fN=qs0p@@gN~xt@06jo#MOqPx zbkJMaRzv~H2AC8Do&kBK)W?1ReH3Y0itGuH_#roZDC;{SE*FqxUO3$6bi4=i+Kik3_JktqbF*zYzlCq0IqEF^YarM z8yj!8wzl3cE-tgxBkwY49>FS>cbY(+H`0MGN9rBbO@see>{0)K#Q^lsRvyA@4cp`rj{pX)KU zVW%HJxb}-1I8GwE1YjQ&c5(5)z==|^0kDhDGxXsx=!_E`MwuSLPeiT@Hmu{=R=^aW zM=~HV{DQ_{8Cu@BWqIt@EeznuK*z*uOs?EB+5pA^0T`q;OWdr6YxzN& k(`)OJ!!3CjYUu6xKm1M)&4c3IY5)KL07*qoM6N<$f^O$^oB#j- diff --git a/core/img/actions/view-play.svg b/core/img/actions/view-play.svg index e617e29cb0..6359e6d018 100644 --- a/core/img/actions/view-play.svg +++ b/core/img/actions/view-play.svg @@ -5,10 +5,10 @@ - - + + - + diff --git a/core/img/actions/view-previous.png b/core/img/actions/view-previous.png index f601ec2ba44ca26ff930b4f95adac37314abb5c8..86e2a809626cb0683078e5582d1f37719c07f7de 100644 GIT binary patch literal 984 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0U~CKU32_B-M;h?;^(E5Fix)3m zx^yW}ac^&LYiny$Q&VGO{)vH&}nKP%n zyc|eYR8-8KJ$w1`<+EnZTDEK%&?ul{pqYynEh;W9E-5Mb3kLuH|Mzz_mj_zYSQ6wH z%)rRR%)-jX&dJTg%O@ZxBrGB-CN3cXJ}+>Vrph?Wn*XW z;OOMy;pye=;lf2r*KY!O zV%zqeyZ7wfxBt-L!$*!BIePTi@e?Oco&NLhQ_zPez~s^3>EaktajSK5c=#a)fmTnB zMis3~AyFX$q5>f~97-_M&n)4JI7N^*p*{*{|= z^wKALUMl8U%ow9TOD3*f(2G5mWyR6+xHiaYAr)}YnTO}qBj3)B^v%BzVQR|18m+Q_LA9maxxq#~h z%Vrs`C)eZ+taL+mcu==UBZm|ra#y&FBR`uXZBn;@upL8 zZ&>_mj$ZxAzxr=$3-6Viy=3{0HsdR&ZC7&l?EAh=%)Qw!In_a7$FUdPLJdMknyOc^ zWPB1{?7hm<;2FDHdV$u^y@rK{z8ew}n=wTPS`fBiVE;$v^CW)*=FtEa1<%Q~loCIH(~H@N@+ delta 1180 zcmV;N1Y`Ty2c-#+8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs000CcNklZT}+!*7{`C~?OMvZq0UWR#vDQm3bYt?y}%+NT=-RuUVoV(iO!FBVT>ji0=l4UQ(AU5K@Vp%F zM!3xOkisK~hk#FkD~pSZH>7xBdU|>uxCFcgbOL7(?tifaP>c9yz}1C?g$*S>H8qt0 zz69Qr^bv zd<47>ya+rCJg%+YRt-Q;FjmD!fscVVfR}();7JbqzNXb12y?j+!J~_R4qS^wBI{+u zF9UA^FMlKaep-rKHvKU<@ifo|T-3zJB9X{-&F9O&l_SL6CE`^9YzRNO5K(&pVam4< zX8(S6cJ^SajgOE20$c??kz-zwz;%f$00+YF&mbar2oY4*W@cs%w%XX(*l)lj@P)Ka zK#HHKR~(9g_ZT92F9Poa-{?Lc9UZ*^{0Mvte18D+Ba+S265d&lI26r)O0MQr;L_aO z+^^}dkD9U|45QSw{Q0qUr2ibkV5 zUa$A0&*y6y8X7vA&1UayY;0@;d$MN`myR6bs5P}-(F)}NY!tJgI(8lLcznC9tp3= zUXbq_;_>)xuh;AH`Ft(GV9;Y2MmCvD?tfCe=~RNK3Q&4oD*Ye;6(ICEc^-zT$pXq$ z`szy|Dp^9!Ro8G8oHYaJ%@Ty&ZqKZ(t^GyuCaiXdg3(=46F?;hQ$ciebTs;WzVpFg z(Cc(M_f}U|?;wg1Rg|d0FGJ&*Vot4+}xaASy{P>xPOkT zM5VjJv^H)zzdt3n;TnOTid_`2~nCUEuB;~7beTg%b|2S zy*oTSoB(!!yFdz&wzE34rK9o)h-#%-3P=O@%2>g2ZK!XfeeIo!_za>@)r->yh&WKf u1??MkRmY_e%Aa|Jd5p0Zs`C30000 - + From c4a100f5359a9405dbe4d0b8a5a53c576c80e901 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 19 Nov 2015 13:27:47 +0100 Subject: [PATCH 10/69] add icons for checked+disabled checkbox and radio --- core/img/actions/checkbox-checked-disabled.png | Bin 0 -> 233 bytes core/img/actions/checkbox-checked-disabled.svg | 5 +++++ core/img/actions/radio-checked-disabled.png | Bin 0 -> 378 bytes core/img/actions/radio-checked-disabled.svg | 5 +++++ 4 files changed, 10 insertions(+) create mode 100644 core/img/actions/checkbox-checked-disabled.png create mode 100644 core/img/actions/checkbox-checked-disabled.svg create mode 100644 core/img/actions/radio-checked-disabled.png create mode 100644 core/img/actions/radio-checked-disabled.svg diff --git a/core/img/actions/checkbox-checked-disabled.png b/core/img/actions/checkbox-checked-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..55980ba730d193e82e2b0f2cedd4efd49cf6a150 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!eSlAhE0CTyZ{FOwbAcof%$hZ8 z+O%n_SFhf+YuBDVd-m?#yKmpV!-o$aJ9g~Ei4!MJo;-Ex)c5b-|Ni~^@87@w|Nq+w zIy(c6U@Hmo3ud@<`O5q6H_vLU2Z{uHx;TbZ-0JP~6lzf5VG$Hn?N~7L|Ng680WPPw zYiFO!a+?u*c;BJg7p}|VQto&Q-d411tbG}we`MC{6Xz_HXOv_nc + + + + diff --git a/core/img/actions/radio-checked-disabled.png b/core/img/actions/radio-checked-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..09abc410f618214c27f1c46afff9d424bc14297a GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}U4T!BE0CT!bLON;lcs~gv}x0T zG*D#5j2W}QV9uO5^XAQ)J9jRS0VE-UKoKASDm!rC08k~6Jb3URkPFm4d-iOIN}z)6 z+qdu7v18}XoiARzc=__>>({T}ym|Bf{rk_KKmYpm>;M1%AEy3w2f9G2B*-tAK}1w6 zI5e!at)uhKoxAt$eg5+0>-XuD$ + + + + From 68a3a3ed6a2515ada5d7bde2a15abf104433cccc Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Thu, 19 Nov 2015 13:30:40 +0100 Subject: [PATCH 11/69] add new icon rules to icons.css --- core/css/icons.css | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/css/icons.css b/core/css/icons.css index 14b2101b33..dd34d03ae5 100644 --- a/core/css/icons.css +++ b/core/css/icons.css @@ -47,10 +47,12 @@ .icon-checkmark { background-image: url('../img/actions/checkmark.svg'); } - .icon-checkmark-white { background-image: url('../img/actions/checkmark-white.svg'); } +.icon-checkmark-color { + background-image: url('../img/actions/checkmark-color.svg'); +} .icon-close { background-image: url('../img/actions/close.svg'); @@ -82,6 +84,16 @@ background-image: url('../img/actions/edit.svg'); } +.icon-error { + background-image: url('../img/actions/error.svg'); +} +.icon-error-white { + background-image: url('../img/actions/error-white.svg'); +} +.icon-error-color { + background-image: url('../img/actions/error-color.svg'); +} + .icon-external { background-image: url('../img/actions/external.svg'); } From 5b9a693fbc73b5bed59197af0f9961605cea11ec Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 20 Nov 2015 16:00:16 +0100 Subject: [PATCH 12/69] Added some unit tests for the status manager --- .../tests/js/statusmanagerSpec.js | 205 ++++++++++++++++++ tests/karma.config.js | 3 +- 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 apps/files_external/tests/js/statusmanagerSpec.js diff --git a/apps/files_external/tests/js/statusmanagerSpec.js b/apps/files_external/tests/js/statusmanagerSpec.js new file mode 100644 index 0000000000..975d71627b --- /dev/null +++ b/apps/files_external/tests/js/statusmanagerSpec.js @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015 Vincent Petry + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +describe('OCA.External.StatusManager tests', function() { + var notificationStub; + var fileList; + var statusManager; + var oldAppWebRoots; + + beforeEach(function() { + notificationStub = sinon.stub(OC.Notification, 'showTemporary'); + var $content = $('
'); + $('#testArea').append($content); + // dummy file list + var $div = $( + '
' + + '' + + '' + + '' + + '' + + '
' + + '
'); + $('#content').append($div); + + var fileActions = new OCA.Files.FileActions(); + fileList = new OCA.Files.FileList( + $div, { + fileActions : fileActions + } + ); + + fileList.add({ + id: 1, + type: 'folder', + name: 'testmount', + mountType: 'external-root', + path: '/', + mimetype: 'httpd/unix-directory', + size: 12, + permissions: OC.PERMISSION_ALL, + etag: 'abc' + }); + + statusManager = OCA.External.StatusManager; + + oldAppWebRoots = _.extend({}, OC.appswebroots); + OC.appswebroots['files_external'] = OC.webroot + '/apps/files_external'; + }); + afterEach(function() { + statusManager.mountStatus = null; + statusManager.mountPointList = null; + + notificationStub.restore(); + OC.appswebroots = oldAppWebRoots; + }); + + describe('getMountStatusForMount', function() { + beforeEach(function() { + statusManager.mountStatus = []; + }); + + it('retrieves mount status and passes it to callback', function() { + var mountData = { + id: 123, + type: 'smb', + mount_point: 'testmount', + location: 3 + }; + + var callbackStub = sinon.stub(); + statusManager.getMountStatusForMount(mountData, callbackStub); + + expect(fakeServer.requests.length).toEqual(1); + + var mountStatus = { + type: 'smb', + status: 0 + }; + + var jsonData = JSON.stringify(mountStatus); + var request = fakeServer.requests[0]; + + expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages/123'); + + fakeServer.requests[0].respond( + 200, + {'Content-Type': 'application/json'}, + jsonData + ); + + + expect(callbackStub.calledOnce).toEqual(true); + expect(callbackStub.getCall(0).args[0]).toEqual(mountData); + expect(callbackStub.getCall(0).args[1]).toEqual(mountStatus); + + // second call does not send request but returns known data + statusManager.getMountStatusForMount(mountData, callbackStub); + + expect(fakeServer.requests.length).toEqual(1); + + expect(callbackStub.calledTwice).toEqual(true); + expect(callbackStub.getCall(1).args[0]).toEqual(mountData); + expect(callbackStub.getCall(1).args[1]).toEqual(mountStatus); + }); + // TODO: case where status is not 0 + // TODO: error case + }); + describe('getMountPointList', function() { + // TODO + }); + describe('processMountList', function() { + var getActiveViewStub; + var getCurrentAppContainerStub; + + beforeEach(function() { + getActiveViewStub = sinon.stub(OCA.Files.App, 'getActiveView'); + getActiveViewStub.returns('files'); + getCurrentAppContainerStub = sinon.stub(OCA.Files.App, 'getCurrentAppContainer'); + getCurrentAppContainerStub.returns($('#testArea')); + }); + afterEach(function() { + getActiveViewStub.restore(); + getCurrentAppContainerStub.restore(); + }); + + it('updates file list element with status', function() { + var mountList = [{ + id: 123, + mount_point: 'testmount', + backend: 'smb', + backendText: 'SMB', + type: 'system', + status: 0, + location: '' + }]; + statusManager.processMountList(mountList); + + var $tr = fileList.findFileEl('testmount'); + expect($tr.attr('data-external-backend')).toEqual('smb'); + expect($tr.attr('data-icon')).toEqual( + OC.imagePath('windows_network_drive', 'folder-windows') + ); + // TODO: thumbnail URL + /* + expect(OC.TestUtil.getImageUrl($tr.find('.thumbnail'))).toEqual( + OC.imagePath('windows_network_drive', 'folder-windows') + ); + */ + // TODO: check CSS class + + }); + }); + describe('processMountStatus', function() { + // TODO + }); + describe('launchFullConnectivityCheckOneByOne', function() { + var getMountPointListStub; + var getMountStatusStub; + var processMountStatusStub; + var processMountListStub; + + beforeEach(function() { + getMountPointListStub = sinon.stub(statusManager, 'getMountPointList'); + getMountStatusStub = sinon.stub(statusManager, 'getMountStatus'); + processMountStatusStub = sinon.stub(statusManager, 'processMountStatus'); + processMountListStub = sinon.stub(statusManager, 'processMountList'); + }); + afterEach(function() { + getMountPointListStub.restore(); + getMountStatusStub.restore(); + processMountStatusStub.restore(); + processMountListStub.restore(); + }); + it('retrieves mount points then processes them', function() { + statusManager.launchFullConnectivityCheck(); + + expect(getMountPointListStub.calledOnce).toEqual(true); + var mountList = [{ + id: 123, + mount_point: 'testmount', + backend: 'smb', + backendText: 'SMB', + type: 'system', + status: 0, + location: '' + }]; + getMountPointListStub.yield(mountList); + + expect(processMountListStub.calledOnce).toEqual(true); + expect(processMountListStub.calledWith(mountList)).toEqual(true); + + // TODO: continue checking getMountStatus, etc + }); + }); + describe('recheckConnectivityForOne', function() { + // TODO + }); +}); diff --git a/tests/karma.config.js b/tests/karma.config.js index 64a94ef230..10c5fa3344 100644 --- a/tests/karma.config.js +++ b/tests/karma.config.js @@ -67,7 +67,8 @@ module.exports = function(config) { // up with the global namespace/classes/state 'apps/files_external/js/app.js', 'apps/files_external/js/mountsfilelist.js', - 'apps/files_external/js/settings.js' + 'apps/files_external/js/settings.js', + 'apps/files_external/js/statusmanager.js' ], testFiles: ['apps/files_external/tests/js/*.js'] }, From b2d2b52eea7efdf5f35c359f1caae81c75c44270 Mon Sep 17 00:00:00 2001 From: Hendrik Leppelsack Date: Thu, 12 Nov 2015 15:24:03 +0100 Subject: [PATCH 13/69] remove unneeded css prefixes --- core/css/apps.css | 21 +++++---------------- core/css/header.css | 7 +------ core/css/icons.css | 1 - core/css/inputs.css | 4 ++-- core/css/mobile.css | 1 - core/css/share.css | 2 -- core/css/styles.css | 16 +++------------- 7 files changed, 11 insertions(+), 41 deletions(-) diff --git a/core/css/apps.css b/core/css/apps.css index e9abbe0aee..9afd704434 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -6,7 +6,7 @@ width: 100%; } #app * { - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } @@ -21,7 +21,7 @@ width: 250px; height: 100%; float: left; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; background-color: #fff; padding-bottom: 44px; -webkit-user-select: none; @@ -35,12 +35,12 @@ height: 100%; width: inherit; overflow: auto; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } #app-navigation li { position: relative; width: 100%; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } #app-navigation .active.with-menu > a, @@ -67,7 +67,7 @@ min-height: 44px; padding: 0 12px; overflow: hidden; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; white-space: nowrap; text-overflow: ellipsis; color: #000; @@ -109,17 +109,13 @@ } #app-navigation .collapsible .collapse { - -moz-transform: rotate(-90deg); -webkit-transform: rotate(-90deg); -ms-transform:rotate(-90deg); - -o-transform:rotate(-90deg); transform: rotate(-90deg); } #app-navigation .collapsible.open .collapse { - -moz-transform: rotate(0); -webkit-transform: rotate(0); -ms-transform:rotate(0); - -o-transform:rotate(0); transform: rotate(0); } @@ -138,8 +134,6 @@ #app-navigation .collapsible.open { background-image: linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); - background-image: -o-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); - background-image: -moz-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); background-image: -webkit-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); background-image: -ms-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%); } @@ -209,10 +203,7 @@ /* drag and drop */ #app-navigation .drag-and-drop { - -moz-transition: padding-bottom 500ms ease 0s; - -o-transition: padding-bottom 500ms ease 0s; -webkit-transition: padding-bottom 500ms ease 0s; - -ms-transition: padding-bottom 500ms ease 0s; transition: padding-bottom 500ms ease 0s; padding-bottom: 40px; } @@ -459,8 +450,6 @@ background: #fff; border-left: 1px solid #eee; -webkit-transition: margin-right 300ms; - -moz-transition: margin-right 300ms; - -o-transition: margin-right 300ms; transition: margin-right 300ms; overflow-x: hidden; overflow-y: auto; diff --git a/core/css/header.css b/core/css/header.css index 37f06ef063..4a5db088f9 100644 --- a/core/css/header.css +++ b/core/css/header.css @@ -39,7 +39,6 @@ height: 45px; line-height: 2.5em; background-color: #1d2d44; - -moz-box-sizing: border-box; box-sizing: border-box; } @@ -54,7 +53,6 @@ padding: 5px; padding-bottom: 0; height: 45px; /* header height */ - -moz-box-sizing: border-box; box-sizing: border-box; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; opacity: 1; @@ -185,7 +183,6 @@ } #navigation, #navigation * { - -moz-box-sizing:border-box; box-sizing:border-box; } #navigation li { @@ -272,7 +269,6 @@ height: 100%; max-width: 80%; white-space: nowrap; - -moz-box-sizing: border-box; box-sizing: border-box; } @@ -330,7 +326,7 @@ border-radius: 3px; border-top-left-radius: 0; border-top-right-radius: 0; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } #expanddiv a { display: block; @@ -339,7 +335,6 @@ padding: 4px 12px 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; opacity: .7; - -moz-box-sizing: border-box; box-sizing: border-box; } #expanddiv a img { diff --git a/core/css/icons.css b/core/css/icons.css index 14b2101b33..76afb19f20 100644 --- a/core/css/icons.css +++ b/core/css/icons.css @@ -24,7 +24,6 @@ background-image: url('../img/loading-small.gif'); } .icon-32 { - -webkit-background-size: 32px !important; background-size: 32px !important; } diff --git a/core/css/inputs.css b/core/css/inputs.css index 9f440a6c35..b2d78c2562 100644 --- a/core/css/inputs.css +++ b/core/css/inputs.css @@ -55,7 +55,7 @@ input[type="email"], input[type="url"], input[type="time"] { -webkit-appearance:textfield; -moz-appearance:textfield; - -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; + box-sizing:content-box; } input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active, input[type="password"]:hover, input[type="password"]:focus, input[type="password"]:active, @@ -119,7 +119,7 @@ html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="c input[type="time"] { width: initial; height: 31px; - -moz-box-sizing: border-box; box-sizing: border-box; + box-sizing: border-box; } select { diff --git a/core/css/mobile.css b/core/css/mobile.css index 288ae2979d..131907eb09 100644 --- a/core/css/mobile.css +++ b/core/css/mobile.css @@ -46,7 +46,6 @@ .error-wide { width: 100%; margin-left: 0 !important; - -moz-box-sizing: border-box; box-sizing: border-box; } diff --git a/core/css/share.css b/core/css/share.css index 15f8061b06..55ee5996a7 100644 --- a/core/css/share.css +++ b/core/css/share.css @@ -125,8 +125,6 @@ a.unshare { .shareTabView .error { color: #e9322d; border-color: #e9322d; - -webkit-box-shadow: 0 0 6px #f8b9b7; - -moz-box-shadow: 0 0 6px #f8b9b7; box-shadow: 0 0 6px #f8b9b7; } diff --git a/core/css/styles.css b/core/css/styles.css index 75bbb78fe5..ac4e3bb0c4 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -26,11 +26,8 @@ body { #body-login { text-align: center; background: #1d2d44; /* Old browsers */ - background: -moz-linear-gradient(top, #35537a 0%, #1d2d44 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#35537a), color-stop(100%,#1d2d44)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #35537a 0%,#1d2d44 100%); /* IE10+ */ background: linear-gradient(top, #35537a 0%,#1d2d44 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#35537a', endColorstr='#1d2d44',GradientType=0 ); /* IE6-9 */ } @@ -99,8 +96,6 @@ body { width: 0; cursor: pointer; -webkit-transition: all 100ms; - -moz-transition: all 100ms; - -o-transition: all 100ms; transition: all 100ms; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; opacity: .7; @@ -117,8 +112,6 @@ body { /* CONTENT ------------------------------------------------------------------ */ #controls { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; box-sizing: border-box; position: fixed; top: 45px; @@ -149,8 +142,6 @@ body { #controls input[type='text'], #controls input[type='password'], #controls select { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; box-sizing: border-box; display: inline-block; height: 36px; @@ -175,7 +166,6 @@ body { width: 100%; overflow-x: hidden; /* prevent horizontal scrollbar */ padding-top: 45px; - -moz-box-sizing:border-box; box-sizing:border-box; } /* allow horizontal scrollbar for personal and admin settings */ @@ -806,7 +796,7 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;} width: 100%; height: 30px; } #tagsdialog .bottombuttons * { float:left;} -#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } +#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; transition:background-color 500ms; } #tagsdialog .taglist li:hover, #tagsdialog .taglist li:active { background:#eee; } #tagsdialog .addinput { width: 90%; clear: both; } @@ -825,9 +815,9 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;} .popup .close { position:absolute; top:0.2em; right:0.2em; height:20px; width:20px; background:url('../img/actions/close.svg') no-repeat center; } .popup h2 { font-size:20px; } .arrow { border-bottom:10px solid white; border-left:10px solid transparent; border-right:10px solid transparent; display:block; height:0; position:absolute; width:0; z-index:201; } -.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); -o-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); } +.arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); } .arrow.up { top:-8px; right:6px; } -.arrow.down { -webkit-transform:rotate(180deg); -moz-transform:rotate(180deg); -o-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); } +.arrow.down { -webkit-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); } /* ---- BREADCRUMB ---- */ From 9caf4ffbfc2be077a1431149e77be485cd087081 Mon Sep 17 00:00:00 2001 From: Clark Tomlinson Date: Wed, 17 Sep 2014 10:07:32 -0400 Subject: [PATCH 14/69] Replacing ini_get instances with inigetwrapper usages --- apps/files/admin.php | 5 ++--- apps/files/ajax/upload.php | 2 +- core/js/config.php | 2 +- lib/private/files.php | 2 +- lib/private/helper.php | 2 +- lib/private/memcache/apc.php | 4 ++-- lib/private/memcache/apcu.php | 4 ++-- lib/private/memcache/xcache.php | 2 +- 8 files changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/files/admin.php b/apps/files/admin.php index 786a8edf2a..f23f9b5269 100644 --- a/apps/files/admin.php +++ b/apps/files/admin.php @@ -30,9 +30,8 @@ OCP\User::checkAdminUser(); $htaccessWorking=(getenv('htaccessWorking')=='true'); - -$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); -$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); +$upload_max_filesize = OC::$server->getIniWrapper()->getBytes('upload_max_filesize'); +$post_max_size = OC::$server->getIniWrapper()->getBytes('post_max_size'); $maxUploadFilesize = OCP\Util::humanFileSize(min($upload_max_filesize, $post_max_size)); if($_POST && OC_Util::isCallRegistered()) { if(isset($_POST['maxUploadSize'])) { diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index 18e9cfe611..14f56a24b4 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -114,7 +114,7 @@ foreach ($_FILES['files']['error'] as $error) { $errors = array( UPLOAD_ERR_OK => $l->t('There is no error, the file uploaded with success'), UPLOAD_ERR_INI_SIZE => $l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ') - . ini_get('upload_max_filesize'), + . OC::$server->getIniWrapper()->getNumeric('upload_max_filesize'), UPLOAD_ERR_FORM_SIZE => $l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'), UPLOAD_ERR_PARTIAL => $l->t('The uploaded file was only partially uploaded'), UPLOAD_ERR_NO_FILE => $l->t('No file was uploaded'), diff --git a/core/js/config.php b/core/js/config.php index 953bd2ede4..376e108055 100644 --- a/core/js/config.php +++ b/core/js/config.php @@ -136,7 +136,7 @@ $array = array( "firstDay" => json_encode($l->getFirstWeekDay()) , "oc_config" => json_encode( array( - 'session_lifetime' => min(\OCP\Config::getSystemValue('session_lifetime', ini_get('session.gc_maxlifetime')), ini_get('session.gc_maxlifetime')), + 'session_lifetime' => min(\OCP\Config::getSystemValue('session_lifetime', OC::$server->getIniWrapper()->getNumeric('session.gc_maxlifetime')), OC::$server->getIniWrapper()->getNumeric('session.gc_maxlifetime')), 'session_keepalive' => \OCP\Config::getSystemValue('session_keepalive', true), 'version' => implode('.', OC_Util::getVersion()), 'versionstring' => OC_Util::getVersionString(), diff --git a/lib/private/files.php b/lib/private/files.php index af10f3e1e3..1cda28496c 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -115,7 +115,7 @@ class OC_Files { self::lockFiles($view, $dir, $files); $streamer->sendHeaders($name); - $executionTime = intval(ini_get('max_execution_time')); + $executionTime = intval(OC::$server->getIniWrapper()->getNumeric('max_execution_time')); set_time_limit(0); if ($getType === self::ZIP_FILES) { foreach ($files as $file) { diff --git a/lib/private/helper.php b/lib/private/helper.php index ee2f520fe2..3bb81fba60 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -462,7 +462,7 @@ class OC_Helper { // Default check will be done with $path directories : $dirs = explode(PATH_SEPARATOR, $path); // WARNING : We have to check if open_basedir is enabled : - $obd = ini_get('open_basedir'); + $obd = OC::$server->getIniWrapper()->getString('open_basedir'); if ($obd != "none") { $obd_values = explode(PATH_SEPARATOR, $obd); if (count($obd_values) > 0 and $obd_values[0]) { diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php index f768cdc1c6..e38b4bd3a3 100644 --- a/lib/private/memcache/apc.php +++ b/lib/private/memcache/apc.php @@ -115,9 +115,9 @@ class APC extends Cache implements IMemcache { static public function isAvailable() { if (!extension_loaded('apc')) { return false; - } elseif (!ini_get('apc.enabled')) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) { return false; - } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) { return false; } else { return true; diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php index 9a8da2ae60..84147233ef 100644 --- a/lib/private/memcache/apcu.php +++ b/lib/private/memcache/apcu.php @@ -28,9 +28,9 @@ class APCu extends APC { static public function isAvailable() { if (!extension_loaded('apcu')) { return false; - } elseif (!ini_get('apc.enabled')) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) { return false; - } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) { + } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) { return false; } elseif (version_compare(phpversion('apc'), '4.0.6') === -1) { return false; diff --git a/lib/private/memcache/xcache.php b/lib/private/memcache/xcache.php index a6265ed562..f1f932ba2c 100644 --- a/lib/private/memcache/xcache.php +++ b/lib/private/memcache/xcache.php @@ -118,7 +118,7 @@ class XCache extends Cache implements IMemcache { if (\OC::$CLI && !getenv('XCACHE_TEST')) { return false; } - if (!function_exists('xcache_unset_by_prefix') && ini_get('xcache.admin.enable_auth')) { + if (!function_exists('xcache_unset_by_prefix') && \OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) { // We do not want to use XCache if we can not clear it without // using the administration function xcache_clear_cache() // AND administration functions are password-protected. From 728648ad77ba3d96d8e61f95a748702df3d615bd Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Thu, 29 Oct 2015 09:52:13 +0100 Subject: [PATCH 15/69] Replace new occurences of ini_get with IniWrapper methods --- lib/private/helper.php | 10 ++++++---- lib/private/memcache/xcache.php | 2 +- lib/private/tempmanager.php | 2 +- lib/private/util.php | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/private/helper.php b/lib/private/helper.php index 3bb81fba60..e9fe43a4b3 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -753,8 +753,9 @@ class OC_Helper { * @return int PHP upload file size limit */ public static function uploadLimit() { - $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); - $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); + $ini = \OC::$server->getIniWrapper(); + $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize')); + $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size')); if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { return INF; } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { @@ -774,12 +775,13 @@ class OC_Helper { if (!function_exists($function_name)) { return false; } - $disabled = explode(',', ini_get('disable_functions')); + $ini = \OC::$server->getIniWrapper(); + $disabled = explode(',', $ini->get('disable_functions')); $disabled = array_map('trim', $disabled); if (in_array($function_name, $disabled)) { return false; } - $disabled = explode(',', ini_get('suhosin.executor.func.blacklist')); + $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist')); $disabled = array_map('trim', $disabled); if (in_array($function_name, $disabled)) { return false; diff --git a/lib/private/memcache/xcache.php b/lib/private/memcache/xcache.php index f1f932ba2c..0d2e43a1c1 100644 --- a/lib/private/memcache/xcache.php +++ b/lib/private/memcache/xcache.php @@ -124,7 +124,7 @@ class XCache extends Cache implements IMemcache { // AND administration functions are password-protected. return false; } - $var_size = (int)ini_get('xcache.var_size'); + $var_size = \OC::$server->getIniWrapper()->getNumeric('xcache.var_size'); if (!$var_size) { return false; } diff --git a/lib/private/tempmanager.php b/lib/private/tempmanager.php index 365d639389..ac44b76d68 100644 --- a/lib/private/tempmanager.php +++ b/lib/private/tempmanager.php @@ -213,7 +213,7 @@ class TempManager implements ITempManager { if ($temp = $this->config->getSystemValue('tempdirectory', null)) { $directories[] = $temp; } - if ($temp = ini_get('upload_tmp_dir')) { + if ($temp = \OC::$server->getIniWrapper()->get('upload_tmp_dir')) { $directories[] = $temp; } if ($temp = getenv('TMP')) { diff --git a/lib/private/util.php b/lib/private/util.php index 69f01c22be..95cbc480ea 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -1415,7 +1415,7 @@ class OC_Util { } // XCache if (function_exists('xcache_clear_cache')) { - if (ini_get('xcache.admin.enable_auth')) { + if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) { \OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN); } else { @xcache_clear_cache(XC_TYPE_PHP, 0); From 5580b562a36c682c4baea89c7026af5596f714bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Tue, 24 Nov 2015 08:16:14 +0100 Subject: [PATCH 16/69] Fix code from PR comments --- apps/files_external/js/app.js | 165 ++++++++++++------------ apps/files_external/js/rollingqueue.js | 118 ++++++++--------- apps/files_external/js/settings.js | 4 +- apps/files_external/js/statusmanager.js | 157 +++++++++------------- 4 files changed, 208 insertions(+), 236 deletions(-) diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js index 411d5fc343..87507f93be 100644 --- a/apps/files_external/js/app.js +++ b/apps/files_external/js/app.js @@ -9,105 +9,106 @@ */ if (!OCA.External) { - /** - * @namespace - */ - OCA.External = {}; + /** + * @namespace + */ + OCA.External = {}; } /** * @namespace */ OCA.External.App = { - fileList: null, + fileList: null, - initList: function($el) { - if (this.fileList) { - return this.fileList; - } + initList: function($el) { + if (this.fileList) { + return this.fileList; + } - this.fileList = new OCA.External.FileList( - $el, - { - scrollContainer: $('#app-content'), - fileActions: this._createFileActions() - } - ); + this.fileList = new OCA.External.FileList( + $el, + { + scrollContainer: $('#app-content'), + fileActions: this._createFileActions() + } + ); - this._extendFileList(this.fileList); - this.fileList.appName = t('files_external', 'External storage'); - return this.fileList; - }, + this._extendFileList(this.fileList); + this.fileList.appName = t('files_external', 'External storage'); + return this.fileList; + }, - removeList: function() { - if (this.fileList) { - this.fileList.$fileList.empty(); - } - }, + removeList: function() { + if (this.fileList) { + this.fileList.$fileList.empty(); + } + }, - _createFileActions: function() { - // inherit file actions from the files app - var fileActions = new OCA.Files.FileActions(); - fileActions.registerDefaultActions(); + _createFileActions: function() { + // inherit file actions from the files app + var fileActions = new OCA.Files.FileActions(); + fileActions.registerDefaultActions(); - // when the user clicks on a folder, redirect to the corresponding - // folder in the files app instead of opening it directly - fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { - OCA.Files.App.setActiveView('files', {silent: true}); - OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); - }); - fileActions.setDefault('dir', 'Open'); - return fileActions; - }, + // when the user clicks on a folder, redirect to the corresponding + // folder in the files app instead of opening it directly + fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { + OCA.Files.App.setActiveView('files', {silent: true}); + OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); + }); + fileActions.setDefault('dir', 'Open'); + return fileActions; + }, - _extendFileList: function(fileList) { - // remove size column from summary - fileList.fileSummary.$el.find('.filesize').remove(); - } + _extendFileList: function(fileList) { + // remove size column from summary + fileList.fileSummary.$el.find('.filesize').remove(); + } }; $(document).ready(function() { - $('#app-content-extstoragemounts').on('show', function(e) { - OCA.External.App.initList($(e.target)); - }); - $('#app-content-extstoragemounts').on('hide', function() { - OCA.External.App.removeList(); - }); + $('#app-content-extstoragemounts').on('show', function(e) { + OCA.External.App.initList($(e.target)); + }); + $('#app-content-extstoragemounts').on('hide', function() { + OCA.External.App.removeList(); + }); - /* Status Manager */ - if ($('#filesApp').val()) { + /* 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]; - // make sure we have a mount point list - OCA.External.StatusManager.getMountPointList(function() { - OCA.External.StatusManager.recheckConnectivityForMount([mount_point], true, 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)) { - // we don't have the data cached, so we'll get it one by one - OCA.External.StatusManager.launchFullConnectivityCheckOneByOne(); - } else { - // make sure we have a mount point list - OCA.External.StatusManager.getMountPointList(function(){ - var fileNames = []; - $.each(e.$files, function(key, value){ - fileNames.push(value.attr('data-file')); - }); - OCA.External.StatusManager.recheckConnectivityForMount(fileNames, false, false); - }); - } - } - }); - } - /* End Status Manager */ + $('#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 index 0bff974414..58cb0fb22f 100644 --- a/apps/files_external/js/rollingqueue.js +++ b/apps/files_external/js/rollingqueue.js @@ -59,77 +59,77 @@ * 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"; - } + 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(); - } - }; + for (i = 0; i < this.queueWindow; i++) { + this.launchNext(); + } + }; - this.hasNext = function() { - return (this.counter in this.functionList); - }; + 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); - } + 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.fail)) { + defObj.fail(funcData.fail); + } - if ($.isFunction(funcData.always)) { - defObj.always(funcData.always); - } + 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 (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 = {}; + OCA.External = {}; } if (!OCA.External.StatusManager) { - OCA.External.StatusManager = {}; + OCA.External.StatusManager = {}; } OCA.External.StatusManager.RollingQueue = RollingQueue; diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index a839f396b9..22f18fc29e 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1054,12 +1054,12 @@ MountConfigListView.prototype = _.extend({ } return defaultMountPoint + append; }, - + /** * Toggles the mount options dropdown * * @param {Object} $tr configuration row - */ + */ _showMountOptionsDropdown: function($tr) { if (this._preventNextDropdown) { // prevented because the click was on the toggle diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 5c60c935e9..0aedeb9922 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -21,9 +21,15 @@ if (!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) { @@ -32,36 +38,14 @@ OCA.External.StatusManager = { if (self.mountStatus) { afterCallback(self.mountStatus); - } else { - self.isGetMountStatusRunning = true; - $.ajax({ - type : 'GET', - url : OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), - success : function(response) { - self.mountStatus = response.data; - afterCallback(self.mountStatus); - }, - error : function(jqxhr, state, error) { - OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the status of the external mounts: {type}', {type : error})); - if (!self.mountStatus) { - self.mountStatus = {}; - } - $.each(self.mountPointList, function(name, value){ - if (!self.mountStatus[value.mount_point]) { - self.mountStatus[value.mount_point] = {}; - } - self.mountStatus[value.mount_point].status = 'ok'; - OCA.External.StatusManager.Utils.restoreFolder(value); - OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); - }); - }, - complete : function() { - self.isGetMountStatusRunning = false; - } - }); } }, + /** + * Function Check mount point status from cache + * @param {string} mount_point + */ + getMountPointListElement : function(mount_point) { var element; $.each(this.mountPointList, function(key, value){ @@ -73,6 +57,12 @@ OCA.External.StatusManager = { 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) { @@ -124,13 +114,17 @@ OCA.External.StatusManager = { 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 { @@ -164,13 +158,10 @@ OCA.External.StatusManager = { } }, - setMountPointAsGood : function(mountPoint) { - OCA.External.StatusManager.Utils.restoreFolder(mountPoint); - OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); - delete this.mountStatus[mountPoint].code; - delete this.mountStatus[mountPoint].error; - this.mountStatus[mountPoint].status = 'ok'; - }, + /** + * 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; @@ -194,27 +185,17 @@ OCA.External.StatusManager = { }, this)); }, - - processMountStatus : function(mounts) { - var hasErrors = false; - var self = this; - $.each(mounts, function(mountPoint, values){ - hasErrors = !self.processMountStatusIndividual(mountPoint, values) || hasErrors; - }); - - if (!this.notificationHasShown) { - this.notificationHasShown = true; - if (hasErrors) { - 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')); - } - } - }, + /** + * 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)); //$('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(mountPoint) + '\"]'); + var trElement = FileList.findFileEl(OCA.External.StatusManager.Utils.jqSelEscape(mountPoint)); route = OCA.External.StatusManager.Utils.getIconRoute(trElement) + '-error'; @@ -231,6 +212,12 @@ OCA.External.StatusManager = { } }, + /** + * 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){ @@ -256,39 +243,9 @@ OCA.External.StatusManager = { } }, - launchFullConnectivityCheck : 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 external mount points: empty response from the server')); - return; - } - if (list && list.length > 0) { - self.processMountList(list); - self.getMountStatus(function(mountStatus){ - if (mountStatus === undefined && !self.notificationNoProcessListDone) { - self.notificationNoProcessListDone = true; - OC.Notification.showTemporary(t('files_external', 'Couldn\'t get the status of the external mounts: empty response from the server')); - if (!self.mountStatus) { - self.mountStatus = {}; - } - $.each(list, function(name, value){ - if (!self.mountStatus[value.mount_point]) { - self.mountStatus[value.mount_point] = {}; - } - self.mountStatus[value.mount_point].status = 'ok'; - OCA.External.StatusManager.Utils.restoreFolder(value.mount_point); - OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); - }); - return; - } - self.processMountStatus(mountStatus); - }); - } - }); - }, + /** + * Function to process the whole mount point list in relation with their status (Async queue) + */ launchFullConnectivityCheckOneByOne : function() { var self = this; @@ -333,6 +290,13 @@ OCA.External.StatusManager = { }); }, + + /** + * 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; @@ -352,7 +316,14 @@ OCA.External.StatusManager = { new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue(); }, - recheckConnectivityForMount : function(mountListNames, recheck, checkGlobal) { + + /** + * 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; } @@ -486,28 +457,28 @@ OCA.External.StatusManager.Utils = { icon = OC.imagePath('sharepoint', 'folder-sharepoint'); break; case 'amazons3': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'dav': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'dropbox': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'ftp': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'google': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'owncloud': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'sftp': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; case 'swift': - icon = OC.imagePath('core', 'filesystem/folder-external'); + icon = OC.imagePath('core', 'filetypes/folder-external'); break; } From 674bc8e9cb340b2be1b27d4c8e3a539f550acb14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Tue, 24 Nov 2015 08:52:02 +0100 Subject: [PATCH 17/69] Add css to manage row status color --- apps/files_external/css/external.css | 8 ++++++++ apps/files_external/js/statusmanager.js | 7 +++---- apps/files_external/list.php | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 apps/files_external/css/external.css diff --git a/apps/files_external/css/external.css b/apps/files_external/css/external.css new file mode 100644 index 0000000000..b0b0634fc5 --- /dev/null +++ b/apps/files_external/css/external.css @@ -0,0 +1,8 @@ +.externalDisabledRow { + background-color: #CCC ! important;; +} + + +.externalErroredRow { + background-color: #F2DEDE ! important;; +} diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 0aedeb9922..5e7cb4e109 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -237,7 +237,7 @@ OCA.External.StatusManager = { // Save default view OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); // Disable row until check status - elementList.css('background-color', '#CCC'); + elementList.addClass('externalDisabledRow'); OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); } } @@ -361,12 +361,11 @@ OCA.External.StatusManager = { OCA.External.StatusManager.Utils = { showIconError: function(folder, clickAction, errorImageUrl) { - var bgColor = '#F2DEDE'; 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.css('background-color', bgColor); + trFolder.addClass('externalErroredRow'); }, /** @@ -406,7 +405,7 @@ OCA.External.StatusManager.Utils = { // 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.css('background-color', ''); + trFolder.removeClass('externalErroredRow').removeClass('externalDisabledRow'); tdChilds = trFolder.find("td:first-child div.thumbnail"); tdChilds.each(function(){ var thisElement = $(this); diff --git a/apps/files_external/list.php b/apps/files_external/list.php index 0a994e147f..4bbe5588c2 100644 --- a/apps/files_external/list.php +++ b/apps/files_external/list.php @@ -24,6 +24,7 @@ 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'); From 70071c8865eb18b739e9e681244497da310512d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Tue, 24 Nov 2015 11:55:33 +0100 Subject: [PATCH 18/69] Fix css selector and bug checking personal mounts status --- apps/files_external/css/external.css | 8 ++++---- apps/files_external/js/statusmanager.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/files_external/css/external.css b/apps/files_external/css/external.css index b0b0634fc5..bf57ec8805 100644 --- a/apps/files_external/css/external.css +++ b/apps/files_external/css/external.css @@ -1,8 +1,8 @@ -.externalDisabledRow { - background-color: #CCC ! important;; +#filestable tbody tr.externalDisabledRow { + background-color: #CCC; } -.externalErroredRow { - background-color: #F2DEDE ! important;; +#filestable tbody tr.externalErroredRow { + background-color: #F2DEDE; } diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 5e7cb4e109..4048bfc31b 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -77,7 +77,7 @@ OCA.External.StatusManager = { } else { defObj = $.ajax({ type : 'GET', - url: OC.webroot + '/index.php/apps/files_external/globalstorages/' + mountData.id, + 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; From f864b55323330db8ff7e6e66e6b9da6daf2e68ca Mon Sep 17 00:00:00 2001 From: Renaud Fortier Date: Thu, 26 Nov 2015 10:00:15 -0500 Subject: [PATCH 19/69] Remove of useless code --- apps/user_ldap/user_ldap.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index 204995198b..0b4bdff967 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -176,12 +176,8 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn } $dn = $user->getDN(); - $userFilter = 'objectclass=*'; - if ($this->access->connection->ldapUserFilter !== '') { - $userFilter = $this->access->connection->ldapUserFilter; - } //check if user really still exists by reading its entry - if(!is_array($this->access->readAttribute($dn, '', $userFilter))) { + if(!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapUserFilter))) { $lcr = $this->access->connection->getConnectionResource(); if(is_null($lcr)) { throw new \Exception('No LDAP Connection to server ' . $this->access->connection->ldapHost); From 574d0d08bb19a0084b9bbe14808dcacd209330ee Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 27 Nov 2015 15:37:55 +0100 Subject: [PATCH 20/69] Cleanup trashbin expire code * requested by @schiesbn --- apps/files_trashbin/lib/trashbin.php | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php index d492810b95..676252e163 100644 --- a/apps/files_trashbin/lib/trashbin.php +++ b/apps/files_trashbin/lib/trashbin.php @@ -214,13 +214,13 @@ class Trashbin { /** @var \OC\Files\Storage\Storage $sourceStorage */ list($sourceStorage, $sourceInternalPath) = $ownerView->resolvePath('/files/' . $ownerPath); try { - $sizeOfAddedFiles = $sourceStorage->filesize($sourceInternalPath); + $moveSuccessful = true; if ($trashStorage->file_exists($trashInternalPath)) { $trashStorage->unlink($trashInternalPath); } $trashStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath); } catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) { - $sizeOfAddedFiles = false; + $moveSuccessful = false; if ($trashStorage->file_exists($trashInternalPath)) { $trashStorage->unlink($trashInternalPath); } @@ -234,7 +234,7 @@ class Trashbin { $trashStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $trashInternalPath); - if ($sizeOfAddedFiles !== false) { + if ($moveSuccessful) { $query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)"); $result = $query->execute(array($filename, $timestamp, $location, $owner)); if (!$result) { @@ -258,7 +258,7 @@ class Trashbin { self::scheduleExpire($owner); } - return ($sizeOfAddedFiles === false) ? false : true; + return $moveSuccessful; } /** @@ -268,18 +268,14 @@ class Trashbin { * @param string $owner owner user id * @param string $ownerPath path relative to the owner's home storage * @param integer $timestamp when the file was deleted - * - * @return int size of stored versions */ private static function retainVersions($filename, $owner, $ownerPath, $timestamp) { - $size = 0; if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) { $user = \OCP\User::getUser(); $rootView = new \OC\Files\View('/'); if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) { - $size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath)); if ($owner !== $user) { self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView); } @@ -287,7 +283,6 @@ class Trashbin { } else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) { foreach ($versions as $v) { - $size += $rootView->filesize($owner . '/files_versions/' . $v['path'] . '.v' . $v['version']); if ($owner !== $user) { self::copy($rootView, $owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp); } @@ -295,8 +290,6 @@ class Trashbin { } } } - - return $size; } /** @@ -633,18 +626,16 @@ class Trashbin { public static function expire($user) { $trashBinSize = self::getTrashbinSize($user); $availableSpace = self::calculateFreeSpace($trashBinSize, $user); - $size = 0; $dirContent = Helper::getTrashFiles('/', $user, 'mtime'); // delete all files older then $retention_obligation list($delSize, $count) = self::deleteExpiredFiles($dirContent, $user); - $size += $delSize; - $availableSpace += $size; + $availableSpace += $delSize; // delete files from trash until we meet the trash bin size limit again - $size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace); + self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace); } /** From a79ae4ae086c08c75a6d974966458251e2167347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Tue, 1 Dec 2015 12:58:01 +0100 Subject: [PATCH 21/69] Delete js unit test. Another issue has been created to create js test --- .../tests/js/statusmanagerSpec.js | 205 ------------------ 1 file changed, 205 deletions(-) delete mode 100644 apps/files_external/tests/js/statusmanagerSpec.js diff --git a/apps/files_external/tests/js/statusmanagerSpec.js b/apps/files_external/tests/js/statusmanagerSpec.js deleted file mode 100644 index 975d71627b..0000000000 --- a/apps/files_external/tests/js/statusmanagerSpec.js +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2015 Vincent Petry - * - * This file is licensed under the Affero General Public License version 3 - * or later. - * - * See the COPYING-README file. - * - */ - -describe('OCA.External.StatusManager tests', function() { - var notificationStub; - var fileList; - var statusManager; - var oldAppWebRoots; - - beforeEach(function() { - notificationStub = sinon.stub(OC.Notification, 'showTemporary'); - var $content = $('
'); - $('#testArea').append($content); - // dummy file list - var $div = $( - '
' + - '' + - '' + - '' + - '' + - '
' + - '
'); - $('#content').append($div); - - var fileActions = new OCA.Files.FileActions(); - fileList = new OCA.Files.FileList( - $div, { - fileActions : fileActions - } - ); - - fileList.add({ - id: 1, - type: 'folder', - name: 'testmount', - mountType: 'external-root', - path: '/', - mimetype: 'httpd/unix-directory', - size: 12, - permissions: OC.PERMISSION_ALL, - etag: 'abc' - }); - - statusManager = OCA.External.StatusManager; - - oldAppWebRoots = _.extend({}, OC.appswebroots); - OC.appswebroots['files_external'] = OC.webroot + '/apps/files_external'; - }); - afterEach(function() { - statusManager.mountStatus = null; - statusManager.mountPointList = null; - - notificationStub.restore(); - OC.appswebroots = oldAppWebRoots; - }); - - describe('getMountStatusForMount', function() { - beforeEach(function() { - statusManager.mountStatus = []; - }); - - it('retrieves mount status and passes it to callback', function() { - var mountData = { - id: 123, - type: 'smb', - mount_point: 'testmount', - location: 3 - }; - - var callbackStub = sinon.stub(); - statusManager.getMountStatusForMount(mountData, callbackStub); - - expect(fakeServer.requests.length).toEqual(1); - - var mountStatus = { - type: 'smb', - status: 0 - }; - - var jsonData = JSON.stringify(mountStatus); - var request = fakeServer.requests[0]; - - expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages/123'); - - fakeServer.requests[0].respond( - 200, - {'Content-Type': 'application/json'}, - jsonData - ); - - - expect(callbackStub.calledOnce).toEqual(true); - expect(callbackStub.getCall(0).args[0]).toEqual(mountData); - expect(callbackStub.getCall(0).args[1]).toEqual(mountStatus); - - // second call does not send request but returns known data - statusManager.getMountStatusForMount(mountData, callbackStub); - - expect(fakeServer.requests.length).toEqual(1); - - expect(callbackStub.calledTwice).toEqual(true); - expect(callbackStub.getCall(1).args[0]).toEqual(mountData); - expect(callbackStub.getCall(1).args[1]).toEqual(mountStatus); - }); - // TODO: case where status is not 0 - // TODO: error case - }); - describe('getMountPointList', function() { - // TODO - }); - describe('processMountList', function() { - var getActiveViewStub; - var getCurrentAppContainerStub; - - beforeEach(function() { - getActiveViewStub = sinon.stub(OCA.Files.App, 'getActiveView'); - getActiveViewStub.returns('files'); - getCurrentAppContainerStub = sinon.stub(OCA.Files.App, 'getCurrentAppContainer'); - getCurrentAppContainerStub.returns($('#testArea')); - }); - afterEach(function() { - getActiveViewStub.restore(); - getCurrentAppContainerStub.restore(); - }); - - it('updates file list element with status', function() { - var mountList = [{ - id: 123, - mount_point: 'testmount', - backend: 'smb', - backendText: 'SMB', - type: 'system', - status: 0, - location: '' - }]; - statusManager.processMountList(mountList); - - var $tr = fileList.findFileEl('testmount'); - expect($tr.attr('data-external-backend')).toEqual('smb'); - expect($tr.attr('data-icon')).toEqual( - OC.imagePath('windows_network_drive', 'folder-windows') - ); - // TODO: thumbnail URL - /* - expect(OC.TestUtil.getImageUrl($tr.find('.thumbnail'))).toEqual( - OC.imagePath('windows_network_drive', 'folder-windows') - ); - */ - // TODO: check CSS class - - }); - }); - describe('processMountStatus', function() { - // TODO - }); - describe('launchFullConnectivityCheckOneByOne', function() { - var getMountPointListStub; - var getMountStatusStub; - var processMountStatusStub; - var processMountListStub; - - beforeEach(function() { - getMountPointListStub = sinon.stub(statusManager, 'getMountPointList'); - getMountStatusStub = sinon.stub(statusManager, 'getMountStatus'); - processMountStatusStub = sinon.stub(statusManager, 'processMountStatus'); - processMountListStub = sinon.stub(statusManager, 'processMountList'); - }); - afterEach(function() { - getMountPointListStub.restore(); - getMountStatusStub.restore(); - processMountStatusStub.restore(); - processMountListStub.restore(); - }); - it('retrieves mount points then processes them', function() { - statusManager.launchFullConnectivityCheck(); - - expect(getMountPointListStub.calledOnce).toEqual(true); - var mountList = [{ - id: 123, - mount_point: 'testmount', - backend: 'smb', - backendText: 'SMB', - type: 'system', - status: 0, - location: '' - }]; - getMountPointListStub.yield(mountList); - - expect(processMountListStub.calledOnce).toEqual(true); - expect(processMountListStub.calledWith(mountList)).toEqual(true); - - // TODO: continue checking getMountStatus, etc - }); - }); - describe('recheckConnectivityForOne', function() { - // TODO - }); -}); From 19b2fe6a3ab4d9ded3c6974ac109d5d5b02251bb Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 16:48:15 +0100 Subject: [PATCH 22/69] Fix mimetype filter in getDirectoryContent --- lib/private/files/view.php | 8 ++------ tests/lib/files/view.php | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 7854790d0e..6abefff419 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -1427,13 +1427,9 @@ class View { if ($mimetype_filter) { $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) { if (strpos($mimetype_filter, '/')) { - if ($file->getMimetype() === $mimetype_filter) { - $result[] = $file; - } + return $file->getMimetype() === $mimetype_filter; } else { - if ($file->getMimePart() === $mimetype_filter) { - $result[] = $file; - } + return $file->getMimePart() === $mimetype_filter; } }); } diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php index 186cf28d7c..1fc4b9ab68 100644 --- a/tests/lib/files/view.php +++ b/tests/lib/files/view.php @@ -2389,4 +2389,39 @@ class View extends \Test\TestCase { $view = new \OC\Files\View('/' . $this->user . '/files'); $this->assertEquals('foo', $view->rmdir('mount')); } + + public function mimeFilterProvider() { + return [ + [null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']], + ['text/plain', ['test1.txt', 'test2.txt']], + ['text/markdown', ['test3.md']], + ['text', ['test1.txt', 'test2.txt', 'test3.md']], + ]; + } + + /** + * @param string $filter + * @param string[] $expected + * @dataProvider mimeFilterProvider + */ + public function testGetDirectoryContentMimeFilter($filter, $expected) { + $storage1 = new Temporary(); + $root = $this->getUniqueID('/'); + \OC\Files\Filesystem::mount($storage1, array(), $root . '/'); + $view = new \OC\Files\View($root); + + $view->file_put_contents('test1.txt', 'asd'); + $view->file_put_contents('test2.txt', 'asd'); + $view->file_put_contents('test3.md', 'asd'); + $view->file_put_contents('test4.png', ''); + + $content = $view->getDirectoryContent('', $filter); + + $files = array_map(function(FileInfo $info) { + return $info->getName(); + }, $content); + sort($files); + + $this->assertEquals($expected, $files); + } } From cc72c6a30dc12b49dec907cd2fcd01766dbda4c1 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 27 Nov 2015 12:54:31 +0100 Subject: [PATCH 23/69] Added dav endpoints for system tags --- apps/dav/lib/rootcollection.php | 9 + apps/dav/lib/server.php | 3 + .../lib/systemtag/systemtagmappingnode.php | 81 ++++++ apps/dav/lib/systemtag/systemtagnode.php | 112 ++++++++ apps/dav/lib/systemtag/systemtagplugin.php | 241 ++++++++++++++++++ .../systemtag/systemtagsbyidcollection.php | 119 +++++++++ .../systemtagsobjectmappingcollection.php | 160 ++++++++++++ .../systemtagsobjecttypecollection.php | 114 +++++++++ .../systemtagsrelationscollection.php | 50 ++++ .../systemtag/systemtagobjectmapper.php | 4 + 10 files changed, 893 insertions(+) create mode 100644 apps/dav/lib/systemtag/systemtagmappingnode.php create mode 100644 apps/dav/lib/systemtag/systemtagnode.php create mode 100644 apps/dav/lib/systemtag/systemtagplugin.php create mode 100644 apps/dav/lib/systemtag/systemtagsbyidcollection.php create mode 100644 apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php create mode 100644 apps/dav/lib/systemtag/systemtagsobjecttypecollection.php create mode 100644 apps/dav/lib/systemtag/systemtagsrelationscollection.php diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index c1635c9cde..9ee32822bb 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -33,6 +33,13 @@ class RootCollection extends SimpleCollection { $caldavBackend = new CalDavBackend($db); $calendarRoot = new CalendarRoot($principalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; + $systemTagCollection = new SystemTag\SystemTagsByIdCollection( + \OC::$server->getSystemTagManager() + ); + $systemTagRelationsCollection = new SystemTag\SystemTagsRelationsCollection( + \OC::$server->getSystemTagManager(), + \OC::$server->getSystemTagObjectMapper() + ); $usersCardDavBackend = new CardDavBackend($db, $principalBackend); $usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users'); @@ -51,6 +58,8 @@ class RootCollection extends SimpleCollection { new SimpleCollection('addressbooks', [ $usersAddressBookRoot, $systemAddressBookRoot]), + $systemTagCollection, + $systemTagRelationsCollection, ]; parent::__construct('root', $children); diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index a031f2c442..ffcbb02db7 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -60,6 +60,9 @@ class Server { // addressbook plugins $this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin()); + // system tags plugins + $this->server->addPlugin(new \OCA\DAV\SystemTag\SystemTagPlugin(\OC::$server->getSystemTagManager())); + // Finder on OS X requires Class 2 WebDAV support (locking), since we do // not provide locking we emulate it using a fake locking plugin. if($request->isUserAgent(['/WebDAVFS/'])) { diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php new file mode 100644 index 0000000000..97c1afc140 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -0,0 +1,81 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\TagNotFoundException; + +/** + * Mapping node for system tag to object id + */ +class SystemTagMappingNode extends SystemTagNode { + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * @var string + */ + private $objectId; + + /** + * @var string + */ + private $objectType; + + /** + * Sets up the node, expects a full path name + * + * @param ISystemTag $tag system tag + */ + public function __construct( + ISystemTag $tag, + $objectId, + $objectType, + ISystemTagManager $tagManager, + ISystemTagObjectMapper $tagMapper + ) { + $this->objectId = $objectId; + $this->objectType = $objectType; + $this->tagMapper = $tagMapper; + parent::__construct($tag, $tagManager); + } + + /** + * Delete tag to object association + */ + public function delete() { + try { + $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId()); + } catch (TagNotFoundException $e) { + // can happen if concurrent deletion occurred + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); + } + } +} diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php new file mode 100644 index 0000000000..e425595352 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -0,0 +1,112 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\TagNotFoundException; + +class SystemTagNode implements \Sabre\DAV\INode { + + /** + * @var ISystemTag + */ + protected $tag; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * Sets up the node, expects a full path name + * + * @param ISystemTag $tag system tag + */ + public function __construct(ISystemTag $tag, ISystemTagManager $tagManager) { + $this->tag = $tag; + $this->tagManager = $tagManager; + } + + /** + * Returns the id of the tag + * + * @return string + */ + public function getName() { + return $this->tag->getId(); + } + + /** + * Returns the system tag represented by this node + * + * @return ISystemTag system tag + */ + public function getSystemTag() { + return $this->tag; + } + + /** + * Renames the node + * + * @param string $name The new name + * + * @throws \Sabre\DAV\Exception\MethodNotAllowed + */ + public function setName($name) { + throw new MethodNotAllowed(); + } + + /** + * @param string $name new tag name + * @param bool $userVisible user visible + * @param bool $userAssignable user assignable + */ + public function update($name, $userVisible, $userAssignable) { + try { + $this->tagManager->updateTag($name, $userVisible, $userAssignable); + } catch (TagAlreadyExistsException $e) { + throw new Conflict('Tag with the properties "' . $name . '", ' . $userVisible, ', ' . $userAssignable . ' already exists'); + } + } + + /** + * Returns null, not supported + * + */ + public function getLastModified() { + return null; + } + + public function delete() { + try { + $this->tagManager->deleteTags($this->tag->getId()); + } catch (TagNotFoundException $e) { + // can happen if concurrent deletion occurred + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); + } + } +} diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php new file mode 100644 index 0000000000..c213640964 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -0,0 +1,241 @@ + + * + * @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 + * + */ +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\UnsupportedMediaType; +use Sabre\DAV\Exception\Conflict; + +use OCA\DAV\SystemTag\SystemTagNode; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { + + // namespace + const NS_OWNCLOUD = 'http://owncloud.org/ns'; + const ID_PROPERTYNAME = '{http://owncloud.org/ns}id'; + const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name'; + const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible'; + const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable'; + + /** + * @var \Sabre\DAV\Server $server + */ + private $server; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * System tags plugin + * + * @param ISystemTagManager $tagManager tag manager + */ + public function __construct(ISystemTagManager $tagManager) { + $this->tagManager = $tagManager; + } + + /** + * This initializes the plugin. + * + * This function is called by \Sabre\DAV\Server, after + * addPlugin is called. + * + * This method should set up the required event subscriptions. + * + * @param \Sabre\DAV\Server $server + * @return void + */ + public function initialize(\Sabre\DAV\Server $server) { + + $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; + + $server->protectedProperties[] = self::ID_PROPERTYNAME; + + $server->on('propFind', array($this, 'handleGetProperties')); + $server->on('propPatch', array($this, 'handleUpdateProperties')); + $server->on('method:POST', [$this, 'httpPost']); + + $this->server = $server; + } + + /** + * We intercept this to handle POST requests on calendars. + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return null|false + */ + function httpPost(RequestInterface $request, ResponseInterface $response) { + $path = $request->getPath(); + + // Making sure the node exists + try { + $node = $this->server->tree->getNodeForPath($path); + } catch (NotFound $e) { + return; + } + + if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) { + $data = $request->getBodyAsString(); + + $tag = $this->createTag($data, $request->getHeader('Content-Type')); + + if ($node instanceof SystemTagsObjectMappingCollection) { + // also add to collection + $node->createFile($tag->getId()); + $url = $request->getBaseUrl() . 'systemtags/'; + } else { + $url = $request->getUrl(); + } + + if ($url[strlen($url) - 1] !== '/') { + $url .= '/'; + } + + $response->setHeader('Location', $url . $tag->getId()); + + // created + $response->setStatus(201); + return false; + } + } + + /** + * Creates a new tag + * + * @param string $data + * @param string $contentType content type of the data + * + * @return ISystemTag newly created system tag + * + * @throws UnsupportedMediaType if the content type is not supported + * @throws BadRequest if a field was missing + */ + private function createTag($data, $contentType = 'application/json') { + if ($contentType === 'application/json') { + $data = json_decode($data, true); + // TODO: application/x-www-form-urlencoded ? + } else { + throw new UnsupportedMediaType(); + } + + if (!isset($data['name'])) { + throw new BadRequest('Missing "name" attribute'); + } + + $tagName = $data['name']; + $userVisible = true; + $userAssignable = true; + + if (isset($data['userVisible'])) { + $userVisible = (bool)$data['userVisible']; + } + + if (isset($data['userAssignable'])) { + $userVisible = (bool)$data['userAssignable']; + } + try { + return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); + } catch (TagAlreadyExistsException $e) { + throw new Conflict('Tag already exists'); + } + } + + + /** + * Retrieves system tag properties + * + * @param PropFind $propFind + * @param \Sabre\DAV\INode $node + */ + public function handleGetProperties( + PropFind $propFind, + \Sabre\DAV\INode $node + ) { + if (!($node instanceof SystemTagNode)) { + return; + } + + $propFind->handle(self::ID_PROPERTYNAME, function() use ($node) { + return $node->getSystemTag()->getId(); + }); + + $propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function() use ($node) { + return $node->getSystemTag()->getName(); + }); + + $propFind->handle(self::USERVISIBLE_PROPERTYNAME, function() use ($node) { + return (int)$node->getSystemTag()->isUserVisible(); + }); + + $propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) { + return (int)$node->getSystemTag()->isUserAssignable(); + }); + } + + /** + * Updates tag attributes + * + * @param string $path + * @param PropPatch $propPatch + * + * @return void + */ + public function handleUpdateProperties($path, PropPatch $propPatch) { + $propPatch->handle([ + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME, + ], function($props) use ($path) { + $node = $this->tree->getNodeForPath($path); + if (!($node instanceof SystemTagNode)) { + return; + } + + $tag = $node->getTag(); + $name = $tag->getName(); + $userVisible = $tag->getUserVisible(); + $userAssignable = $tag->getUserAssignable(); + + if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) { + $name = $props[self::DISPLAYNAME_PROPERTYNAME]; + } + + if (isset($props[self::USERVISIBLE_PROPERTYNAME])) { + $userVisible = (bool)$props[self::USERVISIBLE_PROPERTYNAME]; + } + + if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) { + $userAssignable = (bool)$props[self::USERASSIGNABLE_PROPERTYNAME]; + } + + $node->update($name, $userVisible, $userAssignable); + return true; + }); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php new file mode 100644 index 0000000000..8643ffedd4 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -0,0 +1,119 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; +use OC\SystemTag\SystemTag; + +class SystemTagsByIdCollection implements ICollection { + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * SystemTagsByIdCollection constructor. + * + * @param ISystemTagManager $tagManager + */ + public function __construct($tagManager) { + $this->tagManager = $tagManager; + } + + function createFile($name, $data = null) { + throw new Forbidden('Cannot create tags by id'); + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($name) { + try { + $tags = $this->tagManager->getTagsById($name); + return $this->makeNode(current($tags)); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $name . ' not found', 0, $e); + } + } + + function getChildren() { + // TODO: set visibility filter based on principal/permissions ? + $tags = $this->tagManager->getAllTags(true); + return array_map(function($tag) { + return $this->makeNode($tag); + }, $tags); + } + + function childExists($name) { + try { + $this->tagManager->getTagsById($name); + return true; + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + return false; + } + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return 'systemtags'; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } + + /** + * Create a sabre node for the given system tag + * + * @param ISystemTag $tag + * + * @return SystemTagNode + */ + private function makeNode(ISystemTag $tag) { + return new SystemTagNode($tag, $this->tagManager); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php new file mode 100644 index 0000000000..a0a71306f9 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -0,0 +1,160 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; +use OC\SystemTag\SystemTag; + +/** + * Collection containing tags by object id + */ +class SystemTagsObjectMappingCollection implements ICollection { + + /** + * @var string + */ + private $objectId; + + /** + * @var string + */ + private $objectType; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * Constructor + * + * @param string $objectId object id + * @param string $objectType object type + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($objectId, $objectType, $tagManager, $tagMapper) { + $this->tagManager = $tagManager; + $this->tagMapper = $tagMapper; + $this->objectId = $objectId; + $this->objectType = $objectType; + } + + function createFile($tagId, $data = null) { + try { + $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); + } catch (TagNotFoundException $e) { + throw new Forbidden('Tag with id ' . $tagId . ' does not exist, cannot assign'); + } + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($tagId) { + try { + if ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)) { + $tag = $this->tagManager->getTagsById($tagId); + return $this->makeNode(current($tag)); + } + throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + } + } + + function getChildren() { + $tagIds = current($this->tagMapper->getTagIdsForObjects($this->objectId, $this->objectType)); + if (empty($tagIds)) { + return []; + } + $tags = $this->tagManager->getTagsById($tagIds); + return array_map(function($tag) { + return $this->makeNode($tag); + }, $tags); + } + + function childExists($tagId) { + try { + return ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + } + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return $this->objectId; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } + + /** + * Create a sabre node for the given system tag + * + * @param ISystemTag $tag + * + * @return SystemTagNode + */ + private function makeNode(ISystemTag $tag) { + return new SystemTagMappingNode( + $tag, + $this->objectId, + $this->objectType, + $this->tagManager, + $this->tagMapper + ); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php new file mode 100644 index 0000000000..c90e4fd2d8 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -0,0 +1,114 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; +use OC\SystemTag\SystemTag; + +/** + * Collection containing object ids by object type + */ +class SystemTagsObjectTypeCollection implements ICollection { + + /** + * @var string + */ + private $objectType; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * Constructor + * + * @param string $objectType object type + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($objectType, $tagManager, $tagMapper) { + $this->tagManager = $tagManager; + $this->tagMapper = $tagMapper; + $this->objectType = $objectType; + } + + function createFile($name, $data = null) { + throw new Forbidden('Permission denied to create collections'); + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($objectId) { + return new SystemTagsObjectMappingCollection( + $objectId, + $this->objectType, + $this->tagManager, + $this->tagMapper + ); + } + + function getChildren() { + // do not list object ids + throw new MethodNotAllowed(); + } + + function childExists($name) { + return true; + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return $this->objectType; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } +} diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php new file mode 100644 index 0000000000..4bcb6882a4 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php @@ -0,0 +1,50 @@ + + * + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\SimpleCollection; + +class SystemTagsRelationsCollection extends SimpleCollection { + + /** + * SystemTagsRelationsCollection constructor. + * + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($tagManager, $tagMapper) { + $children = [ + new SystemTagsObjectTypeCollection('files', $tagManager, $tagMapper), + ]; + + parent::__construct('root', $children); + } + + function getName() { + return 'systemtags-relations'; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + +} diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php index 75f2631a01..bb64a35456 100644 --- a/lib/private/systemtag/systemtagobjectmapper.php +++ b/lib/private/systemtag/systemtagobjectmapper.php @@ -171,6 +171,10 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { public function haveTag($objIds, $objectType, $tagId, $all = true) { $this->assertTagsExist([$tagId]); + if (!is_array($objIds)) { + $objIds = [$objIds]; + } + $query = $this->connection->getQueryBuilder(); if (!$all) { From 502e454a6902c51d6756d606061a1a9092946c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 2 Dec 2015 21:17:03 +0100 Subject: [PATCH 24/69] Fix PHPDoc ... --- .../dav/lib/systemtag/systemtagmappingnode.php | 5 ++++- apps/dav/lib/systemtag/systemtagnode.php | 3 +++ apps/dav/lib/systemtag/systemtagplugin.php | 18 ++++++++++-------- .../lib/systemtag/systemtagsbyidcollection.php | 1 - .../systemtagsobjectmappingcollection.php | 2 -- .../systemtagsobjecttypecollection.php | 4 ---- .../systemtagsrelationscollection.php | 3 +++ 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php index 97c1afc140..03088d734d 100644 --- a/apps/dav/lib/systemtag/systemtagmappingnode.php +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -22,7 +22,6 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\MethodNotAllowed; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; @@ -53,6 +52,10 @@ class SystemTagMappingNode extends SystemTagNode { * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag + * @param string $objectId + * @param string $objectType + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper */ public function __construct( ISystemTag $tag, diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index e425595352..b09a773793 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -21,6 +21,7 @@ namespace OCA\DAV\SystemTag; +use OCP\SystemTag\TagAlreadyExistsException; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\Conflict; @@ -45,6 +46,7 @@ class SystemTagNode implements \Sabre\DAV\INode { * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag + * @param ISystemTagManager $tagManager */ public function __construct(ISystemTag $tag, ISystemTagManager $tagManager) { $this->tag = $tag; @@ -84,6 +86,7 @@ class SystemTagNode implements \Sabre\DAV\INode { * @param string $name new tag name * @param bool $userVisible user visible * @param bool $userAssignable user assignable + * @throws Conflict */ public function update($name, $userVisible, $userAssignable) { try { diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php index c213640964..d5591c2849 100644 --- a/apps/dav/lib/systemtag/systemtagplugin.php +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -20,16 +20,18 @@ */ namespace OCA\DAV\SystemTag; +use Sabre\DAV\Exception\NotFound; use Sabre\DAV\PropFind; use Sabre\DAV\PropPatch; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Exception\UnsupportedMediaType; use Sabre\DAV\Exception\Conflict; -use OCA\DAV\SystemTag\SystemTagNode; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagAlreadyExistsException; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { @@ -72,7 +74,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { */ public function initialize(\Sabre\DAV\Server $server) { - $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; + $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; $server->protectedProperties[] = self::ID_PROPERTYNAME; @@ -130,11 +132,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { * * @param string $data * @param string $contentType content type of the data - * * @return ISystemTag newly created system tag * - * @throws UnsupportedMediaType if the content type is not supported * @throws BadRequest if a field was missing + * @throws Conflict + * @throws UnsupportedMediaType if the content type is not supported */ private function createTag($data, $contentType = 'application/json') { if ($contentType === 'application/json') { @@ -212,15 +214,15 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { self::USERVISIBLE_PROPERTYNAME, self::USERASSIGNABLE_PROPERTYNAME, ], function($props) use ($path) { - $node = $this->tree->getNodeForPath($path); + $node = $this->server->tree->getNodeForPath($path); if (!($node instanceof SystemTagNode)) { return; } - $tag = $node->getTag(); + $tag = $node->getSystemTag(); $name = $tag->getName(); - $userVisible = $tag->getUserVisible(); - $userAssignable = $tag->getUserAssignable(); + $userVisible = $tag->isUserVisible(); + $userAssignable = $tag->isUserAssignable(); if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) { $name = $props[self::DISPLAYNAME_PROPERTYNAME]; diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php index 8643ffedd4..0164b9b0b3 100644 --- a/apps/dav/lib/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -29,7 +29,6 @@ use Sabre\DAV\ICollection; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\TagNotFoundException; -use OC\SystemTag\SystemTag; class SystemTagsByIdCollection implements ICollection { diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index a0a71306f9..6ed959fd88 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -23,7 +23,6 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\ICollection; @@ -31,7 +30,6 @@ use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\TagNotFoundException; -use OC\SystemTag\SystemTag; /** * Collection containing tags by object id diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php index c90e4fd2d8..8dee85ccd4 100644 --- a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -22,15 +22,11 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\ICollection; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; -use OCP\SystemTag\ISystemTag; -use OCP\SystemTag\TagNotFoundException; -use OC\SystemTag\SystemTag; /** * Collection containing object ids by object type diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php index 4bcb6882a4..44069bca02 100644 --- a/apps/dav/lib/systemtag/systemtagsrelationscollection.php +++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php @@ -21,6 +21,9 @@ namespace OCA\DAV\SystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\SimpleCollection; class SystemTagsRelationsCollection extends SimpleCollection { From fe95fd5bec5e4b52112ab68cff0d942bb8ffb226 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 3 Dec 2015 11:26:16 +0100 Subject: [PATCH 25/69] Unit test for system tags plugin --- .../lib/systemtag/systemtagmappingnode.php | 18 + apps/dav/lib/systemtag/systemtagnode.php | 18 +- apps/dav/lib/systemtag/systemtagplugin.php | 10 +- .../systemtagsobjectmappingcollection.php | 9 +- .../unit/systemtag/systemtagmappingnode.php | 84 +++++ .../tests/unit/systemtag/systemtagnode.php | 103 ++++++ .../tests/unit/systemtag/systemtagplugin.php | 308 ++++++++++++++++++ .../systemtag/systemtagsbyidcollection.php | 147 +++++++++ .../systemtagsobjectmappingcollection.php | 215 ++++++++++++ .../systemtagsobjecttypecollection.php | 90 +++++ 10 files changed, 988 insertions(+), 14 deletions(-) create mode 100644 apps/dav/tests/unit/systemtag/systemtagmappingnode.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagnode.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagplugin.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php index 03088d734d..cbf8542a4f 100644 --- a/apps/dav/lib/systemtag/systemtagmappingnode.php +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -70,6 +70,24 @@ class SystemTagMappingNode extends SystemTagNode { parent::__construct($tag, $tagManager); } + /** + * Returns the object id of the relationship + * + * @return string object id + */ + public function getObjectId() { + return $this->objectId; + } + + /** + * Returns the object type of the relationship + * + * @return string object type + */ + public function getObjectType() { + return $this->objectType; + } + /** * Delete tag to object association */ diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index b09a773793..f7228108b3 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -21,7 +21,6 @@ namespace OCA\DAV\SystemTag; -use OCP\SystemTag\TagAlreadyExistsException; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\Conflict; @@ -29,6 +28,7 @@ use Sabre\DAV\Exception\Conflict; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; class SystemTagNode implements \Sabre\DAV\INode { @@ -76,23 +76,31 @@ class SystemTagNode implements \Sabre\DAV\INode { * * @param string $name The new name * - * @throws \Sabre\DAV\Exception\MethodNotAllowed + * @throws MethodNotAllowed not allowed to rename node */ public function setName($name) { throw new MethodNotAllowed(); } /** + * Update tag + * * @param string $name new tag name * @param bool $userVisible user visible * @param bool $userAssignable user assignable - * @throws Conflict + * @throws NotFound whenever the given tag id does not exist + * @throws Conflict whenever a tag already exists with the given attributes */ public function update($name, $userVisible, $userAssignable) { try { - $this->tagManager->updateTag($name, $userVisible, $userAssignable); + $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); } catch (TagAlreadyExistsException $e) { - throw new Conflict('Tag with the properties "' . $name . '", ' . $userVisible, ', ' . $userAssignable . ' already exists'); + throw new Conflict( + 'Tag with the properties "' . $name . '", ' . + $userVisible . ', ' . $userAssignable . ' already exists' + ); } } diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php index d5591c2849..692b7e9701 100644 --- a/apps/dav/lib/systemtag/systemtagplugin.php +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -88,18 +88,18 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { /** * We intercept this to handle POST requests on calendars. * - * @param RequestInterface $request - * @param ResponseInterface $response + * @param RequestInterface $request request object + * @param ResponseInterface $response response object * @return null|false */ - function httpPost(RequestInterface $request, ResponseInterface $response) { + public function httpPost(RequestInterface $request, ResponseInterface $response) { $path = $request->getPath(); // Making sure the node exists try { $node = $this->server->tree->getNodeForPath($path); } catch (NotFound $e) { - return; + return null; } if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) { @@ -159,7 +159,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { } if (isset($data['userAssignable'])) { - $userVisible = (bool)$data['userAssignable']; + $userAssignable = (bool)$data['userAssignable']; } try { return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index 6ed959fd88..e81994e0bd 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -24,6 +24,7 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\PreconditionFailed; use Sabre\DAV\ICollection; use OCP\SystemTag\ISystemTagManager; @@ -75,7 +76,7 @@ class SystemTagsObjectMappingCollection implements ICollection { try { $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); } catch (TagNotFoundException $e) { - throw new Forbidden('Tag with id ' . $tagId . ' does not exist, cannot assign'); + throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); } } @@ -103,9 +104,9 @@ class SystemTagsObjectMappingCollection implements ICollection { return []; } $tags = $this->tagManager->getTagsById($tagIds); - return array_map(function($tag) { + return array_values(array_map(function($tag) { return $this->makeNode($tag); - }, $tags); + }, $tags)); } function childExists($tagId) { @@ -114,7 +115,7 @@ class SystemTagsObjectMappingCollection implements ICollection { } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { - throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + return false; } } diff --git a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php new file mode 100644 index 0000000000..849f7c2fa5 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php @@ -0,0 +1,84 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagMappingNode extends SystemTagNode { + + /** + * @var \OCA\DAV\SystemTag\SystemTagMappingNode + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * @var \OCP\SystemTag\ISystemTag + */ + private $tag; + + protected function setUp() { + parent::setUp(); + + $this->tag = new SystemTag(1, 'Test', true, false); + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagMappingNode( + $this->tag, + 123, + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + public function testGetters() { + parent::testGetters(); + $this->assertEquals(123, $this->node->getObjectId()); + $this->assertEquals('files', $this->node->getObjectType()); + } + + public function testDeleteTag() { + $this->tagManager->expects($this->never()) + ->method('deleteTags'); + $this->tagMapper->expects($this->once()) + ->method('unassignTags') + ->with(123, 'files', 1); + + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testDeleteTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('unassignTags') + ->with(123, 'files', 1) + ->will($this->throwException(new TagNotFoundException())); + + $this->node->delete(); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagnode.php b/apps/dav/tests/unit/systemtag/systemtagnode.php new file mode 100644 index 0000000000..a43dda3025 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagnode.php @@ -0,0 +1,103 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagNode extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagNode + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTag + */ + private $tag; + + protected function setUp() { + parent::setUp(); + + $this->tag = new SystemTag(1, 'Test', true, false); + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagNode($this->tag, $this->tagManager); + } + + public function testGetters() { + $this->assertEquals('1', $this->node->getName()); + $this->assertEquals($this->tag, $this->node->getSystemTag()); + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testSetName() { + $this->node->setName('2'); + } + + public function testUpdateTag() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true); + $this->node->update('Renamed', false, true); + } + + /** + * @expectedException Sabre\DAV\Exception\Conflict + */ + public function testUpdateTagAlreadyExists() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true) + ->will($this->throwException(new TagAlreadyExistsException())); + $this->node->update('Renamed', false, true); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testUpdateTagNotFound() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true) + ->will($this->throwException(new TagNotFoundException())); + $this->node->update('Renamed', false, true); + } + + public function testDeleteTag() { + $this->tagManager->expects($this->once()) + ->method('deleteTags') + ->with('1'); + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testDeleteTagNotFound() { + $this->tagManager->expects($this->once()) + ->method('deleteTags') + ->with('1') + ->will($this->throwException(new TagNotFoundException())); + $this->node->delete(); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagplugin.php b/apps/dav/tests/unit/systemtag/systemtagplugin.php new file mode 100644 index 0000000000..48c9aa69f7 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagplugin.php @@ -0,0 +1,308 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagPlugin extends \Test\TestCase { + + const ID_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::ID_PROPERTYNAME; + const DISPLAYNAME_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::DISPLAYNAME_PROPERTYNAME; + const USERVISIBLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERVISIBLE_PROPERTYNAME; + const USERASSIGNABLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERASSIGNABLE_PROPERTYNAME; + + /** + * @var \Sabre\DAV\Server + */ + private $server; + + /** + * @var \Sabre\DAV\Tree + */ + private $tree; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCA\DAV\Connector\Sabre\TagsPlugin + */ + private $plugin; + + public function setUp() { + parent::setUp(); + $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree') + ->disableOriginalConstructor() + ->getMock(); + + $this->server = new \Sabre\DAV\Server($this->tree); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->plugin = new \OCA\DAV\SystemTag\SystemTagPlugin($this->tagManager); + $this->plugin->initialize($this->server); + } + + public function testGetProperties() { + $systemTag = new SystemTag(1, 'Test', true, true); + $requestedProperties = [ + self::ID_PROPERTYNAME, + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME + ]; + $expectedProperties = [ + 200 => [ + self::ID_PROPERTYNAME => '1', + self::DISPLAYNAME_PROPERTYNAME => 'Test', + self::USERVISIBLE_PROPERTYNAME => 1, + self::USERASSIGNABLE_PROPERTYNAME => 1, + ] + ]; + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtag/1') + ->will($this->returnValue($node)); + + $propFind = new \Sabre\DAV\PropFind( + '/systemtag/1', + $requestedProperties, + 0 + ); + + $this->plugin->handleGetProperties( + $propFind, + $node + ); + + $result = $propFind->getResultForMultiStatus(); + + $this->assertEmpty($result[404]); + unset($result[404]); + $this->assertEquals($expectedProperties, $result); + } + + public function testUpdateProperties() { + $systemTag = new SystemTag(1, 'Test', true, false); + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtag/1') + ->will($this->returnValue($node)); + + $node->expects($this->once()) + ->method('update') + ->with('Test changed', false, true); + + // properties to set + $propPatch = new \Sabre\DAV\PropPatch(array( + self::DISPLAYNAME_PROPERTYNAME => 'Test changed', + self::USERVISIBLE_PROPERTYNAME => 0, + self::USERASSIGNABLE_PROPERTYNAME => 1, + )); + + $this->plugin->handleUpdateProperties( + '/systemtag/1', + $propPatch + ); + + $propPatch->commit(); + + // all requested properties removed, as they were processed already + $this->assertEmpty($propPatch->getRemainingMutations()); + + $result = $propPatch->getResult(); + $this->assertEquals(200, $result[self::DISPLAYNAME_PROPERTYNAME]); + $this->assertEquals(200, $result[self::USERASSIGNABLE_PROPERTYNAME]); + $this->assertEquals(200, $result[self::USERVISIBLE_PROPERTYNAME]); + } + + public function testCreateTagInByIdCollection() { + $systemTag = new SystemTag(1, 'Test', true, false); + + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection') + ->disableOriginalConstructor() + ->getMock(); + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags') + ->will($this->returnValue($node)); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $request->expects($this->once()) + ->method('getUrl') + ->will($this->returnValue('http://example.com/dav/systemtags')); + + $response->expects($this->once()) + ->method('setHeader') + ->with('Location', 'http://example.com/dav/systemtags/1'); + + $this->plugin->httpPost($request, $response); + } + + public function nodeClassProvider() { + return [ + ['\OCA\DAV\SystemTag\SystemTagsByIdCollection'], + ['\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection'], + ]; + } + + public function testCreateTagInMappingCollection() { + $systemTag = new SystemTag(1, 'Test', true, false); + + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection') + ->disableOriginalConstructor() + ->getMock(); + + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags-relations/files/12') + ->will($this->returnValue($node)); + + $node->expects($this->once()) + ->method('createFile') + ->with(1); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags-relations/files/12')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $request->expects($this->once()) + ->method('getBaseUrl') + ->will($this->returnValue('http://example.com/dav/')); + + $response->expects($this->once()) + ->method('setHeader') + ->with('Location', 'http://example.com/dav/systemtags/1'); + + $this->plugin->httpPost($request, $response); + } + + /** + * @dataProvider nodeClassProvider + * @expectedException Sabre\DAV\Exception\Conflict + */ + public function testCreateTagConflict($nodeClass) { + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder($nodeClass) + ->disableOriginalConstructor() + ->getMock(); + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->throwException(new TagAlreadyExistsException('Tag already exists'))); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags') + ->will($this->returnValue($node)); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $this->plugin->httpPost($request, $response); + } + +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php new file mode 100644 index 0000000000..fdaaf2cd00 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -0,0 +1,147 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagsByIdCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsByIdCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsByIdCollection($this->tagManager); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateFile() { + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $tag = new SystemTag(123, 'Test', true, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('123') + ->will($this->returnValue([$tag])); + + $childNode = $this->node->getChild('123'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertEquals('123', $childNode->getName()); + $this->assertEquals($tag, $childNode->getSystemTag()); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testGetChildInvalidName() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('invalid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->getChild('invalid'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildNotFound() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('444') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->getChild('444'); + } + + public function testGetChildren() { + $tag1 = new SystemTag(123, 'One', true, false); + $tag2 = new SystemTag(456, 'Two', true, true); + + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(true) + ->will($this->returnValue([$tag1, $tag2])); + + $children = $this->node->getChildren(); + + $this->assertCount(2, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]); + $this->assertEquals($tag1, $children[0]->getSystemTag()); + $this->assertEquals($tag2, $children[1]->getSystemTag()); + } + + public function testGetChildrenEmpty() { + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(true) + ->will($this->returnValue([])); + $this->assertCount(0, $this->node->getChildren()); + } + + public function testChildExists() { + $tag = new SystemTag(123, 'One', true, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('123') + ->will($this->returnValue([$tag])); + + $this->assertTrue($this->node->childExists('123')); + } + + public function testChildExistsNotFound() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('123') + ->will($this->throwException(new TagNotFoundException())); + + $this->assertFalse($this->node->childExists('123')); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testChildExistsBadRequest() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('invalid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->childExists('invalid'); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php new file mode 100644 index 0000000000..1a9ffa6f4a --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -0,0 +1,215 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagsObjectMappingCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagMapper + */ + private $tagMapper; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection ( + 111, + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + public function testAssignTag() { + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555'); + + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + public function testAssignTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $tag = new SystemTag(555, 'TheTag', true, false); + + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555', true) + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('555') + ->will($this->returnValue([$tag])); + + $childNode = $this->node->getChild('555'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertEquals('555', $childNode->getName()); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildRelationNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '777') + ->will($this->returnValue(false)); + + $this->node->getChild('777'); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testGetChildInvalidId() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', 'badid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->getChild('badid'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildTagDoesNotExist() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '777') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->getChild('777'); + } + + public function testGetChildren() { + $tag1 = new SystemTag(555, 'TagOne', true, false); + $tag2 = new SystemTag(556, 'TagTwo', true, true); + + $this->tagMapper->expects($this->once()) + ->method('getTagIdsForObjects') + ->with(111, 'files') + ->will($this->returnValue(['111' => ['555', '556']])); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with(['555', '556']) + ->will($this->returnValue(['555' => $tag1, '666' => $tag2])); + + $children = $this->node->getChildren(); + + $this->assertCount(2, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]); + + $this->assertEquals(111, $children[0]->getObjectId()); + $this->assertEquals('files', $children[0]->getObjectType()); + $this->assertEquals($tag1, $children[0]->getSystemTag()); + + $this->assertEquals(111, $children[1]->getObjectId()); + $this->assertEquals('files', $children[1]->getObjectType()); + $this->assertEquals($tag2, $children[1]->getSystemTag()); + } + + public function testChildExists() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->returnValue(true)); + + $this->assertTrue($this->node->childExists('555')); + } + + public function testChildExistsNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->returnValue(false)); + + $this->assertFalse($this->node->childExists('555')); + } + + public function testChildExistsTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->throwException(new TagNotFoundException())); + + $this->assertFalse($this->node->childExists('555')); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testChildExistsInvalidId() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->childExists('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + $this->node->setName('somethingelse'); + } + + public function testGetName() { + $this->assertEquals('111', $this->node->getName()); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php new file mode 100644 index 0000000000..39223ff912 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php @@ -0,0 +1,90 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +class SystemTagsObjectTypeCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagMapper + */ + private $tagMapper; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection( + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateFile() { + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $childNode = $this->node->getChild('files'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection', $childNode); + $this->assertEquals('files', $childNode->getName()); + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testGetChildren() { + $this->node->getChildren(); + } + + public function testChildExists() { + $this->assertTrue($this->node->childExists('123')); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + $this->node->setName('somethingelse'); + } + + public function testGetName() { + $this->assertEquals('files', $this->node->getName()); + } +} From 11d8b336e2fdf5ce3893c66059c2cd2d11a81d13 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Fri, 4 Dec 2015 12:10:08 +0100 Subject: [PATCH 26/69] [Sharing] Properly check if a group already has access The old code check was to liberal resulting in wrong matches if a user with the same name as the group already had access. Fixes 20892 --- lib/private/share/share.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 70f9a6e892..8899df2563 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -745,10 +745,8 @@ class Share extends Constants { // The check for each user in the group is done inside the put() function if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) { - // Only allow the same share to occur again if it is the same - // owner and is not a group share, this use case is for increasing - // permissions for a specific user - if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) { + + if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) { $message = 'Sharing %s failed, because this item is already shared with %s'; $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith)); \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG); From 48a91164e5e63e3c1ef2c14b54337dbf19ed7d04 Mon Sep 17 00:00:00 2001 From: Sergio Bertolin Date: Fri, 4 Dec 2015 12:43:08 +0000 Subject: [PATCH 27/69] Controlled arguments for run script --- build/integration/run.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build/integration/run.sh b/build/integration/run.sh index 76c01068de..23f71f83ff 100755 --- a/build/integration/run.sh +++ b/build/integration/run.sh @@ -2,6 +2,9 @@ composer install +SCENARIO_TO_RUN=$1 +HIDE_OC_LOGS=$2 + # avoid port collision on jenkins - use $EXECUTOR_NUMBER if [ -z "$EXECUTOR_NUMBER" ]; then EXECUTOR_NUMBER=0 @@ -27,7 +30,9 @@ RESULT=$? kill $PHPPID kill $PHPPID_FED -tail "../../data/owncloud.log" +if [ -z $HIDE_OC_LOGS ]; then + tail "../../data/owncloud.log" +fi exit $RESULT From 5cca471e82e1c77a0d3a831ffb5deb11f98f9640 Mon Sep 17 00:00:00 2001 From: Sergio Bertolin Date: Fri, 4 Dec 2015 12:53:11 +0000 Subject: [PATCH 28/69] forgotten variable --- build/integration/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/integration/run.sh b/build/integration/run.sh index 23f71f83ff..5a222bda3e 100755 --- a/build/integration/run.sh +++ b/build/integration/run.sh @@ -24,7 +24,7 @@ echo $PHPPID_FED export TEST_SERVER_URL="http://localhost:$PORT/ocs/" export TEST_SERVER_FED_URL="http://localhost:$PORT_FED/ocs/" -vendor/bin/behat -f junit -f pretty $1 +vendor/bin/behat -f junit -f pretty $SCENARIO_TO_RUN RESULT=$? kill $PHPPID From a619629ac0e026fa938b45eeb82ea2a7ebe35aa2 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Fri, 4 Dec 2015 14:30:12 +0100 Subject: [PATCH 29/69] Only try to load avatars in the user list if there is any --- settings/application.php | 3 +- settings/controller/userscontroller.php | 14 ++++- .../controller/userscontrollertest.php | 60 +++++++++++++++---- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/settings/application.php b/settings/application.php index f9ee0121db..729e61b592 100644 --- a/settings/application.php +++ b/settings/application.php @@ -136,7 +136,8 @@ class Application extends App { $c->query('Mailer'), $c->query('DefaultMailAddress'), $c->query('URLGenerator'), - $c->query('OCP\\App\\IAppManager') + $c->query('OCP\\App\\IAppManager'), + $c->query('OCP\\IAvatarManager') ); }); $container->registerService('LogSettingsController', function(IContainer $c) { diff --git a/settings/controller/userscontroller.php b/settings/controller/userscontroller.php index 827f74c4c8..0164d3bcee 100644 --- a/settings/controller/userscontroller.php +++ b/settings/controller/userscontroller.php @@ -43,6 +43,7 @@ use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; use OCP\Mail\IMailer; +use OCP\IAvatarManager; /** * @package OC\Settings\Controller @@ -74,6 +75,8 @@ class UsersController extends Controller { private $isEncryptionAppEnabled; /** @var bool contains the state of the admin recovery setting */ private $isRestoreEnabled = false; + /** @var IAvatarManager */ + private $avatarManager; /** * @param string $appName @@ -104,7 +107,8 @@ class UsersController extends Controller { IMailer $mailer, $fromMailAddress, IURLGenerator $urlGenerator, - IAppManager $appManager) { + IAppManager $appManager, + IAvatarManager $avatarManager) { parent::__construct($appName, $request); $this->userManager = $userManager; $this->groupManager = $groupManager; @@ -117,6 +121,7 @@ class UsersController extends Controller { $this->mailer = $mailer; $this->fromMailAddress = $fromMailAddress; $this->urlGenerator = $urlGenerator; + $this->avatarManager = $avatarManager; // check for encryption state - TODO see formatUserForIndex $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption'); @@ -168,6 +173,12 @@ class UsersController extends Controller { if (is_null($displayName)) { $displayName = ''; } + + $avatarAvailable = false; + if ($this->config->getSystemValue('enable_avatars', true) === true) { + $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists(); + } + return [ 'name' => $user->getUID(), 'displayname' => $user->getDisplayName(), @@ -179,6 +190,7 @@ class UsersController extends Controller { 'backend' => $user->getBackendClassName(), 'email' => $displayName, 'isRestoreDisabled' => !$restorePossible, + 'isAvatarAvailable' => $avatarAvailable, ]; } diff --git a/tests/settings/controller/userscontrollertest.php b/tests/settings/controller/userscontrollertest.php index b52d6c66aa..e1e3c4d4b6 100644 --- a/tests/settings/controller/userscontrollertest.php +++ b/tests/settings/controller/userscontrollertest.php @@ -54,6 +54,30 @@ class UsersControllerTest extends \Test\TestCase { ->disableOriginalConstructor()->getMock(); $this->container['OCP\\App\\IAppManager'] = $this->getMockBuilder('OCP\\App\\IAppManager') ->disableOriginalConstructor()->getMock(); + + + /* + * Set default avtar behaviour for whole testsuite + */ + $this->container['OCP\\IAvatarManager'] = $this->getMock('OCP\IAvatarManager'); + + $avatarExists = $this->getMock('OCP\IAvatar'); + $avatarExists->method('exists')->willReturn(true); + $avatarNotExists = $this->getMock('OCP\IAvatar'); + $avatarNotExists->method('exists')->willReturn(false); + $this->container['OCP\\IAvatarManager'] + ->method('getAvatar') + ->will($this->returnValueMap([ + ['foo', $avatarExists], + ['bar', $avatarExists], + ['admin', $avatarNotExists], + ])); + + $this->container['Config'] + ->method('getSystemValue') + ->with('enable_avatars', true) + ->willReturn(true); + } public function testIndexAdmin() { @@ -62,7 +86,7 @@ class UsersControllerTest extends \Test\TestCase { $foo = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $foo - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $foo @@ -86,7 +110,7 @@ class UsersControllerTest extends \Test\TestCase { $admin = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $admin - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('admin')); $admin @@ -112,7 +136,7 @@ class UsersControllerTest extends \Test\TestCase { $bar = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $bar - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('bar')); $bar @@ -188,7 +212,6 @@ class UsersControllerTest extends \Test\TestCase { ->method('getSubAdmin') ->will($this->returnValue($subadmin)); - $expectedResponse = new DataResponse( array( 0 => array( @@ -202,6 +225,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => 'foo@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), 1 => array( 'name' => 'admin', @@ -214,6 +238,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'admin@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => false, ), 2 => array( 'name' => 'bar', @@ -226,6 +251,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'bar@dummy.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), ) ); @@ -246,7 +272,7 @@ class UsersControllerTest extends \Test\TestCase { $foo = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $foo - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $foo @@ -270,7 +296,7 @@ class UsersControllerTest extends \Test\TestCase { $admin = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $admin - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('admin')); $admin @@ -296,7 +322,7 @@ class UsersControllerTest extends \Test\TestCase { $bar = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $bar - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('bar')); $bar @@ -401,6 +427,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'bar@dummy.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ], 1=> [ 'name' => 'foo', @@ -413,6 +440,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => 'foo@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ], 2 => [ 'name' => 'admin', @@ -425,6 +453,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'admin@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => false, ], ] ); @@ -443,7 +472,7 @@ class UsersControllerTest extends \Test\TestCase { $foo = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $foo - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $foo @@ -467,7 +496,7 @@ class UsersControllerTest extends \Test\TestCase { $admin = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $admin - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('admin')); $admin @@ -493,7 +522,7 @@ class UsersControllerTest extends \Test\TestCase { $bar = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $bar - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('bar')); $bar @@ -553,6 +582,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => 'foo@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), 1 => array( 'name' => 'admin', @@ -565,6 +595,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'admin@bar.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => false, ), 2 => array( 'name' => 'bar', @@ -577,6 +608,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => '\Test\Util\User\Dummy', 'email' => 'bar@dummy.com', 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), ) ); @@ -590,7 +622,7 @@ class UsersControllerTest extends \Test\TestCase { $user = $this->getMockBuilder('\OC\User\User') ->disableOriginalConstructor()->getMock(); $user - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUID') ->will($this->returnValue('foo')); $user @@ -648,6 +680,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => 'OC_User_Database', 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ) ) ); @@ -719,6 +752,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => array(), 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -807,6 +841,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => [], 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -889,6 +924,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => array(), 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -984,6 +1020,7 @@ class UsersControllerTest extends \Test\TestCase { 'subadmin' => [], 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ), Http::STATUS_CREATED ); @@ -1480,6 +1517,7 @@ class UsersControllerTest extends \Test\TestCase { 'backend' => $backend, 'email' => null, 'isRestoreDisabled' => false, + 'isAvatarAvailable' => true, ]; return [$user, $result]; From 8c9a3ccefc81206f3a381d365e5909405169aa65 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Fri, 4 Dec 2015 14:35:48 +0100 Subject: [PATCH 30/69] Do not request an avatar if there is none --- settings/js/users/users.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/settings/js/users/users.js b/settings/js/users/users.js index aeecac7b24..2f8a964baf 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -64,8 +64,12 @@ var UserList = { /** * Avatar or placeholder */ - if ($tr.find('div.avatardiv').length){ - $('div.avatardiv', $tr).avatar(user.name, 32, undefined, undefined, undefined, user.displayname); + if ($tr.find('div.avatardiv').length) { + if (user.isAvatarAvailable === true) { + $('div.avatardiv', $tr).avatar(user.name, 32, undefined, undefined, undefined, user.displayname); + } else { + $('div.avatardiv', $tr).imageplaceholder(user.displayname); + } } /** From d5227972273d850a711fdcfdded9b45eff2afc1c Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Fri, 4 Dec 2015 15:52:42 +0100 Subject: [PATCH 31/69] Use correct method signature This function takes only one parameter --- lib/private/app/infoparser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php index 789f01e5bc..22f705884b 100644 --- a/lib/private/app/infoparser.php +++ b/lib/private/app/infoparser.php @@ -61,7 +61,7 @@ class InfoParser { if ($xml == false) { return null; } - $array = $this->xmlToArray($xml, false); + $array = $this->xmlToArray($xml); if (is_null($array)) { return null; } From e6d4496fc2a924c3682ae205226cce80ee401cbd Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 4 Dec 2015 17:23:51 +0100 Subject: [PATCH 32/69] Remove unused setActiveNavigationEntry of OC_App - it's also in OCP\App --- lib/private/app.php | 17 ----------------- lib/public/app.php | 3 ++- settings/admin.php | 2 +- settings/help.php | 2 +- settings/users.php | 2 +- 5 files changed, 5 insertions(+), 21 deletions(-) diff --git a/lib/private/app.php b/lib/private/app.php index c6e235eda4..78b039b87f 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -360,23 +360,6 @@ class OC_App { $appManager->disableApp($app); } - /** - * marks a navigation entry as active - * - * @param string $id id of the entry - * @return bool - * - * This function sets a navigation entry as active and removes the 'active' - * property from all other entries. The templates can use this for - * highlighting the current position of the user. - * - * @deprecated Use \OC::$server->getNavigationManager()->setActiveEntry() instead - */ - public static function setActiveNavigationEntry($id) { - OC::$server->getNavigationManager()->setActiveEntry($id); - return true; - } - /** * gets the active Menu entry * diff --git a/lib/public/app.php b/lib/public/app.php index c66d988c31..cc41484262 100644 --- a/lib/public/app.php +++ b/lib/public/app.php @@ -82,7 +82,8 @@ class App { * @since 4.0.0 */ public static function setActiveNavigationEntry( $id ) { - return \OC_App::setActiveNavigationEntry( $id ); + \OC::$server->getNavigationManager()->setActiveEntry($id); + return true; } /** diff --git a/settings/admin.php b/settings/admin.php index bccb117174..ae4340cf14 100644 --- a/settings/admin.php +++ b/settings/admin.php @@ -33,7 +33,7 @@ use OC\Lock\NoopLockingProvider; OC_Util::checkAdminUser(); -OC_App::setActiveNavigationEntry("admin"); +\OC::$server->getNavigationManager()->setActiveEntry("admin"); $template = new OC_Template('settings', 'admin', 'user'); $l = \OC::$server->getL10N('settings'); diff --git a/settings/help.php b/settings/help.php index aa89277d88..60719a3df9 100644 --- a/settings/help.php +++ b/settings/help.php @@ -30,7 +30,7 @@ OC_Util::checkLoggedIn(); // Load the files we need OC_Util::addStyle( "settings", "settings" ); -OC_App::setActiveNavigationEntry( "help" ); +\OC::$server->getNavigationManager()->setActiveEntry('help'); if(isset($_GET['mode']) and $_GET['mode'] === 'admin') { diff --git a/settings/users.php b/settings/users.php index 2795032a16..ccf1bcd9e1 100644 --- a/settings/users.php +++ b/settings/users.php @@ -35,7 +35,7 @@ OC_Util::checkSubAdminUser(); -OC_App::setActiveNavigationEntry( 'core_users' ); +\OC::$server->getNavigationManager()->setActiveEntry('core_users'); $userManager = \OC_User::getManager(); $groupManager = \OC_Group::getManager(); From 46a6c6d70bb3d66a129c247ce9d9e5b41c80c2ed Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 4 Dec 2015 17:26:28 +0100 Subject: [PATCH 33/69] remove OC_App::getActiveNavigationEntry - not unsed anymore --- lib/private/app.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/private/app.php b/lib/private/app.php index 78b039b87f..145517e218 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -360,20 +360,6 @@ class OC_App { $appManager->disableApp($app); } - /** - * gets the active Menu entry - * - * @return string id or empty string - * - * This function returns the id of the active navigation entry (set by - * setActiveNavigationEntry - * - * @deprecated Use \OC::$server->getNavigationManager()->getActiveEntry() instead - */ - public static function getActiveNavigationEntry() { - return OC::$server->getNavigationManager()->getActiveEntry(); - } - /** * Returns the Settings Navigation * From 316b907a13fcca9781f09b0f1a2a2d7324e42770 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 4 Dec 2015 17:30:22 +0100 Subject: [PATCH 34/69] Fixed system tags DAV and API and docs --- apps/dav/lib/systemtag/systemtagnode.php | 3 +++ apps/dav/lib/systemtag/systemtagplugin.php | 16 ++++++++---- .../systemtag/systemtagsbyidcollection.php | 5 ++-- .../systemtagsobjectmappingcollection.php | 13 +++++----- .../systemtagsobjecttypecollection.php | 2 +- .../systemtag/systemtagsbyidcollection.php | 24 ++++++++--------- .../systemtagsobjectmappingcollection.php | 26 +++++++++---------- lib/private/systemtag/systemtagmanager.php | 4 +-- .../systemtag/systemtagobjectmapper.php | 2 +- lib/public/systemtag/isystemtagmanager.php | 2 +- tests/lib/systemtag/systemtagmanagertest.php | 6 ++--- .../systemtag/systemtagobjectmappertest.php | 2 +- 12 files changed, 57 insertions(+), 48 deletions(-) diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index f7228108b3..7ab4a8a14f 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -30,6 +30,9 @@ use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagNotFoundException; use OCP\SystemTag\TagAlreadyExistsException; +/** + * DAV node representing a system tag, with the name being the tag id. + */ class SystemTagNode implements \Sabre\DAV\INode { /** diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php index 692b7e9701..51db063254 100644 --- a/apps/dav/lib/systemtag/systemtagplugin.php +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -33,6 +33,13 @@ use OCP\SystemTag\TagAlreadyExistsException; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +/** + * Sabre plugin to handle system tags: + * + * - makes it possible to create new tags with POST operation + * - get/set Webdav properties for tags + * + */ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { // namespace @@ -86,7 +93,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { } /** - * We intercept this to handle POST requests on calendars. + * POST operation on system tag collections * * @param RequestInterface $request request object * @param ResponseInterface $response response object @@ -130,18 +137,17 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { /** * Creates a new tag * - * @param string $data + * @param string $data JSON encoded string containing the properties of the tag to create * @param string $contentType content type of the data * @return ISystemTag newly created system tag * * @throws BadRequest if a field was missing - * @throws Conflict + * @throws Conflict if a tag with the same properties already exists * @throws UnsupportedMediaType if the content type is not supported */ private function createTag($data, $contentType = 'application/json') { if ($contentType === 'application/json') { $data = json_decode($data, true); - // TODO: application/x-www-form-urlencoded ? } else { throw new UnsupportedMediaType(); } @@ -164,7 +170,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { try { return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); } catch (TagAlreadyExistsException $e) { - throw new Conflict('Tag already exists'); + throw new Conflict('Tag already exists', 0, $e); } } diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php index 0164b9b0b3..e7b7b6d0ac 100644 --- a/apps/dav/lib/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -56,7 +56,7 @@ class SystemTagsByIdCollection implements ICollection { function getChild($name) { try { - $tags = $this->tagManager->getTagsById($name); + $tags = $this->tagManager->getTagsByIds([$name]); return $this->makeNode(current($tags)); } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); @@ -66,7 +66,6 @@ class SystemTagsByIdCollection implements ICollection { } function getChildren() { - // TODO: set visibility filter based on principal/permissions ? $tags = $this->tagManager->getAllTags(true); return array_map(function($tag) { return $this->makeNode($tag); @@ -75,7 +74,7 @@ class SystemTagsByIdCollection implements ICollection { function childExists($name) { try { - $this->tagManager->getTagsById($name); + $this->tagManager->getTagsByIds([$name]); return true; } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index e81994e0bd..89e8620614 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -86,8 +86,8 @@ class SystemTagsObjectMappingCollection implements ICollection { function getChild($tagId) { try { - if ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)) { - $tag = $this->tagManager->getTagsById($tagId); + if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) { + $tag = $this->tagManager->getTagsByIds([$tagId]); return $this->makeNode(current($tag)); } throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId); @@ -99,11 +99,11 @@ class SystemTagsObjectMappingCollection implements ICollection { } function getChildren() { - $tagIds = current($this->tagMapper->getTagIdsForObjects($this->objectId, $this->objectType)); + $tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType)); if (empty($tagIds)) { return []; } - $tags = $this->tagManager->getTagsById($tagIds); + $tags = $this->tagManager->getTagsByIds($tagIds); return array_values(array_map(function($tag) { return $this->makeNode($tag); }, $tags)); @@ -111,7 +111,7 @@ class SystemTagsObjectMappingCollection implements ICollection { function childExists($tagId) { try { - return ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)); + return ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)); } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { @@ -141,7 +141,8 @@ class SystemTagsObjectMappingCollection implements ICollection { } /** - * Create a sabre node for the given system tag + * Create a sabre node for the mapping of the + * given system tag to the collection's object * * @param ISystemTag $tag * diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php index 8dee85ccd4..e544073613 100644 --- a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -62,7 +62,7 @@ class SystemTagsObjectTypeCollection implements ICollection { } function createFile($name, $data = null) { - throw new Forbidden('Permission denied to create collections'); + throw new Forbidden('Permission denied to create nodes'); } function createDirectory($name) { diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php index fdaaf2cd00..104ce36603 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -51,8 +51,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { $tag = new SystemTag(123, 'Test', true, false); $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('123') + ->method('getTagsByIds') + ->with(['123']) ->will($this->returnValue([$tag])); $childNode = $this->node->getChild('123'); @@ -67,8 +67,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ public function testGetChildInvalidName() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('invalid') + ->method('getTagsByIds') + ->with(['invalid']) ->will($this->throwException(new \InvalidArgumentException())); $this->node->getChild('invalid'); @@ -79,8 +79,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ public function testGetChildNotFound() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('444') + ->method('getTagsByIds') + ->with(['444']) ->will($this->throwException(new TagNotFoundException())); $this->node->getChild('444'); @@ -117,8 +117,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { $tag = new SystemTag(123, 'One', true, false); $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('123') + ->method('getTagsByIds') + ->with(['123']) ->will($this->returnValue([$tag])); $this->assertTrue($this->node->childExists('123')); @@ -126,8 +126,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { public function testChildExistsNotFound() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('123') + ->method('getTagsByIds') + ->with(['123']) ->will($this->throwException(new TagNotFoundException())); $this->assertFalse($this->node->childExists('123')); @@ -138,8 +138,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ public function testChildExistsBadRequest() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('invalid') + ->method('getTagsByIds') + ->with(['invalid']) ->will($this->throwException(new \InvalidArgumentException())); $this->node->childExists('invalid'); diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php index 1a9ffa6f4a..6e15bb78e7 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -76,13 +76,13 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555', true) + ->with([111], 'files', '555', true) ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('555') - ->will($this->returnValue([$tag])); + ->method('getTagsByIds') + ->with(['555']) + ->will($this->returnValue(['555' => $tag])); $childNode = $this->node->getChild('555'); @@ -96,7 +96,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testGetChildRelationNotFound() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '777') + ->with([111], 'files', '777') ->will($this->returnValue(false)); $this->node->getChild('777'); @@ -108,7 +108,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testGetChildInvalidId() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', 'badid') + ->with([111], 'files', 'badid') ->will($this->throwException(new \InvalidArgumentException())); $this->node->getChild('badid'); @@ -120,7 +120,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testGetChildTagDoesNotExist() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '777') + ->with([111], 'files', '777') ->will($this->throwException(new TagNotFoundException())); $this->node->getChild('777'); @@ -132,11 +132,11 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->tagMapper->expects($this->once()) ->method('getTagIdsForObjects') - ->with(111, 'files') + ->with([111], 'files') ->will($this->returnValue(['111' => ['555', '556']])); $this->tagManager->expects($this->once()) - ->method('getTagsById') + ->method('getTagsByIds') ->with(['555', '556']) ->will($this->returnValue(['555' => $tag1, '666' => $tag2])); @@ -159,7 +159,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExists() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->returnValue(true)); $this->assertTrue($this->node->childExists('555')); @@ -168,7 +168,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExistsNotFound() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->returnValue(false)); $this->assertFalse($this->node->childExists('555')); @@ -177,7 +177,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExistsTagNotFound() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->throwException(new TagNotFoundException())); $this->assertFalse($this->node->childExists('555')); @@ -189,7 +189,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExistsInvalidId() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->throwException(new \InvalidArgumentException())); $this->node->childExists('555'); diff --git a/lib/private/systemtag/systemtagmanager.php b/lib/private/systemtag/systemtagmanager.php index 8caf10d69d..7f239dc84c 100644 --- a/lib/private/systemtag/systemtagmanager.php +++ b/lib/private/systemtag/systemtagmanager.php @@ -63,7 +63,7 @@ class SystemTagManager implements ISystemTagManager { /** * {@inheritdoc} */ - public function getTagsById($tagIds) { + public function getTagsByIds($tagIds) { if (!is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -242,7 +242,7 @@ class SystemTagManager implements ISystemTagManager { $tagNotFoundException = null; try { - $this->getTagsById($tagIds); + $this->getTagsByIds($tagIds); } catch (TagNotFoundException $e) { $tagNotFoundException = $e; } diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php index bb64a35456..988fa66d77 100644 --- a/lib/private/systemtag/systemtagobjectmapper.php +++ b/lib/private/systemtag/systemtagobjectmapper.php @@ -213,7 +213,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist */ private function assertTagsExist($tagIds) { - $tags = $this->tagManager->getTagsById($tagIds); + $tags = $this->tagManager->getTagsByIds($tagIds); if (count($tags) !== count($tagIds)) { // at least one tag missing, bail out $foundTagIds = array_map( diff --git a/lib/public/systemtag/isystemtagmanager.php b/lib/public/systemtag/isystemtagmanager.php index 4e3b263e56..6e8fed36dc 100644 --- a/lib/public/systemtag/isystemtagmanager.php +++ b/lib/public/systemtag/isystemtagmanager.php @@ -41,7 +41,7 @@ interface ISystemTagManager { * * @since 9.0.0 */ - public function getTagsById($tagIds); + public function getTagsByIds($tagIds); /** * Returns the tag object matching the given attributes. diff --git a/tests/lib/systemtag/systemtagmanagertest.php b/tests/lib/systemtag/systemtagmanagertest.php index 8498b85519..97c072f33f 100644 --- a/tests/lib/systemtag/systemtagmanagertest.php +++ b/tests/lib/systemtag/systemtagmanagertest.php @@ -250,7 +250,7 @@ class SystemTagManagerTest extends TestCase { $tag1 = $this->tagManager->createTag('one', true, false); $tag2 = $this->tagManager->createTag('two', false, true); - $tagList = $this->tagManager->getTagsById([$tag1->getId(), $tag2->getId()]); + $tagList = $this->tagManager->getTagsByIds([$tag1->getId(), $tag2->getId()]); $this->assertCount(2, $tagList); @@ -270,7 +270,7 @@ class SystemTagManagerTest extends TestCase { */ public function testGetNonExistingTagsById() { $tag1 = $this->tagManager->createTag('one', true, false); - $this->tagManager->getTagsById([$tag1->getId(), 100, 101]); + $this->tagManager->getTagsByIds([$tag1->getId(), 100, 101]); } /** @@ -278,7 +278,7 @@ class SystemTagManagerTest extends TestCase { */ public function testGetInvalidTagIdFormat() { $tag1 = $this->tagManager->createTag('one', true, false); - $this->tagManager->getTagsById([$tag1->getId() . 'suffix']); + $this->tagManager->getTagsByIds([$tag1->getId() . 'suffix']); } public function updateTagProvider() { diff --git a/tests/lib/systemtag/systemtagobjectmappertest.php b/tests/lib/systemtag/systemtagobjectmappertest.php index 43d0b8c696..4ea80c216e 100644 --- a/tests/lib/systemtag/systemtagobjectmappertest.php +++ b/tests/lib/systemtag/systemtagobjectmappertest.php @@ -74,7 +74,7 @@ class SystemTagObjectMapperTest extends TestCase { $this->tag3 = new SystemTag(3, 'testtag3', false, false); $this->tagManager->expects($this->any()) - ->method('getTagsById') + ->method('getTagsByIds') ->will($this->returnCallback(function($tagIds) { $result = []; if (in_array(1, $tagIds)) { From 4548a0aa90cd3b3a0034178609f74bca5b0eccd3 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Fri, 4 Dec 2015 18:02:47 +0100 Subject: [PATCH 35/69] Remove OC_Util::getUrlContent and replace by proper usage of public interfaces --- lib/private/apphelper.php | 8 +++++++- lib/private/util.php | 23 +++++------------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/lib/private/apphelper.php b/lib/private/apphelper.php index 9084d2b8ab..478787b21d 100644 --- a/lib/private/apphelper.php +++ b/lib/private/apphelper.php @@ -36,6 +36,12 @@ class AppHelper implements \OCP\IHelper { * @deprecated 8.1.0 Use \OCP\IServerContainer::getHTTPClientService */ public function getUrlContent($url) { - return \OC_Util::getUrlContent($url); + try { + $client = \OC::$server->getHTTPClientService()->newClient(); + $response = $client->get($url); + return $response->getBody(); + } catch (\Exception $e) { + return false; + } } } diff --git a/lib/private/util.php b/lib/private/util.php index ac42b96de2..2038f3bfa2 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -1237,7 +1237,11 @@ class OC_Util { // accessing the file via http $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName); - $content = self::getUrlContent($url); + try { + $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody(); + } catch (\Exception $e) { + $content = false; + } // cleanup @unlink($testFile); @@ -1312,23 +1316,6 @@ class OC_Util { return \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($length, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS); } - /** - * Get URL content - * @param string $url Url to get content - * @throws Exception If the URL does not start with http:// or https:// - * @return string of the response or false on error - * This function get the content of a page via curl, if curl is enabled. - * If not, file_get_contents is used. - * @deprecated Use \OC::$server->getHTTPClientService()->newClient()->get($url); - */ - public static function getUrlContent($url) { - try { - return \OC::$server->getHTTPHelper()->getUrlContent($url); - } catch (\Exception $e) { - throw $e; - } - } - /** * Checks whether the server is running on Windows * From d14f1283290552f10b58f28ac46a8e74ab8c615d Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Sun, 6 Dec 2015 01:54:33 -0500 Subject: [PATCH 36/69] [tx-robot] updated from transifex --- apps/files_external/l10n/lt_LT.js | 1 + apps/files_external/l10n/lt_LT.json | 1 + apps/user_ldap/l10n/lt_LT.js | 2 ++ apps/user_ldap/l10n/lt_LT.json | 2 ++ lib/l10n/lt_LT.js | 2 ++ lib/l10n/lt_LT.json | 2 ++ lib/l10n/pt_BR.js | 6 +++++- lib/l10n/pt_BR.json | 6 +++++- 8 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/files_external/l10n/lt_LT.js b/apps/files_external/l10n/lt_LT.js index dabdeb8bd3..3a871070f4 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 2b05c277ee..854f753aca 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/user_ldap/l10n/lt_LT.js b/apps/user_ldap/l10n/lt_LT.js index e27dcc3e8d..c263e95220 100644 --- a/apps/user_ldap/l10n/lt_LT.js +++ b/apps/user_ldap/l10n/lt_LT.js @@ -4,7 +4,9 @@ OC.L10N.register( "Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.", "Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos", "The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!", + "The configuration is invalid. Please have a look at the logs for further details." : "Neteisinga konfigūracija. Daugiau informacijos rasite žurnaluose.", "No action specified" : "Nepasirinktas veiksmas", + "No data specified" : "Nepateikta duomenų", "Select groups" : "Pasirinkti grupes", "Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?", "Confirm Deletion" : "Patvirtinkite trynimą", diff --git a/apps/user_ldap/l10n/lt_LT.json b/apps/user_ldap/l10n/lt_LT.json index fa1526c063..64e2bae467 100644 --- a/apps/user_ldap/l10n/lt_LT.json +++ b/apps/user_ldap/l10n/lt_LT.json @@ -2,7 +2,9 @@ "Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.", "Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos", "The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!", + "The configuration is invalid. Please have a look at the logs for further details." : "Neteisinga konfigūracija. Daugiau informacijos rasite žurnaluose.", "No action specified" : "Nepasirinktas veiksmas", + "No data specified" : "Nepateikta duomenų", "Select groups" : "Pasirinkti grupes", "Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?", "Confirm Deletion" : "Patvirtinkite trynimą", diff --git a/lib/l10n/lt_LT.js b/lib/l10n/lt_LT.js index f73b1fdc87..402167cb3c 100644 --- a/lib/l10n/lt_LT.js +++ b/lib/l10n/lt_LT.js @@ -4,7 +4,9 @@ OC.L10N.register( "Cannot write into \"config\" directory!" : "Negalima rašyti į \"config\" aplanką!", "This can usually be fixed by giving the webserver write access to the config directory" : "Tai gali būti ištaisyta suteikiant web serveriui rašymo teises į config aplanką", "See %s" : "Žiūrėk %s", + "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys", "PHP %s or higher is required." : "Reikalinga PHP %s arba aukštesnė.", + "Following databases are supported: %s" : "Palaikomos duomenų bazės: %s", "Help" : "Pagalba", "Personal" : "Asmeniniai", "Users" : "Vartotojai", diff --git a/lib/l10n/lt_LT.json b/lib/l10n/lt_LT.json index e9acd6f295..c4efe38665 100644 --- a/lib/l10n/lt_LT.json +++ b/lib/l10n/lt_LT.json @@ -2,7 +2,9 @@ "Cannot write into \"config\" directory!" : "Negalima rašyti į \"config\" aplanką!", "This can usually be fixed by giving the webserver write access to the config directory" : "Tai gali būti ištaisyta suteikiant web serveriui rašymo teises į config aplanką", "See %s" : "Žiūrėk %s", + "Sample configuration detected" : "Aptiktas konfigūracijos pavyzdys", "PHP %s or higher is required." : "Reikalinga PHP %s arba aukštesnė.", + "Following databases are supported: %s" : "Palaikomos duomenų bazės: %s", "Help" : "Pagalba", "Personal" : "Asmeniniai", "Users" : "Vartotojai", diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js index 8078d369b7..2595d5dfd3 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -147,6 +147,10 @@ OC.L10N.register( "Data directory (%s) is invalid" : "Diretório de dados (%s) é inválido", "Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor, verifique se o diretório de dados contém um arquivo \".ocdata\" em sua raiz.", "Could not obtain lock type %d on \"%s\"." : "Não foi possível obter tipo de bloqueio %d em \"%s\".", - "Storage not available" : "Armazanamento não disponível" + "Storage unauthorized. %s" : "Armazenamento não autorizado. %s", + "Storage incomplete configuration. %s" : "Incompleta configuração de armazenamento. %s", + "Storage connection error. %s" : "Erro na conexão de armazenamento. %s", + "Storage not available" : "Armazanamento não disponível", + "Storage connection timeout. %s" : "Tempo limite de conexão de armazenamento. %s" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json index 5987c1e2ac..0da54181b3 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -145,6 +145,10 @@ "Data directory (%s) is invalid" : "Diretório de dados (%s) é inválido", "Please check that the data directory contains a file \".ocdata\" in its root." : "Por favor, verifique se o diretório de dados contém um arquivo \".ocdata\" em sua raiz.", "Could not obtain lock type %d on \"%s\"." : "Não foi possível obter tipo de bloqueio %d em \"%s\".", - "Storage not available" : "Armazanamento não disponível" + "Storage unauthorized. %s" : "Armazenamento não autorizado. %s", + "Storage incomplete configuration. %s" : "Incompleta configuração de armazenamento. %s", + "Storage connection error. %s" : "Erro na conexão de armazenamento. %s", + "Storage not available" : "Armazanamento não disponível", + "Storage connection timeout. %s" : "Tempo limite de conexão de armazenamento. %s" },"pluralForm" :"nplurals=2; plural=(n > 1);" } \ No newline at end of file From 884946276e13e7949cb2a5a46fd29d342ff386d4 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Mon, 7 Dec 2015 01:54:35 -0500 Subject: [PATCH 37/69] [tx-robot] updated from transifex --- core/l10n/fr.js | 1 + core/l10n/fr.json | 1 + lib/l10n/fr.js | 3 +++ lib/l10n/fr.json | 3 +++ 4 files changed, 8 insertions(+) diff --git a/core/l10n/fr.js b/core/l10n/fr.js index 9dae27cd45..4bb7aa82c9 100644 --- a/core/l10n/fr.js +++ b/core/l10n/fr.js @@ -191,6 +191,7 @@ OC.L10N.register( "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.", "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.", "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.", + "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.", "%s password reset" : "Réinitialisation de votre mot de passe %s", "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}", "New password" : "Nouveau mot de passe", diff --git a/core/l10n/fr.json b/core/l10n/fr.json index ee8f44595e..02347de170 100644 --- a/core/l10n/fr.json +++ b/core/l10n/fr.json @@ -189,6 +189,7 @@ "Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable.", "Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré.", "Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.", + "Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.", "%s password reset" : "Réinitialisation de votre mot de passe %s", "Use the following link to reset your password: {link}" : "Utilisez le lien suivant pour réinitialiser votre mot de passe : {link}", "New password" : "Nouveau mot de passe", diff --git a/lib/l10n/fr.js b/lib/l10n/fr.js index 9660650b4f..e9b4b52f51 100644 --- a/lib/l10n/fr.js +++ b/lib/l10n/fr.js @@ -146,6 +146,9 @@ OC.L10N.register( "Data directory (%s) is invalid" : "Le répertoire (%s) n'est pas valide", "Please check that the data directory contains a file \".ocdata\" in its root." : "Veuillez vérifier que le répertoire de données contient un fichier \".ocdata\" à sa racine.", "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".", + "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s", + "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s", + "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s", "Storage not available" : "Support de stockage non disponible" }, "nplurals=2; plural=(n > 1);"); diff --git a/lib/l10n/fr.json b/lib/l10n/fr.json index a388630993..7da5eaedd7 100644 --- a/lib/l10n/fr.json +++ b/lib/l10n/fr.json @@ -144,6 +144,9 @@ "Data directory (%s) is invalid" : "Le répertoire (%s) n'est pas valide", "Please check that the data directory contains a file \".ocdata\" in its root." : "Veuillez vérifier que le répertoire de données contient un fichier \".ocdata\" à sa racine.", "Could not obtain lock type %d on \"%s\"." : "Impossible d'obtenir le verrouillage de type %d sur \"%s\".", + "Storage unauthorized. %s" : "Espace de stockage non autorisé. %s", + "Storage incomplete configuration. %s" : "Configuration de l'espace de stockage incomplète. %s", + "Storage connection error. %s" : "Erreur de connexion à l'espace stockage. %s", "Storage not available" : "Support de stockage non disponible" },"pluralForm" :"nplurals=2; plural=(n > 1);" } \ No newline at end of file From 35ab7f0e64316eba1966bde406f31885b61f15a8 Mon Sep 17 00:00:00 2001 From: Tim Dettrick Date: Mon, 10 Aug 2015 11:06:45 +1000 Subject: [PATCH 38/69] Improving fopen behaviour for Swift backend --- apps/files_external/lib/swift.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index e946e7feb7..a64a02a4ed 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; From 5b87413792416beec851be7ecfcaaf2d5bb933c4 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 7 Dec 2015 10:49:34 +0100 Subject: [PATCH 39/69] Allow sending a share email to multiple users --- lib/private/share/mailnotifications.php | 4 +++- tests/lib/share/MailNotificationsTest.php | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php index f45d80b37c..4d282158ba 100644 --- a/lib/private/share/mailnotifications.php +++ b/lib/private/share/mailnotifications.php @@ -176,10 +176,12 @@ class MailNotifications { $subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]); list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration); + $recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient); + $recipients = explode(',', $recipient); try { $message = $this->mailer->createMessage(); $message->setSubject($subject); - $message->setTo([$recipient]); + $message->setTo($recipients); $message->setHtmlBody($htmlBody); $message->setPlainBody($textBody); $message->setFrom([ diff --git a/tests/lib/share/MailNotificationsTest.php b/tests/lib/share/MailNotificationsTest.php index 2124a8bf13..0706b97233 100644 --- a/tests/lib/share/MailNotificationsTest.php +++ b/tests/lib/share/MailNotificationsTest.php @@ -123,7 +123,21 @@ class MailNotificationsTest extends \Test\TestCase { $this->assertSame([], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600)); } - public function testSendLinkShareMailWithReplyTo() { + public function dataSendLinkShareMailWithReplyTo() { + return [ + ['lukas@owncloud.com nickvergessen@owncloud.com'], + ['lukas@owncloud.com,nickvergessen@owncloud.com'], + ['lukas@owncloud.com, nickvergessen@owncloud.com'], + ['lukas@owncloud.com;nickvergessen@owncloud.com'], + ['lukas@owncloud.com; nickvergessen@owncloud.com'], + ]; + } + + /** + * @dataProvider dataSendLinkShareMailWithReplyTo + * @param string $to + */ + public function testSendLinkShareMailWithReplyTo($to) { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); @@ -134,7 +148,7 @@ class MailNotificationsTest extends \Test\TestCase { $message ->expects($this->once()) ->method('setTo') - ->with(['lukas@owncloud.com']); + ->with(['lukas@owncloud.com', 'nickvergessen@owncloud.com']); $message ->expects($this->once()) ->method('setHtmlBody'); @@ -167,7 +181,7 @@ class MailNotificationsTest extends \Test\TestCase { $this->logger, $this->defaults ); - $this->assertSame([], $mailNotifications->sendLinkShareMail('lukas@owncloud.com', 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600)); + $this->assertSame([], $mailNotifications->sendLinkShareMail($to, 'MyFile', 'https://owncloud.com/file/?foo=bar', 3600)); } public function testSendLinkShareMailException() { From 820c3b852dd478761a0ce433d0553a0f94731370 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 7 Dec 2015 12:01:02 +0100 Subject: [PATCH 40/69] Add a unit test for single user case as well --- tests/lib/share/MailNotificationsTest.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/lib/share/MailNotificationsTest.php b/tests/lib/share/MailNotificationsTest.php index 0706b97233..8684886e79 100644 --- a/tests/lib/share/MailNotificationsTest.php +++ b/tests/lib/share/MailNotificationsTest.php @@ -125,19 +125,21 @@ class MailNotificationsTest extends \Test\TestCase { public function dataSendLinkShareMailWithReplyTo() { return [ - ['lukas@owncloud.com nickvergessen@owncloud.com'], - ['lukas@owncloud.com,nickvergessen@owncloud.com'], - ['lukas@owncloud.com, nickvergessen@owncloud.com'], - ['lukas@owncloud.com;nickvergessen@owncloud.com'], - ['lukas@owncloud.com; nickvergessen@owncloud.com'], + ['lukas@owncloud.com', ['lukas@owncloud.com']], + ['lukas@owncloud.com nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com,nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com, nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com;nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], + ['lukas@owncloud.com; nickvergessen@owncloud.com', ['lukas@owncloud.com', 'nickvergessen@owncloud.com']], ]; } /** * @dataProvider dataSendLinkShareMailWithReplyTo * @param string $to + * @param array $expectedTo */ - public function testSendLinkShareMailWithReplyTo($to) { + public function testSendLinkShareMailWithReplyTo($to, array $expectedTo) { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); @@ -148,7 +150,7 @@ class MailNotificationsTest extends \Test\TestCase { $message ->expects($this->once()) ->method('setTo') - ->with(['lukas@owncloud.com', 'nickvergessen@owncloud.com']); + ->with($expectedTo); $message ->expects($this->once()) ->method('setHtmlBody'); From 9c550a07ed439bf589fc5e3ebe7c3f2fe1807449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 7 Dec 2015 12:23:42 +0100 Subject: [PATCH 41/69] OC.FilePath has still a valid use case when generating paths to static files what for generateUrl cannot be used for - closes #15604 --- core/js/js.js | 1 - 1 file changed, 1 deletion(-) diff --git a/core/js/js.js b/core/js/js.js index cbdffd0f01..2937d3f6eb 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -174,7 +174,6 @@ var OC={ * @param {string} type the type of the file to link to (e.g. css,img,ajax.template) * @param {string} file the filename * @return {string} Absolute URL for a file in an app - * @deprecated use OC.generateUrl() instead */ filePath:function(app,type,file){ var isCore=OC.coreApps.indexOf(app)!==-1, From 97f9213da95187a9992f700597fb012429b60469 Mon Sep 17 00:00:00 2001 From: Scrutinizer Auto-Fixer Date: Mon, 7 Dec 2015 12:05:27 +0000 Subject: [PATCH 42/69] Scrutinizer Auto-Fixes This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com --- apps/files_external/lib/smb.php | 1 - apps/files_external/tests/amazons3migration.php | 3 +++ .../tests/controller/storagescontrollertest.php | 6 ++++++ apps/files_external/tests/service/backendservicetest.php | 5 +++++ apps/files_sharing/appinfo/application.php | 1 - apps/files_sharing/lib/cache.php | 2 +- .../lib/controllers/externalsharescontroller.php | 3 +-- apps/files_sharing/lib/controllers/sharecontroller.php | 2 +- .../files_sharing/lib/middleware/sharingcheckmiddleware.php | 1 - apps/files_sharing/lib/sharedstorage.php | 2 -- 10 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index f58cd9849f..a94840ead5 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/tests/amazons3migration.php b/apps/files_external/tests/amazons3migration.php index 33fb6119a9..cc47107c7f 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 8a7acf8100..747bcd46e1 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 5097b479a5..e9cb0e2c36 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() diff --git a/apps/files_sharing/appinfo/application.php b/apps/files_sharing/appinfo/application.php index ffe3a6a513..6af450405a 100644 --- a/apps/files_sharing/appinfo/application.php +++ b/apps/files_sharing/appinfo/application.php @@ -25,7 +25,6 @@ namespace OCA\Files_Sharing\AppInfo; -use OCA\Files_Sharing\Helper; use OCA\Files_Sharing\MountProvider; use OCP\AppFramework\App; use OC\AppFramework\Utility\SimpleContainer; diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 2e615e231f..c903241378 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -98,7 +98,7 @@ class Shared_Cache extends Cache { /** * get the stored metadata of a file or folder * - * @param string|int $file + * @param string $file * @return array|false */ public function get($file) { diff --git a/apps/files_sharing/lib/controllers/externalsharescontroller.php b/apps/files_sharing/lib/controllers/externalsharescontroller.php index edf065ab47..ec57606566 100644 --- a/apps/files_sharing/lib/controllers/externalsharescontroller.php +++ b/apps/files_sharing/lib/controllers/externalsharescontroller.php @@ -45,7 +45,6 @@ class ExternalSharesController extends Controller { /** * @param string $appName * @param IRequest $request - * @param bool $incomingShareEnabled * @param \OCA\Files_Sharing\External\Manager $externalManager * @param IClientService $clientService */ @@ -84,7 +83,7 @@ class ExternalSharesController extends Controller { * @NoAdminRequired * @NoOutgoingFederatedSharingRequired * - * @param $id + * @param integer $id * @return JSONResponse */ public function destroy($id) { diff --git a/apps/files_sharing/lib/controllers/sharecontroller.php b/apps/files_sharing/lib/controllers/sharecontroller.php index 4b446d79ad..fe7b159449 100644 --- a/apps/files_sharing/lib/controllers/sharecontroller.php +++ b/apps/files_sharing/lib/controllers/sharecontroller.php @@ -124,7 +124,7 @@ class ShareController extends Controller { * @UseSession * * Authenticates against password-protected shares - * @param $token + * @param string $token * @param string $password * @return RedirectResponse|TemplateResponse */ diff --git a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php index 22b9d32a27..04dd28574d 100644 --- a/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php +++ b/apps/files_sharing/lib/middleware/sharingcheckmiddleware.php @@ -27,7 +27,6 @@ namespace OCA\Files_Sharing\Middleware; use OCP\App\IAppManager; use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Middleware; -use OCP\AppFramework\Http\TemplateResponse; use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\AppFramework\Utility\IControllerMethodReflector; diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php index 4807b5ee73..cda3f564d5 100644 --- a/apps/files_sharing/lib/sharedstorage.php +++ b/apps/files_sharing/lib/sharedstorage.php @@ -32,8 +32,6 @@ namespace OC\Files\Storage; use OC\Files\Filesystem; use OCA\Files_Sharing\ISharedStorage; -use OCA\Files_Sharing\Propagator; -use OCA\Files_Sharing\SharedMount; use OCP\Lock\ILockingProvider; /** From c6dbe8ac63eb4db135b045ca0dcec1dd5f3b4cbc Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 7 Dec 2015 14:34:15 +0100 Subject: [PATCH 43/69] Do not overwrite the language when it's just missing for one app --- lib/private/l10n.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/private/l10n.php b/lib/private/l10n.php index 86335bce92..7835285bd4 100644 --- a/lib/private/l10n.php +++ b/lib/private/l10n.php @@ -116,13 +116,17 @@ class OC_L10N implements \OCP\IL10N { $preferred_language = str_replace('-', '_', $preferred_language); foreach ($available as $available_language) { if ($preferred_language === strtolower($available_language)) { - self::$language = $available_language; + if (!self::$language) { + self::$language = $available_language; + } return $available_language; } } foreach ($available as $available_language) { if (substr($preferred_language, 0, 2) === $available_language) { - self::$language = $available_language; + if (!self::$language) { + self::$language = $available_language; + } return $available_language; } } @@ -407,7 +411,7 @@ class OC_L10N implements \OCP\IL10N { * If nothing works it returns 'en' */ public static function findLanguage($app = null) { - if(self::$language != '') { + if (self::$language != '' && self::languageExists($app, self::$language)) { return self::$language; } From 57cd5209cab31bb1a20c4043fb2539c0682d33b8 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 7 Dec 2015 14:07:14 +0100 Subject: [PATCH 44/69] Add rules for checked+disabled and disabled checkbox style --- core/css/inputs.css | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/css/inputs.css b/core/css/inputs.css index b2d78c2562..fe03af85f6 100644 --- a/core/css/inputs.css +++ b/core/css/inputs.css @@ -108,10 +108,26 @@ html:not(.ie8) input[type="checkbox"].checkbox:checked + label:before { background-image: url('../img/actions/checkbox-checked.svg'); } +html:not(.ie8) input[type="checkbox"].checkbox:disabled + label:before { + background-image: url('../img/actions/checkbox-disabled.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox:checked:disabled + label:before { + background-image: url('../img/actions/checkbox-checked-disabled.svg'); +} + html:not(.ie8) input[type="checkbox"].checkbox--white:checked + label:before { background-image: url('../img/actions/checkbox-checked-white.svg'); } +html:not(.ie8) input[type="checkbox"].checkbox--white:disabled + label:before { + background-image: url('../img/actions/checkbox-disabled-white.svg'); +} + +html:not(.ie8) input[type="checkbox"].checkbox--white:checked:disabled + label:before { + background-image: url('../img/actions/checkbox-checked-disabled.svg'); +} + html:not(.ie8) input[type="checkbox"].checkbox:hover+label:before, input[type="checkbox"]:focus+label:before { color:#111 !important; } From f8f3c9ecf9da1f14722f6d3266a0e80ea157f98f Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 7 Dec 2015 15:14:19 +0100 Subject: [PATCH 45/69] Remove password reset when the user can not change the password --- core/templates/login.php | 8 ++++++-- lib/private/util.php | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/templates/login.php b/core/templates/login.php index 03be6258fd..7b09d4fac9 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -56,11 +56,15 @@ script('core', [

- + t('Wrong password. Reset it?')); ?> - + +

+ t('Wrong password.')); ?> +

+