Merge pull request #225 from nextcloud/stable9-upstream-sync

[Stable9] upstream sync
This commit is contained in:
Lukas Reschke 2016-06-26 14:50:58 +02:00 committed by GitHub
commit 49a916fb46
22 changed files with 190 additions and 56 deletions

View File

@ -76,16 +76,26 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
*/
private $fileView;
/**
* @var IRequest
*/
private $request;
/**
* @param \Sabre\DAV\Tree $tree
* @param \OC\Files\View $view
* @param \OCP\IRequest $request
* @param bool $isPublic
*/
public function __construct(\Sabre\DAV\Tree $tree,
\OC\Files\View $view,
$isPublic = false) {
public function __construct(
\Sabre\DAV\Tree $tree,
\OC\Files\View $view,
\OCP\IRequest $request,
$isPublic = false
) {
$this->tree = $tree;
$this->fileView = $view;
$this->request = $request;
$this->isPublic = $isPublic;
}
@ -193,7 +203,18 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
if (!($node instanceof IFile)) return;
// adds a 'Content-Disposition: attachment' header
$response->addHeader('Content-Disposition', 'attachment');
$filename = $node->getName();
if ($this->request->isUserAgent(
[
\OC\AppFramework\Http\Request::USER_AGENT_IE,
\OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
\OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
])) {
$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
} else {
$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
. '; filename="' . rawurlencode($filename) . '"');
}
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
//Add OC-Checksum header

View File

