mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-02 20:19:27 +01:00
Cleanup, bugfix & refactoring of hidden upload folder.
This commit is contained in:
parent
b0b9df8e50
commit
895b1ebee9
@ -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);
|
||||
|
306
api/src/Vfs/HiddenUploadSharing.php
Normal file
306
api/src/Vfs/HiddenUploadSharing.php
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
list(,$path) = explode('::', $path);
|
||||
}
|
||||
|
||||
// Set flags so things work
|
||||
$extra['share_writable'] = self::HIDDEN_UPLOAD;
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this share have a hidden upload directory
|
||||
*/
|
||||
public function has_hidden_upload()
|
||||
// We don't allow sharing links, share target instead
|
||||
if(($target = Vfs::readlink($path)))
|
||||
{
|
||||
return (int)$this->share['share_writable'] == self::HIDDEN_UPLOAD;
|
||||
$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!");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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']);
|
||||
// we dont use ['nm']['rows']['delete'], so unset it, if it is present
|
||||
if (isset($content['nm']['rows']['delete'])) unset($content['nm']['rows']['delete']);
|
||||
}
|
||||
elseif($content['nm']['rows']['delete'])
|
||||
if (isset($content['nm']['action']))
|
||||
{
|
||||
$msg = static::action('delete',array_keys($content['nm']['rows']['delete']),$content['nm']['path']);
|
||||
if($msg) Framework::message($msg);
|
||||
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']);
|
||||
}
|
||||
}
|
||||
elseif ($content['nm']['rows']['delete'])
|
||||
{
|
||||
$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))
|
||||
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;
|
||||
}
|
||||
@ -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
|
||||
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']));
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user