Cleanup, bugfix & refactoring of hidden upload folder.

This commit is contained in:
nathangray 2020-03-25 11:39:22 -06:00
parent b0b9df8e50
commit 895b1ebee9
7 changed files with 455 additions and 176 deletions

View File

@ -12,6 +12,8 @@
namespace EGroupware\Api;
use EGroupware\Api\Vfs\HiddenUploadSharing;
/**
* VFS sharing
*
@ -339,10 +341,14 @@ class Sharing
return '\\EGroupware\\Stylite\\Link\\Sharing';
}
}
else if (class_exists ('\EGroupware\Collabora\Wopi') && $share['share_writable'] == \EGroupware\Collabora\Wopi::WOPI_SHARED)
else if (class_exists ('\EGroupware\Collabora\Wopi') && (int)$share['share_writable'] === \EGroupware\Collabora\Wopi::WOPI_SHARED)
{
return '\\EGroupware\\Collabora\\Wopi';
}
else if ((int)$share['share_writable'] == HiddenUploadSharing::HIDDEN_UPLOAD)
{
return '\\'.__NAMESPACE__ . '\\'. 'Vfs\\HiddenUploadSharing';
}
}
catch(Exception $e){throw $e;}
return '\\'.__NAMESPACE__ . '\\'. (self::is_entry($share) ? 'Link' : 'Vfs'). '\\Sharing';
@ -657,11 +663,11 @@ class Sharing
{
throw new Exception\WrongParameter('Missing share path. Unable to create share.');
}
$class = self::get_share_class(array('share_path' => $path));
$extra = $extra + array(
'share_writable' => $writable,
'include_files' => $files
);
$class = self::get_share_class(array('share_path' => $path) + $extra);
$share = $class::create(
$action,
$path,
@ -683,6 +689,10 @@ class Sharing
{
case 'shareFilemanager':
$arr['title'] = lang('Filemanager directory');
break;
case 'shareUploadDir':
$arr['title'] = lang('Upload directory');
break;
}
$response = Json\Response::get();
$response->data($arr);

View File

@ -0,0 +1,306 @@
<?php
/**
* EGroupware API: VFS sharing with a hidden upload folder
*
* @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage Vfs
* @author Nathan Gray <ng@egroupware.org
* @copyright (c) 2020 Nathan Gray
*/
namespace EGroupware\Api\Vfs;
use EGroupware\Api;
use EGroupware\Api\Vfs;
/**
* VFS sharing for a folder, but always read-only. A /Upload directory is used to receive uploads without allowing any
* other changes. The /Upload directory is not visible to the anonymous users, only those logged in with Egw accounts
* and appropriate access.
*/
class HiddenUploadSharing extends Sharing
{
const HIDDEN_UPLOAD = 8; // Just picking these kind of in sequence as we go...
const HIDDEN_UPLOAD_DIR = '/Upload';
/**
* Modes for sharing files
*
* @var array
*/
static $modes = array(
self::HIDDEN_UPLOAD => array(
'label' => 'Hidden upload',
'title' => 'Share as readonly, but allow uploads. Uploads are hidden, and only accessable by those with an account',
)
);
/**
* Create sharing session
*
* Certain cases:
* a) there is not session $keep_session === null
* --> create new anon session with just filemanager rights and share as fstab
* b) there is a session $keep_session === true
* b1) current user is share owner (eg. checking the link)
* --> mount share under token additionally
* b2) current user not share owner
* b2a) need/use filemanager UI (eg. directory)
* --> destroy current session and continue with a)
* b2b) single file or WebDAV
* --> modify EGroupware enviroment for that request only, no change in session
*
* @param boolean $keep_session =null null: create a new session, true: try mounting it into existing (already verified) session
* @return string with sessionid, does NOT return if no session created
*/
public static function setup_share($keep_session, &$share)
{
// Get these before root is mounted readonly
$resolve_url = Vfs::resolve_url($share['share_path'], true, true, true, true);
$upload_dir = Vfs::concat($resolve_url, self::HIDDEN_UPLOAD_DIR);
// Parent mounts the root read-only
parent::setup_share($keep_session, $share);
// Mounting upload dir, has original share owner access (write)
Vfs::$is_root = true;
if (!Vfs::mount($upload_dir, Vfs::concat($share['share_root'], self::HIDDEN_UPLOAD_DIR), false, false, false))
{
sleep(1);
return static::share_fail(
'404 Not Found',
"Requested resource '/" . htmlspecialchars($share['share_token']) . "' does NOT exist!\n"
);
}
Vfs::$is_root = false;
Vfs::clearstatcache();
}
/**
* Create a new share
*
* @param string $action_id Name of the action used to create the share. Allows for customization.
* @param string $path either path in temp_dir or vfs with optional vfs scheme
* @param string $mode self::LINK: copy file in users tmp-dir or self::READABLE share given vfs file,
* if no vfs behave as self::LINK
* @param string $name filename to use for $mode==self::LINK, default basename of $path
* @param string|array $recipients one or more recipient email addresses
* @param array $extra =array() extra data to store
* @return array with share data, eg. value for key 'share_token'
* @throw Api\Exception\NotFound if $path not found
* @throw Api\Exception\AssertionFailed if user temp. directory does not exist and can not be created
*/
public static function create(string $action_id, $path, $mode, $name, $recipients, $extra = array())
{
if (!isset(self::$db))
{
self::$db = $GLOBALS['egw']->db;
}
$path = parent::validate_path($path, $mode);
// Set up anonymous upload directory
if ($action_id == 'shareUploadDir')
{
static::create_hidden_upload($path, $extra);
}
return parent::create($action_id, $path, $mode, $name, $recipients, $extra);
}
/**
* Check the given path for an anonymous upload directory, and create it if it does not
* exist yet. Anon upload directory is not visible over the share, and any files uploaded
* to the share are placed inside it instead.
*
* @param string $path Target path in the VFS
* @param string[] $extra Extra settings
*
* @throws Api\Exception\AssertionFailed
* @throws Api\Exception\NoPermission
* @throws Api\Exception\WrongParameter
*/
protected static function create_hidden_upload(string $path, &$extra)
{
$upload_dir = Vfs::concat($path, self::HIDDEN_UPLOAD_DIR);
if (($stat = Vfs::stat($upload_dir)) && !Vfs::check_access($upload_dir, Vfs::WRITABLE, $stat))
{
throw new Api\Exception\NoPermission("Upload directory exists, but you have no write permission");
}
if (!($stat = Vfs::stat($upload_dir)))
{
// Directory is not there, create it
if (!mkdir($upload_dir))
{
throw new Api\Exception\NoPermission("Could not make upload directory");
}
}
// Set flags so things work
$extra['share_writable'] = self::HIDDEN_UPLOAD;
}
/**
* Get actions for sharing an entry from filemanager
*
* @param string $appname
* @param int $group Current menu group
*
* @return array Actions
*/
public static function get_actions($appname, $group = 6)
{
$actions = parent::get_actions('filemanager', $group);
// Add in a hidden upload directory
$actions['share']['children']['shareUploadDir'] = array(
'caption' => 'Hidden uploads',
'group' => 1,
'order' => 30,
'enabled' => 'javaScript:app.filemanager.hidden_upload_enabled',
'onExecute' => 'javaScript:app.filemanager.share_link',
'data' => ['share_writable' => self::HIDDEN_UPLOAD],
'icon' => 'upload',
'hideOnDisabled' => true
);
return $actions;
}
/**
* Server a request on a share specified in REQUEST_URI
*/
public function get_ui()
{
// run full eTemplate2 UI for directories
$_GET['path'] = $this->share['share_root'];
$GLOBALS['egw_info']['user']['preferences']['filemanager']['nm_view'] = 'tile';
$_GET['cd'] = 'no';
$GLOBALS['egw_info']['flags']['js_link_registry'] = true;
$GLOBALS['egw_info']['flags']['currentapp'] = 'filemanager';
Api\Framework::includeCSS('filemanager', 'sharing');
$ui = new UploadSharingUi();
$ui->index();
}
/**
* Does this share have a hidden upload directory
*/
public function has_hidden_upload()
{
return (int)$this->share['share_writable'] == self::HIDDEN_UPLOAD;
}
}
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);
$this->etemplate->setElementAttribute('nm[upload]', 'onFinishOne', "app.filemanager.upload(ev, 1, '$path', 'rename')");
}
return parent::listview($content, $msg);
}
protected function is_hidden_upload_dir($directory)
{
if (!isset($GLOBALS['egw']->sharing)) return false;
return Vfs::is_dir($directory) && $directory == Vfs::concat( $GLOBALS['egw']->sharing->get_root(), Sharing::HIDDEN_UPLOAD_DIR );
}
/**
* 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
if($hidden_upload && strpos($query['path'], Sharing::HIDDEN_UPLOAD_DIR) === 0)
{
// 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

@ -203,63 +203,15 @@ class Sharing extends \EGroupware\Api\Sharing
{
if (!isset(self::$db)) self::$db = $GLOBALS['egw']->db;
// Parent puts the application as a prefix. If we're coming from there, pull it off
if(strpos($path, 'filemanager::') === 0)
{
list(,$path) = explode('::', $path);
}
if (empty($name)) $name = $path;
$path2tmp =& Api\Cache::getSession(__CLASS__, 'path2tmp');
$path = static::validate_path($path, $mode);
// allow filesystem path only for temp_dir
$temp_dir = $GLOBALS['egw_info']['server']['temp_dir'].'/';
if (substr($path, 0, strlen($temp_dir)) == $temp_dir)
{
$mode = self::LINK;
$exists = file_exists($path) && is_readable($path);
}
else
{
if(parse_url($path, PHP_URL_SCHEME) !== 'vfs')
{
$path = 'vfs://default'.($path[0] == '/' ? '' : '/').$path;
}
// We don't allow sharing links, share target instead
if(($target = Vfs::readlink($path)))
{
$path = $target;
}
if (($exists = ($stat = Vfs::stat($path)) && Vfs::check_access($path, Vfs::READABLE, $stat)))
{
// Make sure we get the correct path if sharing from a share
if(isset($GLOBALS['egw']->sharing) && $exists)
{
$resolved_stat = Vfs::parse_url($stat['url']);
$path = 'vfs://default'. $resolved_stat['path'];
}
$vfs_path = $path;
}
}
// check if file exists and is readable
if (!$exists)
{
throw new Api\Exception\NotFound("'$path' NOT found!");
}
// Set up anonymous upload directory
if($action_id == 'shareUploadDir')
{
static::create_hidden_upload($path, $mode, $name, $recipients, $extra);
}
if (empty($name)) $name = $path;
// check if file has been shared before, with identical attributes
if (($mode != self::LINK ))
{
return parent::create($action_id, $vfs_path ? $vfs_path : $path, $mode, $name, $recipients, $extra);
return parent::create($action_id, $path, $mode, $name, $recipients, $extra);
}
else
{
@ -302,47 +254,61 @@ class Sharing extends \EGroupware\Api\Sharing
}
/**
* Check the given path for an anonymous upload directory, and create it if it does not
* exist yet. Anon upload directory is not visible over the share, and any files uploaded
* to the share are placed inside it instead.
* Clean and validate the share path
*
* @param $path
* @param $mode
* @param $name
* @param $recipients
* @param $extra
* @param $path Proposed share path
* @param $mode Share mode
* @return string
*
* @throws Api\Exception\AssertionFailed
* @throws Api\Exception\NoPermission
* @throws Api\Exception\NotFound
* @throws Api\Exception\WrongParameter
*/
protected static function create_hidden_upload($path, $mode, $name, $recipients, &$extra)
protected static function validate_path($path, &$mode)
{
$upload_dir = Vfs::concat($path, self::HIDDEN_UPLOAD_DIR);
if(($stat = Vfs::stat($upload_dir)) && !Vfs::check_access($upload_dir, Vfs::WRITABLE, $stat))
// Parent puts the application as a prefix. If we're coming from there, pull it off
if(strpos($path, 'filemanager::') === 0)
{
throw new Api\Exception\NoPermission("Upload directory exists, but you have no write permission");
list(,$path) = explode('::', $path);
}
if (!($stat = Vfs::stat($upload_dir)))
// allow filesystem path only for temp_dir
$temp_dir = $GLOBALS['egw_info']['server']['temp_dir'].'/';
if (substr($path, 0, strlen($temp_dir)) == $temp_dir)
{
// Directory is not there, create it
if (!mkdir($upload_dir))
$mode = self::LINK;
$exists = file_exists($path) && is_readable($path);
}
else
{
if(parse_url($path, PHP_URL_SCHEME) !== 'vfs')
{
throw new Api\Exception\NoPermission("Could not make upload directory");
$path = 'vfs://default'.($path[0] == '/' ? '' : '/').$path;
}
// We don't allow sharing links, share target instead
if(($target = Vfs::readlink($path)))
{
$path = $target;
}
if (($exists = ($stat = Vfs::stat($path)) && Vfs::check_access($path, Vfs::READABLE, $stat)))
{
// Make sure we get the correct path if sharing from a share
if(isset($GLOBALS['egw']->sharing) && $exists)
{
$resolved_stat = Vfs::parse_url($stat['url']);
$path = 'vfs://default'. $resolved_stat['path'];
}
}
}
// check if file exists and is readable
if (!$exists)
{
throw new Api\Exception\NotFound("'$path' NOT found!");
}
// Set flags so things work
$extra['share_writable'] = self::HIDDEN_UPLOAD;
}
/**
* Does this share have a hidden upload directory
*/
public function has_hidden_upload()
{
return (int)$this->share['share_writable'] == self::HIDDEN_UPLOAD;
return $path;
}
/**
@ -419,17 +385,6 @@ class Sharing extends \EGroupware\Api\Sharing
$actions['share']['children']['shareReadonlyLink']['order'] = 22;
$actions['share']['children']['shareWritable']['group'] = 3;
// Add in a hidden upload directory
$actions['share']['children']['shareUploadDir'] = array(
'caption' => 'Hidden uploads',
'group' => 1,
'order' => 30,
'enabled' => 'javaScript:app.filemanager.hidden_upload_enabled',
'onExecute' => 'javaScript:app.filemanager.share_link',
'icon' => 'upload',
'hideOnDisabled' => true
);
// Add in merge to document
if (class_exists($appname.'_merge'))
{
@ -520,7 +475,7 @@ if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'
/**
* Get active view - override so it points to this class
*
* @return string
* @return callable
*/
public static function get_view()
{
@ -535,21 +490,10 @@ if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'
*/
function listview(array $content=null,$msg=null)
{
$this->etemplate = new Api\Etemplate(static::LIST_TEMPLATE);
$this->etemplate = $this->etemplate ? $this->etemplate : new Api\Etemplate(static::LIST_TEMPLATE);
// Override and take over get_rows so we can filter out upload directory, or other customisations
$content['nm']['get_rows'] = '.' . __CLASS__ . '.get_rows';
if (isset($GLOBALS['egw']->sharing) && $GLOBALS['egw']->sharing->has_hidden_upload())
{
// 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(static::get_home_dir(), Vfs\Sharing::HIDDEN_UPLOAD_DIR);
$this->etemplate->setElementAttribute('nm[upload]', 'onFinishOne', "app.filemanager.upload(ev, 1, '$path', 'rename')");
}
// Override and take over get_rows so we can customize
$content['nm']['get_rows'] = '.' . get_class($this) . '.get_rows';
return parent::listview($content, $msg);
}
@ -610,12 +554,6 @@ if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'
return $options;
}
protected function is_hidden_upload_dir($directory)
{
if (!isset($GLOBALS['egw']->sharing)) return false;
return Vfs::is_dir($directory) && $directory == Vfs::concat( $GLOBALS['egw']->sharing->get_root(), Vfs\Sharing::HIDDEN_UPLOAD_DIR );
}
/**
* Callback to fetch the rows for the nextmatch widget
*
@ -625,13 +563,8 @@ if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'
*/
function get_rows(&$query, &$rows)
{
$hidden_upload = (isset($GLOBALS['egw']->sharing) && $GLOBALS['egw']->sharing->has_hidden_upload());
// Check for navigating outside share, redirect back to share
if (!Vfs::stat($query['path'],false) || !Vfs::is_dir($query['path']) || !Vfs::check_access($query['path'],Vfs::READABLE) ||
// Not allowed in hidden upload dir
$hidden_upload && strpos($query['path'], Sharing::HIDDEN_UPLOAD_DIR) === 0)
if (!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()))
@ -646,26 +579,6 @@ if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'
// Get file list from parent
$total = parent::get_rows($query, $rows);
if(! $hidden_upload )
{
return $total;
}
// tell client-side if directory is writeable or not
$response = Api\Json\Response::get();
$response->call('app.filemanager.set_readonly', $query['path'], true);
// 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

