Api: Sharing listens to Vfs hooks to stay up-to-date with deleted or renamed files

This commit is contained in:
nathangray 2020-03-06 14:48:26 -07:00
parent 66f197d0b0
commit 173b695cf2
4 changed files with 189 additions and 19 deletions

View File

@ -54,24 +54,29 @@ $setup_info['api']['tables'][] = 'egw_ea_valid';
$setup_info['api']['tables'][] = 'egw_ea_notifications'; $setup_info['api']['tables'][] = 'egw_ea_notifications';
// hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS // hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS
$setup_info['api']['hooks']['addaccount'] = array('EGroupware\\Api\\Vfs\\Hooks::addAccount', 'EGroupware\\Api\\Mail\\Hooks::addaccount'); $setup_info['api']['hooks']['addaccount'] = array('EGroupware\\Api\\Vfs\\Hooks::addAccount', 'EGroupware\\Api\\Mail\\Hooks::addaccount');
$setup_info['api']['hooks']['deleteaccount'] = array('EGroupware\\Api\\Vfs\\Hooks::deleteAccount', 'EGroupware\\Api\\Mail\\Hooks::deleteaccount'); $setup_info['api']['hooks']['deleteaccount'] = array('EGroupware\\Api\\Vfs\\Hooks::deleteAccount', 'EGroupware\\Api\\Mail\\Hooks::deleteaccount');
$setup_info['api']['hooks']['editaccount'] = array('EGroupware\\Api\\Vfs\\Hooks::editAccount', 'EGroupware\\Api\\Mail\\Hooks::addaccount'); $setup_info['api']['hooks']['editaccount'] = array('EGroupware\\Api\\Vfs\\Hooks::editAccount', 'EGroupware\\Api\\Mail\\Hooks::addaccount');
$setup_info['api']['hooks']['addgroup'] = 'EGroupware\\Api\\Vfs\\Hooks::addGroup'; $setup_info['api']['hooks']['addgroup'] = 'EGroupware\\Api\\Vfs\\Hooks::addGroup';
$setup_info['api']['hooks']['deletegroup'] = array('EGroupware\\Api\\Vfs\\Hooks::deleteGroup', 'EGroupware\\Api\\Mail\\Hooks::deletegroup'); $setup_info['api']['hooks']['deletegroup'] = array('EGroupware\\Api\\Vfs\\Hooks::deleteGroup', 'EGroupware\\Api\\Mail\\Hooks::deletegroup');
$setup_info['api']['hooks']['editgroup'] = 'EGroupware\\Api\\Vfs\\Hooks::editGroup'; $setup_info['api']['hooks']['editgroup'] = 'EGroupware\\Api\\Vfs\\Hooks::editGroup';
$setup_info['api']['hooks']['changepassword'] = 'EGroupware\\Api\\Mail\\Hooks::changepassword'; $setup_info['api']['hooks']['changepassword'] = 'EGroupware\\Api\\Mail\\Hooks::changepassword';
$setup_info['api']['hooks']['sidebox_all'] = 'EGroupware\\Api\\Framework\\Tutorial::tutorial_menu'; $setup_info['api']['hooks']['sidebox_all'] = 'EGroupware\\Api\\Framework\\Tutorial::tutorial_menu';
// Hooks to delete shares when file is deleted
$setup_info['api']['hooks']['vfs_unlink'] = 'EGroupware\\Api\\Vfs\\Sharing::vfsUpdate';
$setup_info['api']['hooks']['vfs_rename'] = 'EGroupware\\Api\\Vfs\\Sharing::vfsUpdate';
$setup_info['api']['hooks']['vfs_rmdir'] = 'EGroupware\\Api\\Vfs\\Sharing::vfsUpdate';
// installation checks // installation checks
$setup_info['api']['check_install'] = array( $setup_info['api']['check_install'] = array(
'' => array( '' => array(
'func' => 'pear_check', 'func' => 'pear_check',
'from' => 'Api/Mail', 'from' => 'Api/Mail',
), ),
'pear.horde.org/Horde_Imap_Client' => array( 'pear.horde.org/Horde_Imap_Client' => array(
'func' => 'pear_check', 'func' => 'pear_check',
'from' => 'Api/Mail', 'from' => 'Api/Mail',
'version' => '2.24.2', 'version' => '2.24.2',
), ),
'pear.horde.org/Horde_Nls' => array( 'pear.horde.org/Horde_Nls' => array(

View File

@ -15,8 +15,6 @@ namespace EGroupware\Api\Vfs;
use EGroupware\Api; use EGroupware\Api;
use EGroupware\Api\Vfs; use EGroupware\Api\Vfs;
use EGroupware\Collabora\Wopi;
use filemanager_ui; use filemanager_ui;
/** /**
@ -398,6 +396,52 @@ class Sharing extends \EGroupware\Api\Sharing
return $actions; return $actions;
} }
/**
* Hook callback to watch VFS and remove any shares for files that get moved or removed
*/
public static function vfsUpdate($data)
{
$path = $data['location'] == 'vfs_rename' ? $data['from'] : $data['path'];
if (parse_url($path, PHP_URL_SCHEME) !== 'vfs')
{
$path = Api\Vfs::PREFIX . ($path[0] == '/' ? '' : '/') . $path;
}
if ($data['location'] == 'vfs_rmdir')
{
// Normally removing a directory removes the files first, so any shares inside the directory would
// be handled already, but just in case, get it all.
$path .= '%';
}
$shares = array();
foreach ($GLOBALS['egw']->db->select(self::TABLE, array(
'share_id', 'share_path', 'share_owner'
),
array(
"share_path LIKE '$path'"
),
__LINE__, __FILE__, false) as $share)
{
$shares[] = $share;
}
foreach ($shares as $share)
{
if ($data['location'] == 'vfs_rename')
{
if (parse_url($data['to'], PHP_URL_SCHEME) !== 'vfs')
{
$data['to'] = $path = Api\Vfs::PREFIX . ($data['to'][0] == '/' ? '' : '/') . $data['to'];
}
$GLOBALS['egw']->db->update(self::TABLE, array(
'share_path' => $data['to']
), $share, __LINE__, __FILE__);
}
else
{
static::delete($share['share_id']);
}
}
}
} }
if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php')) if (file_exists(__DIR__.'/../../../filemanager/inc/class.filemanager_ui.inc.php'))

View File

@ -17,8 +17,8 @@ namespace EGroupware\Api\Vfs;
require_once __DIR__ . '/../LoggedInTest.php'; require_once __DIR__ . '/../LoggedInTest.php';
use EGroupware\Api; use EGroupware\Api;
use EGroupware\Api\Vfs;
use EGroupware\Api\LoggedInTest as LoggedInTest; use EGroupware\Api\LoggedInTest as LoggedInTest;
use EGroupware\Api\Vfs;
use EGroupware\Stylite\Vfs\Versioning; use EGroupware\Stylite\Vfs\Versioning;
@ -421,6 +421,19 @@ class SharingBase extends LoggedInTest
return $share; return $share;
} }
public function readShare($share_id)
{
foreach ($GLOBALS['egw']->db->select(Sharing::TABLE, '*',
array(
'share_id' => (int)$share_id
),
__LINE__, __FILE__, false) as $share)
{
return $share;
}
return array();
}
/** /**
* Make an infolog entry * Make an infolog entry
*/ */
@ -428,9 +441,9 @@ class SharingBase extends LoggedInTest
{ {
$bo = new \infolog_bo(); $bo = new \infolog_bo();
$element = array( $element = array(
'info_subject' => "Test infolog for #{$this->getName()}", 'info_subject' => "Test infolog for #{$this->getName()}",
'info_des' => 'Test element for ' . $this->getName() ."\n". Api\DateTime::to(), 'info_des' => 'Test element for ' . $this->getName() . "\n" . Api\DateTime::to(),
'info_status' => 'open' 'info_status' => 'open'
); );
$element_id = $bo->write($element, true, true, true, true); $element_id = $bo->write($element, true, true, true, true);

View File

@ -0,0 +1,108 @@
<?php
/**
* Tests for updating / deleting shares if underlying file is renamed or deleted
*
* We create files and delete them through the VFS, then check to see if the share is
* correctly deleted too.
*
* @link http://www.egroupware.org
* @author Nathan Gray
* @copyright (c) 2020 Nathan Gray
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
*/
namespace EGroupware\Api\Vfs;
require_once __DIR__ . '/SharingBase.php';
use EGroupware\Api\Vfs;
class SharingHooksTest extends SharingBase
{
/**
* Test that deleting a file deletes the share
*/
public function testDeleteFileDeletesShare()
{
$target = Vfs::get_home_dir();
$this->files = $this->addFiles($target);
$test_file = $this->files[0];
// Make sure there are no leftover shares
Sharing::delete(array('share_path' => $test_file));
// Create share
$this->shares[] = $created_share = Sharing::create($test_file, Sharing::READONLY, '', '');
$this->assertEquals(Vfs::PREFIX . $test_file, $created_share['share_path']);
// Now delete the file
Vfs::remove($test_file);
// Check for share for that file
$read_share = $this->readShare($created_share['share_id']);
$this->assertEquals(array(), $read_share, "Expected not to find the share, but something was found");
}
/**
* Test that deleting a directory deletes shares on any file in that directory
*/
public function testDeleteDirectoryDeletesShare()
{
$target = Vfs::get_home_dir();
$this->files = $this->addFiles($target);
$test_file = $target . '/sub_dir/subdir_test_file.txt';
// Make sure there are no leftover shares
Sharing::delete(array('share_path' => $test_file));
// Create share
$this->shares[] = $created_share = Sharing::create($test_file, Sharing::READONLY, '', '');
$this->assertEquals(Vfs::PREFIX . $test_file, $created_share['share_path']);
// Now delete the parent directory
Vfs::remove($target . '/sub_dir');
// Check for share for that file
$read_share = $this->readShare($created_share['share_id']);
$this->assertEquals(array(), $read_share, "Expected not to find the share, but something was found");
}
/**
* Test renaming a file updates the share
*/
public function testRenameFileUpdatesShare()
{
$target = Vfs::get_home_dir();
$this->files = $this->addFiles($target);
$test_file = $this->files[0];
// Make sure there are no leftover shares
Sharing::delete(array('share_path' => $test_file));
// Create share
$this->shares[] = $created_share = Sharing::create($test_file, Sharing::READONLY, '', '');
$this->assertEquals(Vfs::PREFIX . $test_file, $created_share['share_path']);
// Now rename the file
$this->files[] = $moved = $target . '/moved.txt';
Vfs::rename($test_file, $moved);
// Check for share for that file
$read_share = $this->readShare($created_share['share_id']);
$this->assertEquals(Vfs::PREFIX . $moved, $read_share['share_path'], "Expected find the share with a different path");
$this->assertNotEquals(Vfs::PREFIX . $moved, $created_share['share_path'], "Expected find the share with a different path");
}
}