From 895b1ebee93a845fdc55b7a7ac34a601e7d422e6 Mon Sep 17 00:00:00 2001 From: nathangray Date: Wed, 25 Mar 2020 11:39:22 -0600 Subject: [PATCH] Cleanup, bugfix & refactoring of hidden upload folder. --- api/src/Sharing.php | 14 +- api/src/Vfs/HiddenUploadSharing.php | 306 +++++++++++++++++++ api/src/Vfs/Sharing.php | 187 +++--------- filemanager/inc/class.filemanager_ui.inc.php | 108 ++++--- filemanager/js/app.js | 6 + filemanager/js/app.ts | 8 + mail/inc/class.mail_compose.inc.php | 2 +- 7 files changed, 455 insertions(+), 176 deletions(-) create mode 100644 api/src/Vfs/HiddenUploadSharing.php diff --git a/api/src/Sharing.php b/api/src/Sharing.php index caa968e59c..659cf60043 100644 --- a/api/src/Sharing.php +++ b/api/src/Sharing.php @@ -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); diff --git a/api/src/Vfs/HiddenUploadSharing.php b/api/src/Vfs/HiddenUploadSharing.php new file mode 100644 index 0000000000..3c4af0e818 --- /dev/null +++ b/api/src/Vfs/HiddenUploadSharing.php @@ -0,0 +1,306 @@ + 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; + } + } +} \ No newline at end of file diff --git a/api/src/Vfs/Sharing.php b/api/src/Vfs/Sharing.php index 17d6fdf753..47f881bf1f 100644 --- a/api/src/Vfs/Sharing.php +++ b/api/src/Vfs/Sharing.php @@ -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; } } diff --git a/filemanager/inc/class.filemanager_ui.inc.php b/filemanager/inc/class.filemanager_ui.inc.php index 82518c6f9f..c7a3e36264 100644 --- a/filemanager/inc/class.filemanager_ui.inc.php +++ b/filemanager/inc/class.filemanager_ui.inc.php @@ -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'])); } diff --git a/filemanager/js/app.js b/filemanager/js/app.js index ef39adf63b..c1e468c104 100644 --- a/filemanager/js/app.js +++ b/filemanager/js/app.js @@ -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); }; /** diff --git a/filemanager/js/app.ts b/filemanager/js/app.ts index 95d4c2e89f..38ca96e172 100644 --- a/filemanager/js/app.ts +++ b/filemanager/js/app.ts @@ -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); } diff --git a/mail/inc/class.mail_compose.inc.php b/mail/inc/class.mail_compose.inc.php index 3fe9fb1a43..171f1a0836 100644 --- a/mail/inc/class.mail_compose.inc.php +++ b/mail/inc/class.mail_compose.inc.php @@ -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 {