@ -216,7 +216,7 @@ class filemanager_ui
'order' => 10,
'onExecute' => 'javaScript:app.filemanager.copy_link'
),
'share' => EGroupware\Api\Vfs\Sharing::get_actions('filemanager', ++$group)['share'],
'share' => EGroupware\Api\Vfs\HiddenUploadSharing::get_actions('filemanager', ++$group)['share'],
'documents' => filemanager_merge::document_action(
$GLOBALS['egw_info']['user']['preferences']['filemanager']['document_dir'],
++$group, 'Insert in document', 'document_',
@ -470,44 +470,77 @@ class filemanager_ui
{
$tpl = $this->etemplate ? $this->etemplate : new Etemplate(static::LIST_TEMPLATE);
if($msg) Framework::message($msg);
if ($msg)
{
Framework::message($msg);
}
if (($content['nm']['action'] || $content['nm']['rows']) && (empty($content['button']) || !isset($content['button'])))
{
if ($content['nm']['action'])
{
$msg = static::action($content['nm']['action'],$content['nm']['selected'],$content['nm']['path']);
if($msg) Framework::message($msg);
$msg = static::action($content['nm']['action'], $content['nm']['selected'], $content['nm']['path']);
if ($msg)
{
Framework::message($msg);
}
// clean up after action
unset($content['nm']['selected']);
// reset any occasion where action may be stored, as it may be ressurected out of the helpers by etemplate, which is quite unconvenient in case of action delete
if (isset($content['nm']['action'])) unset($content['nm']['action']);
if (isset($content['nm']['nm_action'])) unset($content['nm']['nm_action']);
if (isset($content['nm_action'])) unset($content['nm_action']);
if (isset($content['nm']['action']))
{
unset($content['nm']['action']);
}
if (isset($content['nm']['nm_action']))
{
unset($content['nm']['nm_action']);
}
if (isset($content['nm_action']))
{
unset($content['nm_action']);
}
// we dont use ['nm']['rows']['delete'], so unset it, if it is present
if (isset($content['nm']['rows']['delete'])) unset($content['nm']['rows']['delete']);
if (isset($content['nm']['rows']['delete']))
{
unset($content['nm']['rows']['delete']);
}
}
elseif($content['nm']['rows']['delete'])
elseif ($content['nm']['rows']['delete'])
{
$msg = static::action('delete',array_keys($content['nm']['rows']['delete']),$content['nm']['path']);
if($msg) Framework::message($msg);
$msg = static::action('delete', array_keys($content['nm']['rows']['delete']), $content['nm']['path']);
if ($msg)
{
Framework::message($msg);
}
// clean up after action
unset($content['nm']['rows']['delete']);
// reset any occasion where action may be stored, as we use ['nm']['rows']['delete'] anyhow
// we clean this up, as it may be ressurected out of the helpers by etemplate, which is quite unconvenient in case of action delete
if (isset($content['nm']['action'])) unset($content['nm']['action']);
if (isset($content['nm']['nm_action'])) unset($content['nm']['nm_action']);
if (isset($content['nm_action'])) unset($content['nm_action']);
if (isset($content['nm']['selected'])) unset($content['nm']['selected']);
if (isset($content['nm']['action']))
{
unset($content['nm']['action']);
}
if (isset($content['nm']['nm_action']))
{
unset($content['nm']['nm_action']);
}
if (isset($content['nm_action']))
{
unset($content['nm_action']);
}
if (isset($content['nm']['selected']))
{
unset($content['nm']['selected']);
}
}
unset($content['nm']['rows']);
Api\Cache::setSession('filemanager', 'index',$content['nm']);
Api\Cache::setSession('filemanager', 'index', $content['nm']);
}
// be tolerant with (in previous versions) not correct urlencoded pathes
if ($content['nm']['path'][0] == '/' && !Vfs::stat($content['nm']['path'],true) && Vfs::stat(urldecode($content['nm']['path'])))
if ($content['nm']['path'][0] == '/' && !Vfs::stat($content['nm']['path'], true) && Vfs::stat(urldecode($content['nm']['path'])))
{
$content['nm']['path'] = urldecode($content['nm']['path']);
}
@ -518,22 +551,22 @@ class filemanager_ui
$button = key($content['button']);
unset($content['button']);
}
switch($button)
switch ($button)
{
case 'upload':
if (!$content['upload'])
{
Framework::message(lang('You need to select some files first!'),'error');
Framework::message(lang('You need to select some files first!'), 'error');
break;
}
$upload_success = $upload_failure = array();
foreach(isset($content['upload'][0]) ? $content['upload'] : array($content['upload']) as $upload)
foreach (isset($content['upload'][0]) ? $content['upload'] : array($content['upload']) as $upload)
{
// encode chars which special meaning in url/vfs (some like / get removed!)
$to = Vfs::concat($content['nm']['path'],Vfs::encodePathComponent($upload['name']));
$to = Vfs::concat($content['nm']['path'], Vfs::encodePathComponent($upload['name']));
if ($upload &&
(Vfs::is_writable($content['nm']['path']) || Vfs::is_writable($to)) &&
copy($upload['tmp_name'],Vfs::PREFIX.$to))
(Vfs::is_writable($content['nm']['path']) || Vfs::is_writable($to)) &&
copy($upload['tmp_name'], Vfs::PREFIX . $to))
{
$upload_success[] = $upload['name'];
}
@ -545,12 +578,12 @@ class filemanager_ui
$content['nm']['msg'] = '';
if ($upload_success)
{
Framework::message( count($upload_success) == 1 && !$upload_failure ? lang('File successful uploaded.') :
lang('%1 successful uploaded.',implode(', ',$upload_success)));
Framework::message(count($upload_success) == 1 && !$upload_failure ? lang('File successful uploaded.') :
lang('%1 successful uploaded.', implode(', ', $upload_success)));
}
if ($upload_failure)
{
Framework::message(lang('Error uploading file!')."\n".etemplate::max_upload_size_message(),'error');
Framework::message(lang('Error uploading file!') . "\n" . etemplate::max_upload_size_message(), 'error');
}
break;
}
@ -558,12 +591,12 @@ class filemanager_ui
$readonlys['button[mailpaste]'] = !isset($GLOBALS['egw_info']['user']['apps']['mail']);
$sel_options['filter'] = array(
'' => 'Current directory',
'2' => 'Directories sorted in',
'3' => 'Show hidden files',
'4' => 'All subdirectories',
'5' => 'Files from links',
'0' => 'Files from subdirectories',
'' => 'Current directory',
'2' => 'Directories sorted in',
'3' => 'Show hidden files',
'4' => 'All subdirectories',
'5' => 'Files from links',
'0' => 'Files from subdirectories',
);
$sel_options['new'] = self::convertActionsToselOptions($content['nm']['actions']['new']['children']);
@ -574,14 +607,17 @@ class filemanager_ui
$tpl->setElementAttribute('nm[upload]', 'drop_target', 'popupMainDiv');
}
// Set view button to match current settings
if($content['nm']['view'] == 'tile')
if ($content['nm']['view'] == 'tile')
{
$tpl->setElementAttribute('nm[button][change_view]','statustext',lang('List view'));
$tpl->setElementAttribute('nm[button][change_view]','image','list_row');
$tpl->setElementAttribute('nm[button][change_view]', 'statustext', lang('List view'));
$tpl->setElementAttribute('nm[button][change_view]', 'image', 'list_row');
}
// if initial load is done via GET request (idots template or share.php)
// get_rows cant call app.filemanager.set_readonly, so we need to do that here
$content['initial_path_readonly'] = !Vfs::is_writable($content['nm']['path']);
if (!array_key_exists('initial_path_readonly', $content))
{
$content['initial_path_readonly'] = !Vfs::is_writable($content['nm']['path']);
}
$tpl->exec('filemanager.filemanager_ui.index',$content,$sel_options,$readonlys,array('nm' => $content['nm']));
}

View File

@ -978,7 +978,13 @@ var filemanagerAPP = /** @class */ (function (_super) {
if (!path) {
_senders[0] = { id: this.get_path() };
}
// Pass along any action data
var _extra = {};
for (var i in _action.data) {
if (i.indexOf('share') == 0) {
_extra[i] = _action.data[i];
}
}
_super.prototype.share_link.call(this, _action, _senders, _target, _writable, _files, _callback, _extra);
};
/**

View File

@ -1182,7 +1182,15 @@ export class filemanagerAPP extends EgwApp
{
_senders[0] = {id: this.get_path()};
}
// Pass along any action data
let _extra = {};
for(let i in _action.data)
{
if(i.indexOf('share') == 0)
{
_extra[i] = _action.data[i];
}
}
super.share_link(_action, _senders, _target, _writable, _files, _callback, _extra);
}

View File

@ -2664,7 +2664,7 @@ class mail_compose
// create share
if ($filemode == Vfs\Sharing::WRITABLE || $expiration || $password)
{
$share = stylite_sharing::create('', $path, $filemode, $attachment['name'], $recipients, $expiration, $password);
$share = stylite_sharing::create($path, $filemode, $attachment['name'], $recipients, $expiration, $password);
}
else
{