Fire prehooks when uploading directly to storage
This commit is contained in:
parent
dc362823e0
commit
3cae0135ad
|
@ -161,13 +161,37 @@ class File extends Node implements IFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$view = \OC\Files\Filesystem::getView();
|
||||||
|
$run = true;
|
||||||
|
if ($view) {
|
||||||
|
$hookPath = $view->getRelativePath($this->fileView->getAbsolutePath($this->path));
|
||||||
|
|
||||||
|
if (!$exists) {
|
||||||
|
\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
|
||||||
|
\OC\Files\Filesystem::signal_param_path => $hookPath,
|
||||||
|
\OC\Files\Filesystem::signal_param_run => &$run,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
|
||||||
|
\OC\Files\Filesystem::signal_param_path => $hookPath,
|
||||||
|
\OC\Files\Filesystem::signal_param_run => &$run,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
|
||||||
|
\OC\Files\Filesystem::signal_param_path => $hookPath,
|
||||||
|
\OC\Files\Filesystem::signal_param_run => &$run,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if ($needsPartFile) {
|
if ($needsPartFile) {
|
||||||
// rename to correct path
|
// rename to correct path
|
||||||
try {
|
try {
|
||||||
|
if ($run) {
|
||||||
$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
|
$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
|
||||||
$fileExists = $storage->file_exists($internalPath);
|
$fileExists = $storage->file_exists($internalPath);
|
||||||
if ($renameOkay === false || $fileExists === false) {
|
}
|
||||||
\OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR);
|
if (!$run || $renameOkay === false || $fileExists === false) {
|
||||||
|
\OC_Log::write('webdav', 'renaming part file to final file failed', \OC_Log::ERROR);
|
||||||
$partStorage->unlink($internalPartPath);
|
$partStorage->unlink($internalPartPath);
|
||||||
throw new Exception('Could not rename part file to final file');
|
throw new Exception('Could not rename part file to final file');
|
||||||
}
|
}
|
||||||
|
@ -180,9 +204,7 @@ class File extends Node implements IFile {
|
||||||
// since we skipped the view we need to scan and emit the hooks ourselves
|
// since we skipped the view we need to scan and emit the hooks ourselves
|
||||||
$partStorage->getScanner()->scanFile($internalPath);
|
$partStorage->getScanner()->scanFile($internalPath);
|
||||||
|
|
||||||
$view = \OC\Files\Filesystem::getView();
|
|
||||||
if ($view) {
|
if ($view) {
|
||||||
$hookPath = $view->getRelativePath($this->fileView->getAbsolutePath($this->path));
|
|
||||||
$this->fileView->getUpdater()->propagate($hookPath);
|
$this->fileView->getUpdater()->propagate($hookPath);
|
||||||
if (!$exists) {
|
if (!$exists) {
|
||||||
\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
|
\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
|
||||||
|
|
|
@ -8,8 +8,35 @@
|
||||||
|
|
||||||
namespace Test\Connector\Sabre;
|
namespace Test\Connector\Sabre;
|
||||||
|
|
||||||
|
use Test\HookHelper;
|
||||||
|
use OC\Files\Filesystem;
|
||||||
|
|
||||||
class File extends \Test\TestCase {
|
class File extends \Test\TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
\OC_Hook::clear();
|
||||||
|
|
||||||
|
$this->user = $this->getUniqueID('user_');
|
||||||
|
$userManager = \OC::$server->getUserManager();
|
||||||
|
$userManager->createUser($this->user, 'pass');
|
||||||
|
|
||||||
|
$this->loginAsUser($this->user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown() {
|
||||||
|
$userManager = \OC::$server->getUserManager();
|
||||||
|
$userManager->get($this->user)->delete();
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
private function getStream($string) {
|
private function getStream($string) {
|
||||||
$stream = fopen('php://temp', 'r+');
|
$stream = fopen('php://temp', 'r+');
|
||||||
fwrite($stream, $string);
|
fwrite($stream, $string);
|
||||||
|
@ -23,7 +50,7 @@ class File extends \Test\TestCase {
|
||||||
public function testSimplePutFails() {
|
public function testSimplePutFails() {
|
||||||
// setup
|
// setup
|
||||||
$storage = $this->getMock('\OC\Files\Storage\Local', ['fopen'], [['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]);
|
$storage = $this->getMock('\OC\Files\Storage\Local', ['fopen'], [['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]);
|
||||||
$view = $this->getMock('\OC\Files\View', array('file_put_contents', 'getRelativePath', 'resolvePath'), array());
|
$view = $this->getMock('\OC\Files\View', array('getRelativePath', 'resolvePath'), array());
|
||||||
$view->expects($this->any())
|
$view->expects($this->any())
|
||||||
->method('resolvePath')
|
->method('resolvePath')
|
||||||
->will($this->returnValue(array($storage, '')));
|
->will($this->returnValue(array($storage, '')));
|
||||||
|
@ -45,45 +72,166 @@ class File extends \Test\TestCase {
|
||||||
$file->put('test data');
|
$file->put('test data');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPutSingleFileShare() {
|
private function doPut($path, $viewRoot = null) {
|
||||||
// setup
|
$view = \OC\Files\Filesystem::getView();
|
||||||
$stream = fopen('php://temp', 'w+');
|
if (!is_null($viewRoot)) {
|
||||||
$storage = $this->getMock('\OC\Files\Storage\Local', ['fopen'], [['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]);
|
$view = new \OC\Files\View($viewRoot);
|
||||||
$view = $this->getMock('\OC\Files\View', array('file_put_contents', 'getRelativePath', 'resolvePath'), array());
|
} else {
|
||||||
$view->expects($this->any())
|
$viewRoot = '/' . $this->user . '/files';
|
||||||
->method('resolvePath')
|
}
|
||||||
->will($this->returnValue(array($storage, '')));
|
|
||||||
$view->expects($this->any())
|
|
||||||
->method('getRelativePath')
|
|
||||||
->will($this->returnValue(''));
|
|
||||||
$view->expects($this->any())
|
|
||||||
->method('file_put_contents')
|
|
||||||
->with('')
|
|
||||||
->will($this->returnValue(true));
|
|
||||||
$storage->expects($this->once())
|
|
||||||
->method('fopen')
|
|
||||||
->will($this->returnValue($stream));
|
|
||||||
|
|
||||||
$info = new \OC\Files\FileInfo('/foo.txt', null, null, array(
|
$info = new \OC\Files\FileInfo(
|
||||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
$viewRoot . '/' . ltrim($path, '/'),
|
||||||
), null);
|
null,
|
||||||
|
null,
|
||||||
|
['permissions' => \OCP\Constants::PERMISSION_ALL],
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||||
|
|
||||||
$this->assertNotEmpty($file->put($this->getStream('test data')));
|
$this->assertNotEmpty($file->put($this->getStream('test data')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test putting a single file
|
||||||
|
*/
|
||||||
|
public function testPutSingleFile() {
|
||||||
|
$this->doPut('/foo.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that putting a file triggers create hooks
|
||||||
|
*/
|
||||||
|
public function testPutSingleFileTriggersHooks() {
|
||||||
|
HookHelper::setUpHooks();
|
||||||
|
|
||||||
|
$this->doPut('/foo.txt');
|
||||||
|
|
||||||
|
$this->assertCount(4, HookHelper::$hookCalls);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[0],
|
||||||
|
Filesystem::signal_create,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[1],
|
||||||
|
Filesystem::signal_write,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[2],
|
||||||
|
Filesystem::signal_post_create,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[3],
|
||||||
|
Filesystem::signal_post_write,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that putting a file triggers update hooks
|
||||||
|
*/
|
||||||
|
public function testPutOverwriteFileTriggersHooks() {
|
||||||
|
$view = \OC\Files\Filesystem::getView();
|
||||||
|
$view->file_put_contents('/foo.txt', 'some content that will be replaced');
|
||||||
|
|
||||||
|
HookHelper::setUpHooks();
|
||||||
|
|
||||||
|
$this->doPut('/foo.txt');
|
||||||
|
|
||||||
|
$this->assertCount(4, HookHelper::$hookCalls);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[0],
|
||||||
|
Filesystem::signal_update,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[1],
|
||||||
|
Filesystem::signal_write,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[2],
|
||||||
|
Filesystem::signal_post_update,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[3],
|
||||||
|
Filesystem::signal_post_write,
|
||||||
|
'/foo.txt'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that putting a file triggers hooks with the correct path
|
||||||
|
* if the passed view was chrooted (can happen with public webdav
|
||||||
|
* where the root is the share root)
|
||||||
|
*/
|
||||||
|
public function testPutSingleFileTriggersHooksDifferentRoot() {
|
||||||
|
$view = \OC\Files\Filesystem::getView();
|
||||||
|
$view->mkdir('noderoot');
|
||||||
|
|
||||||
|
HookHelper::setUpHooks();
|
||||||
|
|
||||||
|
// happens with public webdav where the view root is the share root
|
||||||
|
$this->doPut('/foo.txt', '/' . $this->user . '/files/noderoot');
|
||||||
|
|
||||||
|
$this->assertCount(4, HookHelper::$hookCalls);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[0],
|
||||||
|
Filesystem::signal_create,
|
||||||
|
'/noderoot/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[1],
|
||||||
|
Filesystem::signal_write,
|
||||||
|
'/noderoot/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[2],
|
||||||
|
Filesystem::signal_post_create,
|
||||||
|
'/noderoot/foo.txt'
|
||||||
|
);
|
||||||
|
$this->assertHookCall(
|
||||||
|
HookHelper::$hookCalls[3],
|
||||||
|
Filesystem::signal_post_write,
|
||||||
|
'/noderoot/foo.txt'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cancellingHook($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_post_create,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test put file with cancelled hook
|
||||||
|
*
|
||||||
|
* @expectedException \Sabre\DAV\Exception
|
||||||
|
*/
|
||||||
|
public function testPutSingleFileCancelPreHook() {
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_create,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'cancellingCallback'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->doPut('/foo.txt');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Sabre\DAV\Exception
|
* @expectedException \Sabre\DAV\Exception
|
||||||
*/
|
*/
|
||||||
public function testSimplePutFailsOnRename() {
|
public function testSimplePutFailsOnRename() {
|
||||||
// setup
|
// setup
|
||||||
$view = $this->getMock('\OC\Files\View',
|
$view = $this->getMock('\OC\Files\View',
|
||||||
array('file_put_contents', 'rename', 'getRelativePath', 'filesize'));
|
array('rename', 'getRelativePath', 'filesize'));
|
||||||
$view->expects($this->any())
|
|
||||||
->method('file_put_contents')
|
|
||||||
->withAnyParameters()
|
|
||||||
->will($this->returnValue(true));
|
|
||||||
$view->expects($this->any())
|
$view->expects($this->any())
|
||||||
->method('rename')
|
->method('rename')
|
||||||
->withAnyParameters()
|
->withAnyParameters()
|
||||||
|
@ -113,11 +261,7 @@ class File extends \Test\TestCase {
|
||||||
*/
|
*/
|
||||||
public function testSimplePutInvalidChars() {
|
public function testSimplePutInvalidChars() {
|
||||||
// setup
|
// setup
|
||||||
$view = $this->getMock('\OC\Files\View', array('file_put_contents', 'getRelativePath'));
|
$view = $this->getMock('\OC\Files\View', array('getRelativePath'));
|
||||||
$view->expects($this->any())
|
|
||||||
->method('file_put_contents')
|
|
||||||
->will($this->returnValue(false));
|
|
||||||
|
|
||||||
$view->expects($this->any())
|
$view->expects($this->any())
|
||||||
->method('getRelativePath')
|
->method('getRelativePath')
|
||||||
->will($this->returnValue('/*'));
|
->will($this->returnValue('/*'));
|
||||||
|
@ -157,11 +301,7 @@ class File extends \Test\TestCase {
|
||||||
public function testUploadAbort() {
|
public function testUploadAbort() {
|
||||||
// setup
|
// setup
|
||||||
$view = $this->getMock('\OC\Files\View',
|
$view = $this->getMock('\OC\Files\View',
|
||||||
array('file_put_contents', 'rename', 'getRelativePath', 'filesize'));
|
array('rename', 'getRelativePath', 'filesize'));
|
||||||
$view->expects($this->any())
|
|
||||||
->method('file_put_contents')
|
|
||||||
->withAnyParameters()
|
|
||||||
->will($this->returnValue(true));
|
|
||||||
$view->expects($this->any())
|
$view->expects($this->any())
|
||||||
->method('rename')
|
->method('rename')
|
||||||
->withAnyParameters()
|
->withAnyParameters()
|
||||||
|
@ -248,4 +388,20 @@ class File extends \Test\TestCase {
|
||||||
// action
|
// action
|
||||||
$file->delete();
|
$file->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts hook call
|
||||||
|
*
|
||||||
|
* @param array $callData hook call data to check
|
||||||
|
* @param string $signal signal name
|
||||||
|
* @param string $hookPath hook path
|
||||||
|
*/
|
||||||
|
protected function assertHookCall($callData, $signal, $hookPath) {
|
||||||
|
$this->assertEquals($signal, $callData['signal']);
|
||||||
|
$params = $callData['params'];
|
||||||
|
$this->assertEquals(
|
||||||
|
$hookPath,
|
||||||
|
$params[Filesystem::signal_param_path]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
|
* later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Test;
|
||||||
|
|
||||||
|
use OC\Files\Filesystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to register hooks on
|
||||||
|
*/
|
||||||
|
class HookHelper {
|
||||||
|
public static $hookCalls;
|
||||||
|
|
||||||
|
public static function setUpHooks() {
|
||||||
|
self::clear();
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_create,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'createCallback'
|
||||||
|
);
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_update,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'updateCallback'
|
||||||
|
);
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_write,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'writeCallback'
|
||||||
|
);
|
||||||
|
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_post_create,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'postCreateCallback'
|
||||||
|
);
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_post_update,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'postUpdateCallback'
|
||||||
|
);
|
||||||
|
\OCP\Util::connectHook(
|
||||||
|
Filesystem::CLASSNAME,
|
||||||
|
Filesystem::signal_post_write,
|
||||||
|
'\Test\HookHelper',
|
||||||
|
'postWriteCallback'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function clear() {
|
||||||
|
self::$hookCalls = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createCallback($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_create,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateCallback($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_update,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function writeCallback($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_write,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function postCreateCallback($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_post_create,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function postUpdateCallback($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_post_update,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function postWriteCallback($params) {
|
||||||
|
self::$hookCalls[] = array(
|
||||||
|
'signal' => Filesystem::signal_post_write,
|
||||||
|
'params' => $params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback that sets the run paramter to false
|
||||||
|
*/
|
||||||
|
public static function cancellingCallback($params) {
|
||||||
|
$params[Filesystem::signal_param_run] = false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue