WIP on sharing prompt to ask about mounting new share

This commit is contained in:
nathangray 2020-10-20 16:47:26 -06:00
parent 7c9e1c98ec
commit 5bf4d4866f
9 changed files with 500 additions and 274 deletions

View File

@ -334,7 +334,7 @@
et2.load(data.name,data.url,data.data);
if (typeof data.response != 'undefined')
{
var json_request = egw(window).json();
var json_request = egw(window).json("");
json_request.handleResponse({response: data.response});
}
});

View File

@ -180,6 +180,14 @@ class Base
}
unset(self::$fstab[$path], $GLOBALS['egw_info']['server']['vfs_fstab'][$path]);
Config::save_value('vfs_fstab', $GLOBALS['egw_info']['server']['vfs_fstab'],'phpgwapi');
unset($GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'][$path]);
unset($_SESSION[Api\Session::EGW_INFO_CACHE]['user']['preferences']['common']['vfs_fstab'][$path]);
$prefs = new Api\Preferences();
$prefs->read_repository();
unset($prefs->user['common']['vfs_fstab'][$path]);
$prefs->save_repository();
// invalidate session cache
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited
{

View File

@ -14,6 +14,7 @@ namespace EGroupware\Api\Vfs;
use EGroupware\Api;
use EGroupware\Api\Vfs;
use EGroupware\Filemanager\Sharing\HiddenUpload;
/**
* VFS sharing for a folder, but always read-only. A /Upload directory is used to receive uploads without allowing any
@ -187,7 +188,7 @@ class HiddenUploadSharing extends Sharing
$GLOBALS['egw_info']['flags']['currentapp'] = 'filemanager';
Api\Framework::includeCSS('filemanager', 'sharing');
$ui = new UploadSharingUi();
$ui = new HiddenUpload();
$ui->index();
}
@ -204,138 +205,3 @@ class HiddenUploadSharing extends Sharing
static::setup_share(true, $this->share);
}
}
if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'))
{
require_once __DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php';
class UploadSharingUi extends SharingUi
{
/**
* Get active view - override so it points to this class
*
* @return string
*/
public static function get_view()
{
return array(new UploadSharingUi(), 'listview');
}
/**
* Filemanager listview
*
* Override to customize for sharing with a hidden upload directory.
* Everything not in the upload directory is readonly, but we make it look like you can upload.
* The upload directory is not shown.
*
* @param array $content
* @param string $msg
*/
function listview(array $content=null,$msg=null)
{
$this->etemplate = $this->etemplate ? $this->etemplate : new Api\Etemplate(static::LIST_TEMPLATE);
if (isset($GLOBALS['egw']->sharing) && $GLOBALS['egw']->sharing->has_hidden_upload())
{
// Tell client side that the path is actually writable
$content['initial_path_readonly'] = false;
// No new anything
$this->etemplate->disableElement('nm[new]');
$this->etemplate->setElementAttribute('nm[button][createdir]', 'readonly', true);
// Take over upload, change target and conflict strategy
$path = Vfs::concat(self::get_home_dir(), Sharing::HIDDEN_UPLOAD_DIR);
$target = str_replace('\\', '\\\\', __CLASS__);
$this->etemplate->setElementAttribute('nm[upload]', 'onFinishOne', "app.filemanager.upload(ev, 1, '$path', 'rename', '{$target}::ajax_action')");
}
return parent::listview($content, $msg);
}
/**
* Deal with an uploaded file.
* Overridden from the parent to change the message and message type
*
* @param string $action Should be 'upload'
* @param $selected Array of file information
* @param string $dir Target directory
* @param $props
* @param string[] $arr Result
*
* @throws Api\Exception\AssertionFailed
*/
protected static function handle_upload_action(string $action, $selected, $dir, $props, &$arr)
{
Api\Translation::add_app('filemanager');
$vfs = Vfs::mount();
$GLOBALS['egw']->sharing->redo();
parent::handle_upload_action($action, $selected, $dir, $props, $arr);
$arr['msg'] .= "\n" . lang("The uploaded file is only visible to the person sharing these files with you, not to yourself or other people knowing this sharing link.");
$arr['type'] = 'notice';
}
protected function is_hidden_upload_dir($directory)
{
if (!isset($GLOBALS['egw']->sharing)) return false;
// Just hide anything that is 'Upload' mounted where we expect, not just this share, to avoid exposing when
// more than one share is used
$mounts = Vfs::mount();
return Vfs::is_dir($directory) && '/'.Vfs::basename($directory) == Sharing::HIDDEN_UPLOAD_DIR && $mounts[$directory];
}
/**
* Callback to fetch the rows for the nextmatch widget
*
* @param array $query
* @param array &$rows
* @return int
*
* @throws Api\Json\Exception
*/
function get_rows(&$query, &$rows)
{
$hidden_upload = (isset($GLOBALS['egw']->sharing) && $GLOBALS['egw']->sharing->has_hidden_upload());
// Not allowed in hidden upload dir
$check_path = Sharing::HIDDEN_UPLOAD_DIR . (substr($query['path'], -1) == '/' ? '/' : '');
if(($length = strlen($check_path)) && (substr($query['path'], -$length) === $check_path))
{
// only redirect, if it would be to some other location, gives redirect-loop otherwise
if ($query['path'] != ($path = static::get_home_dir()))
{
// we will leave here, since we are not allowed, go back to root
// TODO: Give message about it, redirect to home dir
}
$rows = array();
return 0;
}
// Get file list from parent
$total = parent::get_rows($query, $rows);
if(! $hidden_upload )
{
return $total;
}
// tell client-side that this directory is writeable - allows upload + button
$response = Api\Json\Response::get();
$response->call('app.filemanager.set_readonly', $query['path'], false);
// Hide the hidden upload directory, mark everything else as readonly
foreach($rows as $key => &$row)
{
if($this->is_hidden_upload_dir($row['path']))
{
unset($rows[$key]);
$total--;
continue;
}
$row['class'] .= 'noEdit noDelete ';
}
return $total;
}
}
}