@ -137,7 +137,11 @@ class ServerFactory {
}
$objectTree->init($root, $view, $this->mountManager);
$server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin($objectTree, $view));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin(
$objectTree,
$view,
$this->request
));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\QuotaPlugin($view));
if($this->userSession->isLoggedIn()) {

View File

@ -125,7 +125,11 @@ class Server {
$user = \OC::$server->getUserSession()->getUser();
if (!is_null($user)) {
$view = \OC\Files\Filesystem::getView();
$this->server->addPlugin(new FilesPlugin($this->server->tree, $view));
$this->server->addPlugin(new FilesPlugin(
$this->server->tree,
$view,
$this->request
));
$this->server->addPlugin(
new \Sabre\DAV\PropertyStorage\Plugin(

View File

@ -72,8 +72,13 @@ class FilesPlugin extends \Test\TestCase {
$this->view = $this->getMockBuilder('\OC\Files\View')
->disableOriginalConstructor()
->getMock();
$request = $this->getMock('\OCP\IRequest');
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view);
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin(
$this->tree,
$this->view,
$request
);
$this->plugin->initialize($this->server);
}
@ -237,7 +242,11 @@ class FilesPlugin extends \Test\TestCase {
}
public function testGetPublicPermissions() {
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view, true);
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin(
$this->tree,
$this->view,
$this->getMock('\OCP\IRequest'),
true);
$this->plugin->initialize($this->server);
$propFind = new \Sabre\DAV\PropFind(

View File

@ -336,7 +336,11 @@ class FilesReportPlugin extends \Test\TestCase {
->method('getSize')
->will($this->returnValue(1024));
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin($this->tree, $this->view));
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesPlugin(
$this->tree,
$this->view,
$this->getMock('\OCP\IRequest')
));
$this->plugin->initialize($this->server);
$responses = $this->plugin->prepareResponses($requestedProps, [$node1, $node2]);

View File

@ -131,6 +131,7 @@ class GlobalStoragesController extends StoragesController {
* @param array $applicableUsers users for which to mount the storage
* @param array $applicableGroups groups for which to mount the storage
* @param int $priority priority
* @param bool $testOnly whether to storage should only test the connection or do more things
*
* @return DataResponse
*/
@ -143,7 +144,8 @@ class GlobalStoragesController extends StoragesController {
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
$priority,
$testOnly = true
) {
$storage = $this->createStorage(
$mountPoint,
@ -176,7 +178,7 @@ class GlobalStoragesController extends StoragesController {
);
}
$this->updateStorageStatus($storage);
$this->updateStorageStatus($storage, $testOnly);
return new DataResponse(
$storage,

View File

@ -240,8 +240,9 @@ abstract class StoragesController extends Controller {
* on whether the remote storage is available or not.
*
* @param StorageConfig $storage storage configuration
* @param bool $testOnly whether to storage should only test the connection or do more things
*/
protected function updateStorageStatus(StorageConfig &$storage) {
protected function updateStorageStatus(StorageConfig &$storage, $testOnly = true) {
try {
$this->manipulateStorageConfig($storage);
@ -252,7 +253,8 @@ abstract class StoragesController extends Controller {
\OC_Mount_Config::getBackendStatus(
$backend->getStorageClass(),
$storage->getBackendOptions(),
false
false,
$testOnly
)
);
} catch (InsufficientDataForMeaningfulAnswerException $e) {
@ -293,14 +295,15 @@ abstract class StoragesController extends Controller {
* Get an external storage entry.
*
* @param int $id storage id
* @param bool $testOnly whether to storage should only test the connection or do more things
*
* @return DataResponse
*/
public function show($id) {
public function show($id, $testOnly = true) {
try {
$storage = $this->service->getStorage($id);
$this->updateStorageStatus($storage);
$this->updateStorageStatus($storage, $testOnly);
} catch (NotFoundException $e) {
return new DataResponse(
[

View File

@ -106,15 +106,16 @@ class UserGlobalStoragesController extends StoragesController {
* Get an external storage entry.
*
* @param int $id storage id
* @param bool $testOnly whether to storage should only test the connection or do more things
* @return DataResponse
*
* @NoAdminRequired
*/
public function show($id) {
public function show($id, $testOnly = true) {
try {
$storage = $this->service->getStorage($id);
$this->updateStorageStatus($storage);
$this->updateStorageStatus($storage, $testOnly);
} catch (NotFoundException $e) {
return new DataResponse(
[
@ -138,6 +139,7 @@ class UserGlobalStoragesController extends StoragesController {
*
* @param int $id storage id
* @param array $backendOptions backend-specific options
* @param bool $testOnly whether to storage should only test the connection or do more things
*
* @return DataResponse
*
@ -145,7 +147,8 @@ class UserGlobalStoragesController extends StoragesController {
*/
public function update(
$id,
$backendOptions
$backendOptions,
$testOnly = true
) {
try {
$storage = $this->service->getStorage($id);
@ -170,7 +173,7 @@ class UserGlobalStoragesController extends StoragesController {
);
}
$this->updateStorageStatus($storage);
$this->updateStorageStatus($storage, $testOnly);
$this->sanitizeStorage($storage);
return new DataResponse(

View File

@ -104,8 +104,8 @@ class UserStoragesController extends StoragesController {
*
* {@inheritdoc}
*/
public function show($id) {
return parent::show($id);
public function show($id, $testOnly = true) {
return parent::show($id, $testOnly);
}
/**
@ -162,6 +162,7 @@ class UserStoragesController extends StoragesController {
* @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
* @param bool $testOnly whether to storage should only test the connection or do more things
*
* @return DataResponse
*
@ -173,7 +174,8 @@ class UserStoragesController extends StoragesController {
$backend,
$authMechanism,
$backendOptions,
$mountOptions
$mountOptions,
$testOnly = true
) {
$storage = $this->createStorage(
$mountPoint,
@ -203,7 +205,7 @@ class UserStoragesController extends StoragesController {
);
}
$this->updateStorageStatus($storage);
$this->updateStorageStatus($storage, $testOnly);
return new DataResponse(
$storage,

View File

@ -305,7 +305,8 @@ StorageConfig.prototype = {
mountPoint: this.mountPoint,
backend: this.backend,
authMechanism: this.authMechanism,
backendOptions: this.backendOptions
backendOptions: this.backendOptions,
testOnly: true
};
if (this.id) {
data.id = this.id;
@ -332,6 +333,7 @@ StorageConfig.prototype = {
$.ajax({
type: 'GET',
url: OC.generateUrl(this._url + '/{id}', {id: this.id}),
data: {'testOnly': true},
success: options.success,
error: options.error
});
@ -911,6 +913,7 @@ MountConfigListView.prototype = _.extend({
$.ajax({
type: 'GET',
url: OC.generateUrl('apps/files_external/userglobalstorages'),
data: {'testOnly': true},
contentType: 'application/json',
success: function(result) {
var onCompletion = jQuery.Deferred();

View File

@ -78,6 +78,7 @@ OCA.External.StatusManager = {
defObj = $.ajax({
type: 'GET',
url: OC.webroot + '/index.php/apps/files_external/' + ((mountData.type === 'personal') ? 'userstorages' : 'userglobalstorages') + '/' + mountData.id,
data: {'testOnly': false},
success: function (response) {
if (response && response.status === 0) {
self.mountStatus[mountData.mount_point] = response;

View File

@ -215,7 +215,7 @@ class OC_Mount_Config {
* @return int see self::STATUS_*
* @throws Exception
*/
public static function getBackendStatus($class, $options, $isPersonal) {
public static function getBackendStatus($class, $options, $isPersonal, $testOnly = true) {
if (self::$skipTest) {
return StorageNotAvailableException::STATUS_SUCCESS;
}
@ -228,7 +228,7 @@ class OC_Mount_Config {
$storage = new $class($options);
try {
$result = $storage->test($isPersonal);
$result = $storage->test($isPersonal, $testOnly);
$storage->setAvailability($result);
if ($result) {
return StorageNotAvailableException::STATUS_SUCCESS;

View File

@ -223,7 +223,8 @@ describe('OCA.External.Settings tests', function() {
applicableGroups: [],
mountOptions: {
'previews': true
}
},
testOnly: true
});
// TODO: respond and check data-id

View File

@ -111,7 +111,8 @@ class Application extends App {
/** @var \OCP\IServerContainer $server */
$server = $c->query('ServerContainer');
return new MountProvider(
$server->getConfig()
$server->getConfig(),
$server->getLogger()
);
});

View File

@ -27,6 +27,7 @@ use OC\User\NoUserException;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUser;
class MountProvider implements IMountProvider {
@ -36,10 +37,17 @@ class MountProvider implements IMountProvider {
protected $config;
/**
* @param \OCP\IConfig $config
* @var ILogger
*/
public function __construct(IConfig $config) {
protected $logger;
/**
* @param \OCP\IConfig $config
* @param ILogger $logger
*/
public function __construct(IConfig $config, ILogger $logger) {
$this->config = $config;
$this->logger = $logger;
}
@ -55,19 +63,25 @@ class MountProvider implements IMountProvider {
$shares = array_filter($shares, function ($share) {
return $share['permissions'] > 0;
});
$shares = array_map(function ($share) use ($user, $storageFactory) {
$mounts = [];
foreach ($shares as $share) {
try {
$mounts[] = new SharedMount(
'\OC\Files\Storage\Shared',
$mounts,
[
'share' => $share,
'user' => $user->getUID()
],
$storageFactory
);
} catch (\Exception $e) {
$this->logger->logException($e);
$this->logger->error('Error while trying to create shared mount');
}
}
return new SharedMount(
'\OC\Files\Storage\Shared',
'/' . $user->getUID() . '/' . $share['file_target'],
array(
'share' => $share,
'user' => $user->getUID()
),
$storageFactory
);
}, $shares);
// array_filter removes the null values from the array
return array_filter($shares);
return array_filter($mounts);
}
}

View File

@ -25,6 +25,7 @@
namespace OCA\Files_Sharing;
use OC\Files\Filesystem;
use OC\Files\Mount\MountPoint;
use OC\Files\Mount\MoveableMount;
use OC\Files\View;
@ -50,14 +51,14 @@ class SharedMount extends MountPoint implements MoveableMount {
/**
* @param string $storage
* @param string $mountpoint
* @param SharedMount[] $mountpoints
* @param array|null $arguments
* @param \OCP\Files\Storage\IStorageFactory $loader
*/
public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
$this->user = $arguments['user'];
$this->recipientView = new View('/' . $this->user . '/files');
$newMountPoint = $this->verifyMountPoint($arguments['share']);
$newMountPoint = $this->verifyMountPoint($arguments['share'], $mountpoints);
$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
$arguments['ownerView'] = new View('/' . $arguments['share']['uid_owner'] . '/files');
parent::__construct($storage, $absMountPoint, $arguments, $loader);
@ -67,9 +68,10 @@ class SharedMount extends MountPoint implements MoveableMount {
* check if the parent folder exists otherwise move the mount point up
*
* @param array $share
* @param SharedMount[] $mountpoints
* @return string
*/
private function verifyMountPoint(&$share) {
private function verifyMountPoint(&$share, array $mountpoints) {
$mountPoint = basename($share['file_target']);
$parent = dirname($share['file_target']);
@ -78,10 +80,10 @@ class SharedMount extends MountPoint implements MoveableMount {
$parent = Helper::getShareFolder($this->recipientView);
}
$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
$newMountPoint = $this->generateUniqueTarget(
\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
[],
$this->recipientView
$this->recipientView,
$mountpoints
);
if ($newMountPoint !== $share['file_target']) {
@ -93,6 +95,37 @@ class SharedMount extends MountPoint implements MoveableMount {
return $newMountPoint;
}
/**
* @param string $path
* @param View $view
* @param SharedMount[] $mountpoints
* @return mixed
*/
private function generateUniqueTarget($path, $view, array $mountpoints) {
$pathinfo = pathinfo($path);
$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
$name = $pathinfo['filename'];
$dir = $pathinfo['dirname'];
// Helper function to find existing mount points
$mountpointExists = function($path) use ($mountpoints) {
foreach ($mountpoints as $mountpoint) {
if ($mountpoint->getShare()['file_target'] === $path) {
return true;
}
}
return false;
};
$i = 2;
while ($view->file_exists($path) || $mountpointExists($path)) {
$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
$i++;
}
return $path;
}
/**
* update fileTarget in the database if the mount point changed
*

View File

@ -337,9 +337,16 @@ class Storage {
// Restore encrypted version of the old file for the newly restored file
// This has to happen manually here since the file is manually copied below
$oldVersion = $users_view->getFileInfo($fileToRestore)->getEncryptedVersion();
$oldFileInfo = $users_view->getFileInfo($fileToRestore);
$newFileInfo = $files_view->getFileInfo($filename);
$cache = $newFileInfo->getStorage()->getCache();
$cache->update($newFileInfo->getId(), ['encrypted' => $oldVersion, 'encryptedVersion' => $oldVersion]);
$cache->update(
$newFileInfo->getId(), [
'encrypted' => $oldVersion,
'encryptedVersion' => $oldVersion,
'size' => $oldFileInfo->getSize()
]
);
// rollback
if (self::copyFileContents($users_view, $fileToRestore, 'files' . $filename)) {

View File

@ -730,7 +730,14 @@ class Access extends LDAPUtility implements user\IUserTools {
$user->unmark();
$user = $this->userManager->get($ocName);
}
$user->processAttributes($userRecord);
if ($user !== null) {
$user->processAttributes($userRecord);
} else {
\OC::$server->getLogger()->debug(
"The ldap user manager returned null for $ocName",
['app'=>'user_ldap']
);
}
}
}

View File

@ -566,3 +566,16 @@ Feature: sharing
| path | welcome.txt |
| shareType | 3 |
Then share ids should match
Scenario: unique target names for incomming shares
Given user "user0" exists
And user "user1" exists
And user "user2" exists
And user "user0" created a folder "/foo"
And user "user1" created a folder "/foo"
When file "/foo" of user "user0" is shared with user "user2"
And file "/foo" of user "user1" is shared with user "user2"
Then user "user2" should see following elements
| /foo/ |
| /foo%20(2)/ |

View File

@ -73,7 +73,7 @@ Feature: webdav-related
And As an "admin"
When Downloading file "/welcome.txt"
Then The following headers should be set
|Content-Disposition|attachment|
|Content-Disposition|attachment; filename*=UTF-8''welcome.txt; filename="welcome.txt"|
|Content-Security-Policy|default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *|
|X-Content-Type-Options |nosniff|
|X-Download-Options|noopen|
@ -88,7 +88,7 @@ Feature: webdav-related
And As an "admin"
When Downloading file "/welcome.txt"
Then The following headers should be set
|Content-Disposition|attachment|
|Content-Disposition|attachment; filename*=UTF-8''welcome.txt; filename="welcome.txt"|
|Content-Security-Policy|default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *|
|X-Content-Type-Options |nosniff|
|X-Download-Options|noopen|

View File

@ -76,7 +76,8 @@
$.ajax({
type: 'PROPFIND',
url: url,
complete: afterCall
complete: afterCall,
allowAuthErrors: true
});
return deferred.promise();
},
@ -209,7 +210,8 @@
$.ajax({
type: 'GET',
url: OC.linkTo('', oc_dataURL+'/htaccesstest.txt?t=' + (new Date()).getTime()),
complete: afterCall
complete: afterCall,
allowAuthErrors: true
});
return deferred.promise();
},

View File

@ -256,7 +256,7 @@ class AppManager implements IAppManager {
}
unset($this->installedAppsCache[$appId]);
$this->appConfig->setValue($appId, 'enabled', 'no');
$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent(
$this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent(
ManagerEvent::EVENT_APP_DISABLE, $appId
));
$this->clearAppsCache();