From 4b3ae60558a5d9d18cdd7be0d844d577785f46fb Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Fri, 8 Jun 2012 11:42:00 -0400 Subject: [PATCH] Working UI for external storage mount configuration --- apps/files_external/ajax/addMountPoint.php | 13 + apps/files_external/ajax/removeMountPoint.php | 13 + apps/files_external/appinfo/app.php | 7 +- apps/files_external/css/settings.css | 9 +- apps/files_external/js/settings.js | 166 +++++++++---- apps/files_external/lib/config.php | 231 ++++++++++++++++++ apps/files_external/personal.php | 34 +++ apps/files_external/settings.php | 13 +- apps/files_external/templates/settings.php | 94 +++---- 9 files changed, 485 insertions(+), 95 deletions(-) create mode 100644 apps/files_external/ajax/addMountPoint.php create mode 100644 apps/files_external/ajax/removeMountPoint.php create mode 100755 apps/files_external/lib/config.php create mode 100755 apps/files_external/personal.php diff --git a/apps/files_external/ajax/addMountPoint.php b/apps/files_external/ajax/addMountPoint.php new file mode 100644 index 0000000000..549cb6a342 --- /dev/null +++ b/apps/files_external/ajax/addMountPoint.php @@ -0,0 +1,13 @@ + diff --git a/apps/files_external/ajax/removeMountPoint.php b/apps/files_external/ajax/removeMountPoint.php new file mode 100644 index 0000000000..b77b306bcb --- /dev/null +++ b/apps/files_external/ajax/removeMountPoint.php @@ -0,0 +1,13 @@ + diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 9fd87e3934..b7a07b4aac 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -6,11 +6,16 @@ * See the COPYING-README file. */ - OC::$CLASSPATH['OC_FileStorage_StreamWrapper']='apps/files_external/lib/streamwrapper.php'; +OC::$CLASSPATH['OC_FileStorage_StreamWrapper']='apps/files_external/lib/streamwrapper.php'; OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_external/lib/ftp.php'; OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_external/lib/webdav.php'; OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_external/lib/google.php'; OC::$CLASSPATH['OC_Filestorage_SWIFT']='apps/files_external/lib/swift.php'; OC::$CLASSPATH['OC_Filestorage_SMB']='apps/files_external/lib/smb.php'; +OC::$CLASSPATH['OC_Filestorage_AmazonS3']='apps/files_external/lib/amazons3.php'; +OC::$CLASSPATH['OC_Mount_Config']='apps/files_external/lib/config.php'; OCP\App::registerAdmin('files_external', 'settings'); +if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') { + OCP\App::registerPersonal('files_external', 'personal'); +} diff --git a/apps/files_external/css/settings.css b/apps/files_external/css/settings.css index b11af752ec..d8575c49e3 100644 --- a/apps/files_external/css/settings.css +++ b/apps/files_external/css/settings.css @@ -1,6 +1,5 @@ .error { color: #FF3B3B; } -td.type { width:8em; } -td.mount, td.options, td.applicable { width:10em; } -#addStorage>td { border:none; } -#addStorage>td:not(.selectStorage) { visibility:hidden; } -#selectStorage { margin-left:-10px; } \ No newline at end of file +td.mountPoint, td.backend { width:10em; } +#addMountPoint>td { border:none; } +#addMountPoint>td.applicable { visibility:hidden; } +#selectBackend { margin-left:-10px; } \ No newline at end of file diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 9a558ad6e4..38291d5f7e 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1,59 +1,143 @@ -$(document).ready(function(){ +$(document).ready(function() { - function applicableChange(applicable) { - if (applicable == 'Global') { - - } - console.log(applicable); - } - - $('#selectStorage').live('change', function() { + $('.chzn-select').chosen(); + + $('#selectBackend').live('change', function() { var tr = $(this).parent().parent(); $('#externalStorage tbody').last().append($(tr).clone()); - var selected = $(this).val(); + var selected = $(this).find('option:selected').text(); + var backendClass = $(this).val(); $(this).parent().text(selected); - var backends = $(this).data('configurations').split(';'); - var configuration = []; - // Find selected backend configuration parameters - $.each(backends, function(index, backend) { - if (backend.split(':')[0] == selected) { - configuration = backend.split(':')[1].split(','); - // break; - } - }); + $(tr).find('.backend').data('class', $(this).val()); + var configurations = $(this).data('configurations'); var td = $(tr).find('td.configuration'); - $.each(configuration, function(index, config) { - if (config.indexOf('*') != -1) { - td.append(''); - } else { - td.append(''); + $.each(configurations, function(backend, parameters) { + if (backend == backendClass) { + $.each(parameters['configuration'], function(parameter, placeholder) { + if (placeholder.indexOf('*') != -1) { + td.append(''); + } else if (placeholder.indexOf('!') != -1) { + td.append(''); + } else if (placeholder.indexOf('&') != -1) { + td.append(''); + } else { + td.append(''); + } + }); + return false; } }); + $('.chz-select').chosen(); $(tr).find('td').last().attr('class', 'remove'); $(tr).removeAttr('id'); $(this).remove(); }); - $('td.remove>img').live('click', function() { - $(this).parent().parent().remove(); - // TODO remove storage - }); - - $('#externalStorage select[multiple]').each(function(index,element){ - applyMultiplySelect($(element)); - }); - - function applyMultiplySelect(element) { - var checkHandeler=false; - element.multiSelect({ - oncheck:applicableChange, - onuncheck:applicableChange, - minWidth: 120, + $('#externalStorage td').live('change', function() { + var tr = $(this).parent(); + var mountPoint = $(tr).find('.mountPoint input').val(); + if (mountPoint == '') { + return false; + } + var backendClass = $(tr).find('.backend').data('class'); + var configuration = $(tr).find('.configuration input'); + var addMountPoint = true; + if (configuration.length < 1) { + return false; + } + var classOptions = {}; + $.each(configuration, function(index, input) { + if ($(input).val() == '' && !$(input).hasClass('optional')) { + addMountPoint = false; + return false; + } + if ($(input).is(':checkbox')) { + if ($(input).is(':checked')) { + classOptions[$(input).data('parameter')] = true; + } else { + classOptions[$(input).data('parameter')] = false; + } + } else { + classOptions[$(input).data('parameter')] = $(input).val(); + } }); - } + if (addMountPoint) { + if ($('#externalStorage').data('admin')) { + var isPersonal = false; + var multiselect = $(tr).find('.chzn-select').val(); + var oldGroups = $(tr).find('.applicable').data('applicable-groups'); + var oldUsers = $(tr).find('.applicable').data('applicable-users'); + $.each(multiselect, function(index, value) { + var pos = value.indexOf('(group)'); + if (pos != -1) { + var mountType = 'group'; + var applicable = value.substr(0, pos); + if ($.inArray(applicable, oldGroups) != -1) { + oldGroups.splice($.inArray(applicable, oldGroups), 1); + } + } else { + var mountType = 'user'; + var applicable = value; + if ($.inArray(applicable, oldUsers) != -1) { + oldUsers.splice($.inArray(applicable, oldUsers), 1); + } + } + $.post(OC.filePath('files_external', 'ajax', 'addMountPoint.php'), { mountPoint: mountPoint, class: backendClass, classOptions: classOptions, mountType: mountType, applicable: applicable, isPersonal: isPersonal }); + }); + var mountType = 'group'; + $.each(oldGroups, function(index, applicable) { + $.post(OC.filePath('files_external', 'ajax', 'removeMountPoint.php'), { mountPoint: mountPoint, mountType: mountType, applicable: applicable, isPersonal: isPersonal }); + }); + var mountType = 'user'; + $.each(oldUsers, function(index, applicable) { + $.post(OC.filePath('files_external', 'ajax', 'removeMountPoint.php'), { mountPoint: mountPoint, mountType: mountType, applicable: applicable, isPersonal: isPersonal }); + }); + } else { + var isPersonal = true; + var mountType = 'user'; + var applicable = OC.currentUser; + $.post(OC.filePath('files_external', 'ajax', 'addMountPoint.php'), { mountPoint: mountPoint, class: backendClass, classOptions: classOptions, mountType: mountType, applicable: applicable, isPersonal: isPersonal }); + } + } + }); + + $('td.remove>img').live('click', function() { + var tr = $(this).parent().parent(); + var mountPoint = $(tr).find('.mountPoint input').val(); + if (mountPoint == '') { + return false; + } + if ($('#externalStorage').data('admin')) { + var isPersonal = false; + var multiselect = $(tr).find('.chzn-select').val(); + $.each(multiselect, function(index, value) { + var pos = value.indexOf('(group)'); + if (pos != -1) { + var mountType = 'group'; + var applicable = value.substr(0, pos); + } else { + var mountType = 'user'; + var applicable = value; + } + $.post(OC.filePath('files_external', 'ajax', 'removeMountPoint.php'), { mountPoint: mountPoint, mountType: mountType, applicable: applicable, isPersonal: isPersonal }); + }); + } else { + var mountType = 'user'; + var applicable = OC.currentUser; + var isPersonal = true; + } + $.post(OC.filePath('files_external', 'ajax', 'removeMountPoint.php'), { mountPoint: mountPoint, mountType: mountType, applicable: applicable, isPersonal: isPersonal }); + $(tr).remove(); + }); + + $('#allowUserMounting').bind('change', function() { - // TODO save setting + if (this.checked) { + OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'yes'); + } else { + OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'no'); + } }); }); \ No newline at end of file diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php new file mode 100755 index 0000000000..a87319d33b --- /dev/null +++ b/apps/files_external/lib/config.php @@ -0,0 +1,231 @@ +. +*/ + +/** +* Class to configure the config/mount.php and data/$user/mount.php files +*/ +class OC_Mount_Config { + + const MOUNT_TYPE_GLOBAL = 'global'; + const MOUNT_TYPE_GROUP = 'group'; + const MOUNT_TYPE_USER = 'user'; + + /** + * Get details on each of the external storage backends, used for the mount config UI + * If the configuration parameter should be secret, add a '*' to the beginning of the value + * If the configuration parameter is a boolean, add a '!' to the beginning of the value + * If the configuration parameter is optional, add a '&' to the beginning of the value + * @return array + */ + public static function getBackends() { + return array( + 'OC_Filestorage_Local' => array('backend' => 'Local', 'configuration' => array('datadir' => 'Location')), + 'OC_Filestorage_AmazonS3' => array('backend' => 'Amazon S3', 'configuration' => array('key' => 'Key', 'secret' => '*Secret', 'bucket' => 'Bucket')), + 'OC_Filestorage_FTP' => array('backend' => 'FTP', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'root' => '&Root', 'secure' => '!Secure ftps://')), + 'OC_Filestorage_SWIFT' => array('backend' => 'OpenStack Swift', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'token' => '*Token', 'root' => '&Root', 'secure' => '!Secure ftps://')), + 'OC_Filestorage_SMB' => array('backend' => 'SMB', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'root' => '&Root')), + 'OC_Filestorage_DAV' => array('backend' => 'WebDAV', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'root' => '&Root', 'secure' => '!Secure https://')) + ); + } + + /** + * Get the system mount points + * The returned array is not in the same format as getUserMountPoints() + * @return array + */ + public static function getSystemMountPoints() { + $mountPoints = self::readData(false); + $backends = self::getBackends(); + $system = array(); + if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) { + foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) { + foreach ($mounts as $mountPoint => $mount) { + // Remove '/$user/files/' from mount point + $mountPoint = substr($mountPoint, 13); + // Merge the mount point into the current mount points + if (isset($system[$mountPoint]) && $system[$mountPoint]['configuration'] == $mount['options']) { + $system[$mountPoint]['applicable']['groups'] = array_merge($system[$mountPoint]['applicable']['groups'], array($group)); + } else { + $system[$mountPoint] = array('class' => $mount['class'], 'backend' => $backends[$mount['class']]['backend'], 'configuration' => $mount['options'], 'applicable' => array('groups' => array($group), 'users' => array())); + } + } + } + } + if (isset($mountPoints[self::MOUNT_TYPE_USER])) { + foreach ($mountPoints[self::MOUNT_TYPE_USER] as $user => $mounts) { + foreach ($mounts as $mountPoint => $mount) { + // Remove '/$user/files/' from mount point + $mountPoint = substr($mountPoint, 13); + // Merge the mount point into the current mount points + if (isset($system[$mountPoint]) && $system[$mountPoint]['configuration'] == $mount['options']) { + $system[$mountPoint]['applicable']['users'] = array_merge($system[$mountPoint]['applicable']['users'], array($user)); + } else { + $system[$mountPoint] = array('class' => $mount['class'], 'backend' => $backends[$mount['class']]['backend'], 'configuration' => $mount['options'], 'applicable' => array('groups' => array(), 'users' => array($user))); + } + } + } + } + return $system; + } + + /** + * Get the personal mount points of the current user + * The returned array is not in the same format as getUserMountPoints() + * @return array + */ + public static function getPersonalMountPoints() { + $mountPoints = self::readData(true); + $backends = self::getBackends(); + $uid = OCP\User::getUser(); + $personal = array(); + if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) { + foreach ($mountPoints[self::MOUNT_TYPE_USER][$uid] as $mountPoint => $mount) { + // Remove '/$user/files/' from mount point + $personal[substr($mountPoint, 13)] = array('class' => $mount['class'], 'backend' => $backends[$mount['class']]['backend'], 'configuration' => $mount['options']); + } + } + return $personal; + } + + + /** + * Add a mount point to the filesystem + * @param string Mount point + * @param string Backend class + * @param array Backend parameters for the class + * @param string MOUNT_TYPE_GROUP | MOUNT_TYPE_USER + * @param string User or group to apply mount to + * @param bool Personal or system mount point i.e. is this being called from the personal or admin page + * @return bool + */ + public static function addMountPoint($mountPoint, $class, $classOptions, $mountType, $applicable, $isPersonal = false) { + if ($isPersonal) { + // Verify that the mount point applies for the current user + // Prevent non-admin users from mounting local storage + if ($applicable != OCP\User::getUser() || $class == 'OC_Filestorage_Local') { + return false; + } + } + $mount = array($applicable => array('/$user/files/'.$mountPoint => array('class' => $class, 'options' => $classOptions))); + $mountPoints = self::readData($isPersonal); + // Merge the new mount point into the current mount points + if (isset($mountPoints[$mountType])) { + if (isset($mountPoints[$mountType][$applicable])) { + $mountPoints[$mountType][$applicable] = array_merge($mountPoints[$mountType][$applicable], $mount[$applicable]); + } else { + $mountPoints[$mountType] = array_merge($mountPoints[$mountType], $mount); + } + } else { + $mountPoints[$mountType] = $mount; + } + self::writeData($isPersonal, $mountPoints); + return true; + } + + /** + * + * @param string Mount point + * @param string MOUNT_TYPE_GROUP | MOUNT_TYPE_USER + * @param string User or group to remove mount from + * @param bool Personal or system mount point + * @return bool + */ + public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) { + // Verify that the mount point applies for the current user + if ($isPersonal && $applicable != OCP\User::getUser()) { + return false; + } + $mountPoints = self::readData($isPersonal); + // Remove mount point + unset($mountPoints[$mountType][$applicable]['/$user/files/'.$mountPoint]); + // Unset parent arrays if empty + if (empty($mountPoints[$mountType][$applicable])) { + unset($mountPoints[$mountType][$applicable]); + if (empty($mountPoints[$mountType])) { + unset($mountPoints[$mountType]); + } + } + self::writeData($isPersonal, $mountPoints); + return true; + } + + /** + * Read the mount points in the config file into an array + * @param bool Personal or system config file + * @return array + */ + private static function readData($isPersonal) { + if ($isPersonal) { + $file = OC::$SERVERROOT.'/data/'.OCP\User::getUser().'/mount.php'; + } else { + $file = OC::$SERVERROOT.'/config/mount.php'; + } + if (is_file($file)) { + $mountPoints = include($file); + if (is_array($mountPoints)) { + return $mountPoints; + } + } + return array(); + } + + /** + * Write the mount points to the config file + * @param bool Personal or system config file + * @param array Mount points + */ + private static function writeData($isPersonal, $data) { + if ($isPersonal) { + $file = OC::$SERVERROOT.'/data/'.OCP\User::getUser().'/mount.php'; + } else { + $file = OC::$SERVERROOT.'/config/mount.php'; + } + $content = " array (\n"; + foreach ($data[self::MOUNT_TYPE_GROUP] as $group => $mounts) { + $content .= "\t\t'".$group."' => array (\n"; + foreach ($mounts as $mountPoint => $mount) { + $content .= "\t\t\t'".$mountPoint."' => ".str_replace("\n", '', var_export($mount, true)).",\n"; + + } + $content .= "\t\t),\n"; + } + $content .= "\t),\n"; + } + if (isset($data[self::MOUNT_TYPE_USER])) { + $content .= "\t'user' => array (\n"; + foreach ($data[self::MOUNT_TYPE_USER] as $user => $mounts) { + $content .= "\t\t'".$user."' => array (\n"; + foreach ($mounts as $mountPoint => $mount) { + $content .= "\t\t\t'".$mountPoint."' => ".str_replace("\n", '', var_export($mount, true)).",\n"; + } + $content .= "\t\t),\n"; + } + $content .= "\t),\n"; + } + $content .= ");\n?>"; + @file_put_contents($file, $content); + } + +} + +?> \ No newline at end of file diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php new file mode 100755 index 0000000000..32e0874244 --- /dev/null +++ b/apps/files_external/personal.php @@ -0,0 +1,34 @@ +. +*/ + +OCP\Util::addScript('files_external', 'settings'); +OCP\Util::addStyle('files_external', 'settings'); +$backends = OC_Mount_Config::getBackends(); +// Remove local storage +unset($backends['OC_Filestorage_Local']); +$tmpl = new OCP\Template('files_external', 'settings'); +$tmpl->assign('isAdminPage', false); +$tmpl->assign('mounts', OC_Mount_Config::getPersonalMountPoints()); +$tmpl->assign('backends', $backends); +return $tmpl->fetchPage(); + +?> \ No newline at end of file diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php index ce1b308d75..983855ecdc 100644 --- a/apps/files_external/settings.php +++ b/apps/files_external/settings.php @@ -20,16 +20,15 @@ * License along with this library. If not, see . */ -OCP\Util::addscript('files_external', 'settings'); -OCP\Util::addstyle('files_external', 'settings'); +OCP\Util::addScript('files_external', 'settings'); +OCP\Util::addStyle('files_external', 'settings'); $tmpl = new OCP\Template('files_external', 'settings'); -$tmpl->assign('allowUserMounting', 'yes'); $tmpl->assign('isAdminPage', true); -$tmpl->assign('storage', array()); +$tmpl->assign('mounts', OC_Mount_Config::getSystemMountPoints()); +$tmpl->assign('backends', OC_Mount_Config::getBackends()); $tmpl->assign('groups', OC_Group::getGroups()); -$tmpl->assign('backends', array('Amazon S3', 'FTP', 'Google Drive', 'SWIFT', 'WebDAV')); -$tmpl->assign('configurations', ''); -$tmpl->assign('options', array('Encrypt', 'Version control', 'Allow sharing')); +$tmpl->assign('users', OCP\User::getUsers()); +$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes')); return $tmpl->fetchPage(); ?> \ No newline at end of file diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index e34c032239..9f65cfca96 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -1,70 +1,82 @@
t('External Storage'); ?> - - +
- + + - - - '.$l->t('Applicable').''; ?> + + '.$l->t('Applicable').''; ?> - - 'addStorage', 'mount' => ''))); ?> - - data-storage-id=""> - - + array())); ?> + $mount): ?> + > + + + - - - + - - - +
t('Type'); ?>t('Mount point'); ?>t('Backend'); ?> t('Configuration'); ?>t('Mount Location'); ?>t('Options'); ?> 
-
+ > - - $value): ?> - - - - - - + + + $value): ?> + + + + + + + + + + + + + + - ' data-applicable-users=''> + ><?php echo $l->t('Delete'); ?>><?php echo $l->t('Delete'); ?>
- - +
/>