View File

@ -15,8 +15,9 @@ namespace EGroupware\Api\Vfs;
use EGroupware\Api;
use EGroupware\Api\Vfs;
use EGroupware\Collabora\Wopi;
use filemanager_ui;
use EGroupware\Filemanager\Sharing\AnonymousList;
use EGroupware\Filemanager\Sharing\Ui;
use EGroupware\Filemanager\Sharing\Ui as ShareUi;
/**
* VFS sharing
@ -119,7 +120,7 @@ class Sharing extends \EGroupware\Api\Sharing
// ToDo: handle there's already something there with that name (incl. maybe the same share!)
Vfs::$is_root = true;
if (!Vfs::mount(Vfs\Sharing\StreamWrapper::share2url($share), $share['share_root'], false, false, $clear_fstab))
if (!Vfs::mount(Vfs\Sharing\StreamWrapper::share2url($share), $share['share_root'], false, false, false))
{
sleep(1);
return static::share_fail(
@ -129,8 +130,7 @@ class Sharing extends \EGroupware\Api\Sharing
}
Vfs::$is_root = false;
Api\Framework::message(lang('Share has been mounted into you shares directory').': '.$share['share_root'], 'success');
// ToDo: ask user if he want's the share permanently mounted
// get_ui() will ask user if he wants the share permanently mounted
return;
}
@ -233,6 +233,38 @@ class Sharing extends \EGroupware\Api\Sharing
*/
public function get_ui()
{
// Ask about the share, if the user is not anonymous.
// * Link has already been opened in a new tab by this point *
if($GLOBALS['egw_info']['user']['account_lid'] !== 'anonymous' && $GLOBALS['egw_info']['user']['account_id'] !== $this->share['owner'])
{
// Check to see if this is already permanent mounted share
$mount_target = Vfs\Sharing\StreamWrapper::share2url($this->share);
if(($mounted = array_search($mount_target,$GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'])))
{
Api\Json\Response::get()->apply('window.opener.egw.open_link',[
Api\Framework::link('/index.php',[
'menuaction' => 'filemanager.filemanager_ui.index',
'path' => $mounted
]),'filemanager',false,'filemanager'
]);
}
else
{
// New share, ask about it
Api\Json\Response::get()->apply('window.opener.egw.open_link',[
Api\Framework::link('/index.php',[
'menuaction' => 'filemanager.EGroupware\\Filemanager\\Sharing\\Ui.share_received',
'token' => $this->share['share_token']
]),'filemanager','600x150','filemanager'
]);
}
Api\Json\Response::get()->apply('window.close');
// Still need to load the list after though, since loading it processes what we just added
$ui = new \filemanager_ui();
return $ui->index();
}
// run full eTemplate2 UI for directories
$_GET['path'] = $this->share['share_root'];
$GLOBALS['egw_info']['user']['preferences']['filemanager']['nm_view'] = 'tile';
@ -240,7 +272,7 @@ class Sharing extends \EGroupware\Api\Sharing
$GLOBALS['egw_info']['flags']['js_link_registry'] = true;
$GLOBALS['egw_info']['flags']['currentapp'] = 'filemanager';
Api\Framework::includeCSS('filemanager', 'sharing');
$ui = new SharingUi();
$ui = new AnonymousList();
$ui->index();
}
@ -547,133 +579,3 @@ class Sharing extends \EGroupware\Api\Sharing
}
}
}
if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'))
{
require_once __DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php';
class SharingUi extends filemanager_ui
{
/**
* Constructor
*
* Reimplemented to load filemanager translations
*/
function __construct()
{
parent::__construct();
Api\Translation::add_app('filemanager');
}
/**
* Get active view - override so it points to this class
*
* @return callable
*/
public static function get_view()
{
return array(new SharingUi(), 'listview');
}
/**
* Filemanager listview
*
* @param array $content
* @param string $msg
*/
function listview(array $content=null,$msg=null)
{
$this->etemplate = $this->etemplate ? $this->etemplate : new Api\Etemplate(static::LIST_TEMPLATE);
// Override and take over get_rows so we can customize
$content['nm']['get_rows'] = '.' . get_class($this) . '.get_rows';
return parent::listview($content, $msg);
}
/**
* Get the configured start directory for the current user
*
* @return string
*/
static function get_home_dir()
{
return $GLOBALS['egw']->sharing->get_root();
}
/**
* Context menu
*
* @return array
*/
public static function get_actions()
{
$actions = parent::get_actions();
$group = 1;
// do not add edit setting action when we are in sharing
unset($actions['edit']);
if (Vfs::is_writable($GLOBALS['egw']->sharing->get_root()))
{
return $actions;
}
$actions+= array(
'egw_copy' => array(
'enabled' => false,
'group' => $group + 0.5,
'hideOnDisabled' => true
),
'egw_copy_add' => array(
'enabled' => false,
'group' => $group + 0.5,
'hideOnDisabled' => true
),
'paste' => array(
'enabled' => false,
'group' => $group + 0.5,
'hideOnDisabled' => true
),
);
return $actions;
}
protected function get_vfs_options($query)
{
$options = parent::get_vfs_options($query);
// Hide symlinks
// TODO: This hides everything, see Vfs::_check_add() line 648
//$options['type'] = '!l';
return $options;
}
/**
* Callback to fetch the rows for the nextmatch widget
*
* @param array $query
* @param array &$rows
* @return int
*/
function get_rows(&$query, &$rows)
{
// Check for navigating outside share, redirect back to share
if (!empty($query['path']) && (!Vfs::stat($query['path'],false) || !Vfs::is_dir($query['path']) || !Vfs::check_access($query['path'],Vfs::READABLE)))
{
// only redirect, if it would be to some other location, gives redirect-loop otherwise
if ($query['path'] != ($path = static::get_home_dir()))
{
// we will leave here, since we are not allowed, go back to root
// TODO: Give message about it, redirect to home dir
}
$rows = array();
return 0;
}
// Get file list from parent
$total = parent::get_rows($query, $rows);
return $total;
}
}
}

