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

@ -63,6 +63,11 @@ $setup_info['api']['hooks']['editgroup'] = 'EGroupware\\Api\\Vfs\\Hooks::ed
$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(

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
*/ */
@ -429,7 +442,7 @@ 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'
); );

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");
}
}