View File

@ -842,7 +842,17 @@ class filemanager_ui
// feeding the links to dirs to Vfs::find() deletes the content of the dirs, not just the link!
foreach($selected as $key => $path)
{
if (!Vfs::is_dir($path) || Vfs::is_link($path))
if (Vfs::is_dir($path) && $GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'][$path])
{
// Trying to delete a share. Unmount.
$root = Vfs::$is_root;
Vfs::$is_root = true;
Vfs::umount($path);
Vfs::$is_root = $root;
++$dirs;
unset($selected[$key]);
}
else if (!Vfs::is_dir($path) || Vfs::is_link($path))
{
if (Vfs::unlink($path))
{
@ -1705,4 +1715,24 @@ class filemanager_ui
}
return $mode;
}
/**
* User just got a new share. Ask the questions, let them customize
*
* @param array $content
*/
public function share_received($content = array())
{
// Deal with returning data & changes
// Read info for display
$content['mount_location'] = $content['share_path'];
$sel_options = array();
$readonlys = array();
$preserve = $content;
$template = new Api\Etemplate("api.file_share_received");
$template->exec(__CLASS__ . '::' . __METHOD__, $content, $sel_options, $readonlys, $preserve, 2);
}
}

View File

@ -0,0 +1,144 @@
<?php
/**
* EGroupware - Filemanager - UI for sharing with anonymous user
*
* @link http://www.egroupware.org
* @package filemanager
* @author Nathan Gray
* @copyright (c) 2020 Nathan Gray
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
namespace EGroupware\Filemanager\Sharing;
use \filemanager_ui;
use EGroupware\Api;
use EGroupware\Api\Vfs;
/**
* This is the file list for an anonymous user.
* Logged in users may also end up here, but they will normally just use filemanager_ui
*/
class AnonymousList extends filemanager_ui
{
/**
* Constructor
*
* Reimplemented to load filemanager translations
*/
function __construct()
{
parent::__construct();
Api\Translation::add_app('filemanager');
}
/**
* Get active view - override so it points to this class
*
* @return callable
*/
public static function get_view()
{
return array(new AnonymousList(), 'listview');
}
/**
* Filemanager listview
*
* @param array $content
* @param string $msg
*/
function listview(array $content = null, $msg = null)
{
$this->etemplate = $this->etemplate ? $this->etemplate : new Api\Etemplate(static::LIST_TEMPLATE);
// Override and take over get_rows so we can customize
$content['nm']['get_rows'] = '.' . get_class($this) . '.get_rows';
return parent::listview($content, $msg);
}
/**
* Get the configured start directory for the current user
*
* @return string
*/
static function get_home_dir()
{
return $GLOBALS['egw']->sharing->get_root();
}
/**
* Context menu
*
* @return array
*/
public static function get_actions()
{
$actions = parent::get_actions();
$group = 1;
// do not add edit setting action when we are in sharing
unset($actions['edit']);
if (Vfs::is_writable($GLOBALS['egw']->sharing->get_root()))
{
return $actions;
}
$actions += array(
'egw_copy' => array(
'enabled' => false,
'group' => $group + 0.5,
'hideOnDisabled' => true
),
'egw_copy_add' => array(
'enabled' => false,
'group' => $group + 0.5,
'hideOnDisabled' => true
),
'paste' => array(
'enabled' => false,
'group' => $group + 0.5,
'hideOnDisabled' => true
),
);
return $actions;
}
protected function get_vfs_options($query)
{
$options = parent::get_vfs_options($query);
// Hide symlinks
// TODO: This hides everything, see Vfs::_check_add() line 648
//$options['type'] = '!l';
return $options;
}
/**
* Callback to fetch the rows for the nextmatch widget
*
* @param array $query
* @param array &$rows
* @return int
*/
function get_rows(&$query, &$rows)
{
// Check for navigating outside share, redirect back to share
if (!empty($query['path']) && (!Vfs::stat($query['path'], false) || !Vfs::is_dir($query['path']) || !Vfs::check_access($query['path'], Vfs::READABLE)))
{
// only redirect, if it would be to some other location, gives redirect-loop otherwise
if ($query['path'] != ($path = static::get_home_dir()))
{
// we will leave here, since we are not allowed, go back to root
// TODO: Give message about it, redirect to home dir
}
$rows = array();
return 0;
}
// Get file list from parent
$total = parent::get_rows($query, $rows);
return $total;
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace EGroupware\Filemanager\Sharing;
use EGroupware\Api\Vfs;
use EGroupware\Api\Vfs\Sharing;
use EGroupware\Api\Vfs\UploadSharingUi;
class HiddenUpload extends AnonymousList
{
/**
* Get active view - override so it points to this class
*
* @return string
*/
public static function get_view()
{
return array(new HiddenUpload(), 'listview');
}
/**
* Filemanager listview
*
* Override to customize for sharing with a hidden upload directory.
* Everything not in the upload directory is readonly, but we make it look like you can upload.
* The upload directory is not shown.
*
* @param array $content
* @param string $msg
*/
function listview(array $content=null,$msg=null)
{
$this->etemplate = $this->etemplate ? $this->etemplate : new Api\Etemplate(static::LIST_TEMPLATE);
if (isset($GLOBALS['egw']->sharing) && $GLOBALS['egw']->sharing->has_hidden_upload())
{
// Tell client side that the path is actually writable
$content['initial_path_readonly'] = false;
// No new anything
$this->etemplate->disableElement('nm[new]');
$this->etemplate->setElementAttribute('nm[button][createdir]', 'readonly', true);
// Take over upload, change target and conflict strategy
$path = Vfs::concat(self::get_home_dir(), Sharing::HIDDEN_UPLOAD_DIR);
$target = str_replace('\\', '\\\\', __CLASS__);
$this->etemplate->setElementAttribute('nm[upload]', 'onFinishOne', "app.filemanager.upload(ev, 1, '$path', 'rename', '{$target}::ajax_action')");
}
return parent::listview($content, $msg);
}
/**
* Deal with an uploaded file.
* Overridden from the parent to change the message and message type
*
* @param string $action Should be 'upload'
* @param $selected Array of file information
* @param string $dir Target directory
* @param $props
* @param string[] $arr Result
*
* @throws Api\Exception\AssertionFailed
*/
protected static function handle_upload_action(string $action, $selected, $dir, $props, &$arr)
{
Api\Translation::add_app('filemanager');
$vfs = Vfs::mount();
$GLOBALS['egw']->sharing->redo();
parent::handle_upload_action($action, $selected, $dir, $props, $arr);
$arr['msg'] .= "\n" . lang("The uploaded file is only visible to the person sharing these files with you, not to yourself or other people knowing this sharing link.");
$arr['type'] = 'notice';
}
protected function is_hidden_upload_dir($directory)
{
if (!isset($GLOBALS['egw']->sharing)) return false;
// Just hide anything that is 'Upload' mounted where we expect, not just this share, to avoid exposing when
// more than one share is used
$mounts = Vfs::mount();
return Vfs::is_dir($directory) && '/'.Vfs::basename($directory) == Sharing::HIDDEN_UPLOAD_DIR && $mounts[$directory];
}
/**
* Callback to fetch the rows for the nextmatch widget
*
* @param array $query
* @param array &$rows
* @return int
*
* @throws Api\Json\Exception
*/
function get_rows(&$query, &$rows)
{
$hidden_upload = (isset($GLOBALS['egw']->sharing) && $GLOBALS['egw']->sharing->has_hidden_upload());
// Not allowed in hidden upload dir
$check_path = Sharing::HIDDEN_UPLOAD_DIR . (substr($query['path'], -1) == '/' ? '/' : '');
if(($length = strlen($check_path)) && (substr($query['path'], -$length) === $check_path))
{
// only redirect, if it would be to some other location, gives redirect-loop otherwise
if ($query['path'] != ($path = static::get_home_dir()))
{
// we will leave here, since we are not allowed, go back to root
// TODO: Give message about it, redirect to home dir
}
$rows = array();
return 0;
}
// Get file list from parent
$total = parent::get_rows($query, $rows);
if(! $hidden_upload )
{
return $total;
}
// tell client-side that this directory is writeable - allows upload + button
$response = Api\Json\Response::get();
$response->call('app.filemanager.set_readonly', $query['path'], false);
// Hide the hidden upload directory, mark everything else as readonly
foreach($rows as $key => &$row)
{
if($this->is_hidden_upload_dir($row['path']))
{
unset($rows[$key]);
$total--;
continue;
}
$row['class'] .= 'noEdit noDelete ';
}
return $total;
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* EGroupware - Filemanager - UI for sharing with regular users
*
* @link http://www.egroupware.org
* @package filemanager
* @author Nathan Gray
* @copyright (c) 2020 Nathan Gray
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
namespace EGroupware\Filemanager\Sharing;
use EGroupware\Api;
use EGroupware\Api\Vfs\Sharing;
use EGroupware\Api\Etemplate;
use EGroupware\Api\Framework;
use EGroupware\Api\Link;
use EGroupware\Api\Vfs;
/**
* User interface for dealing with filemanager shares
*/
class Ui
{
// These functions are allowed to be called from client
public $public_functions = Array(
'share_received' => true
);
/**
* The user has been given a new share. Ask what they want to do with it.
*
* This allows changing the name / mountpoint, and if they want to only
* mount it temporarily.
*
* @param array $content
*/
public function share_received($content = array())
{
// Deal with response
$this->handle_share_received($content);
// Set up for display
$template = new Api\Etemplate('filemanager.file_share_received');
$token = $content['token'] ?: $_GET['token'];
$share = Sharing::so()->read(['share_token' => $token]);
// This should already have been done, but we want the correct share root
Sharing::setup_share(true,$share);
$content = $share;
$content['share_passwd'] = !!$content['share_passwd'];
unset($content['share_id']);
$content['mount_location'] = Vfs::basename($content['share_root']);
$content['permanent'] = true;
$sel_options = array();
$readonlys = array();
$preserve = $content;
$preserve['url'] = Vfs\Sharing\StreamWrapper::share2url($share);
$template->exec('filemanager.'.__CLASS__.'.'.__FUNCTION__, $content, $sel_options, $readonlys, $preserve);
}
/**
* User submitted the share_received dialog, update the share appropriately
*
* @param array $content
*/
protected function handle_share_received($content = array())
{
if(!$content) return;
// Set persistent
$persistent_mount = $content['permanent'] ? $GLOBALS['egw_info']['user']['account_id'] : false;
$new_mountpoint = Vfs::dirname($content['share_root']) . '/' . $content['mount_location'];
Vfs::$is_root = true;
Vfs::umount($content['share_root']);
if(Vfs::mount($content['url'], $new_mountpoint, false, $persistent_mount))
{
$content['share_root'] = $new_mountpoint;
}
Vfs::$is_root = false;
// also save for current session
$GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'][$new_mountpoint] =
$_SESSION[Api\Session::EGW_INFO_CACHE]['user']['preferences']['common']['vfs_fstab'][$new_mountpoint] = $content['url'];
$GLOBALS['egw_info']['server']['vfs_fstab'] = Vfs::mount();
// Go to new share
Api\Json\Response::get()->apply('window.opener.egw.open_link',[
Api\Framework::link('/index.php',[
'menuaction' => "filemanager.filemanager_ui.index",
'path' => $content['share_root']
]), 'filemanager',false,'filemanager'
]);
Api\Framework::window_close();
}
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
<!-- $Id$ -->
<overlay>
<template id="filemanager.file_share_received" template="" lang="" group="0" version="20.1">
<grid width="100%">
<columns>
<column width="20%"/>
<column/>
</columns>
<rows>
<row>
<label value="Location"/>
<description id="share_root" />
</row>
<row>
<label value="Name"/>
<textbox id="mount_location"/>
</row>
<row>
<label value="Mount permanently" for="permanent"/>
<checkbox id="permanent"/>
</row>
<row class="dialogFooterToolbar">
<hbox>
<button label="Ok" id="ok" image="ok" background_image="1" align="center"/>
</hbox>
</row>
</rows>
</grid>
</template>
</overlay>