mirror of
https://github.com/nextcloud/server.git
synced 2026-02-19 02:38:40 -05:00
refactor(dav): Modernize Node
Signed-off-by: provokateurin <kate@provokateurin.de>
This commit is contained in:
parent
bf71461bee
commit
e40d6b1c6b
13 changed files with 182 additions and 163 deletions
|
|
@ -166,11 +166,6 @@ class FilesPlugin extends ServerPlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
// Ensure source exists
|
||||
$sourceNodeFileInfo = $sourceNode->getFileInfo();
|
||||
if ($sourceNodeFileInfo === null) {
|
||||
throw new NotFound($source . ' does not exist');
|
||||
}
|
||||
// Ensure the target name is valid
|
||||
try {
|
||||
[$targetPath, $targetName] = \Sabre\Uri\split($target);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
|
|
@ -20,42 +22,48 @@ use OCP\Files\IRootFolder;
|
|||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\Storage\ISharedStorage;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
use OCP\IUser;
|
||||
use OCP\Lock\ILockingProvider;
|
||||
use OCP\Lock\LockedException;
|
||||
use OCP\PreConditionNotMetException;
|
||||
use OCP\Server;
|
||||
use OCP\Share\Exceptions\ShareNotFound;
|
||||
use OCP\Share\IManager;
|
||||
use RuntimeException;
|
||||
use Sabre\DAV\Exception;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\INode;
|
||||
|
||||
abstract class Node implements \Sabre\DAV\INode {
|
||||
abstract class Node implements INode {
|
||||
/**
|
||||
* The path to the current node
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
protected string $path;
|
||||
|
||||
protected FileInfo $info;
|
||||
|
||||
/**
|
||||
* @var IManager
|
||||
*/
|
||||
protected $shareManager;
|
||||
protected IManager $shareManager;
|
||||
|
||||
protected \OCP\Files\Node $node;
|
||||
|
||||
/**
|
||||
* Sets up the node, expects a full path name
|
||||
* @throws PreConditionNotMetException
|
||||
*/
|
||||
public function __construct(
|
||||
protected View $fileView,
|
||||
FileInfo $info,
|
||||
?IManager $shareManager = null,
|
||||
) {
|
||||
$this->path = $this->fileView->getRelativePath($info->getPath());
|
||||
$this->info = $info;
|
||||
if ($shareManager) {
|
||||
$this->shareManager = $shareManager;
|
||||
} else {
|
||||
$this->shareManager = Server::get(\OCP\Share\IManager::class);
|
||||
$relativePath = $this->fileView->getRelativePath($info->getPath());
|
||||
if ($relativePath === null) {
|
||||
throw new RuntimeException('Failed to get relative path for ' . $info->getPath());
|
||||
}
|
||||
|
||||
$this->path = $relativePath;
|
||||
$this->info = $info;
|
||||
$this->shareManager = $shareManager instanceof IManager ? $shareManager : Server::get(IManager::class);
|
||||
|
||||
if ($info instanceof Folder || $info instanceof File) {
|
||||
$this->node = $info;
|
||||
} else {
|
||||
|
|
@ -70,11 +78,16 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws PreConditionNotMetException
|
||||
*/
|
||||
protected function refreshInfo(): void {
|
||||
$info = $this->fileView->getFileInfo($this->path);
|
||||
if ($info === false) {
|
||||
throw new \Sabre\DAV\Exception('Failed to get fileinfo for ' . $this->path);
|
||||
throw new Exception('Failed to get fileinfo for ' . $this->path);
|
||||
}
|
||||
|
||||
$this->info = $info;
|
||||
$root = Server::get(IRootFolder::class);
|
||||
$rootView = Server::get(View::class);
|
||||
|
|
@ -87,19 +100,15 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
|
||||
/**
|
||||
* Returns the name of the node
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
public function getName(): string {
|
||||
return $this->info->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath() {
|
||||
public function getPath(): string {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
|
|
@ -107,25 +116,30 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
* Renames the node
|
||||
*
|
||||
* @param string $name The new name
|
||||
* @throws \Sabre\DAV\Exception\BadRequest
|
||||
* @throws \Sabre\DAV\Exception\Forbidden
|
||||
* @throws Exception
|
||||
* @throws Forbidden
|
||||
* @throws InvalidPath
|
||||
* @throws PreConditionNotMetException
|
||||
* @throws LockedException
|
||||
*/
|
||||
public function setName($name) {
|
||||
public function setName($name): void {
|
||||
// rename is only allowed if the delete privilege is granted
|
||||
// (basically rename is a copy with delete of the original node)
|
||||
if (!($this->info->isDeletable() || ($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === ''))) {
|
||||
throw new \Sabre\DAV\Exception\Forbidden();
|
||||
if (!$this->info->isDeletable() && !($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === '')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
/** @var string $parentPath */
|
||||
[$parentPath,] = \Sabre\Uri\split($this->path);
|
||||
/** @var string $newName */
|
||||
[, $newName] = \Sabre\Uri\split($name);
|
||||
$newPath = $parentPath . '/' . $newName;
|
||||
|
||||
// verify path of the target
|
||||
$this->verifyPath($newPath);
|
||||
|
||||
if (!$this->fileView->rename($this->path, $newPath)) {
|
||||
throw new \Sabre\DAV\Exception('Failed to rename ' . $this->path . ' to ' . $newPath);
|
||||
if ($this->fileView->rename($this->path, $newPath) === false) {
|
||||
throw new Exception('Failed to rename ' . $this->path . ' to ' . $newPath);
|
||||
}
|
||||
|
||||
$this->path = $newPath;
|
||||
|
|
@ -138,12 +152,8 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
*
|
||||
* @return int timestamp as integer
|
||||
*/
|
||||
public function getLastModified() {
|
||||
$timestamp = $this->info->getMtime();
|
||||
if (!empty($timestamp)) {
|
||||
return (int)$timestamp;
|
||||
}
|
||||
return $timestamp;
|
||||
public function getLastModified(): int {
|
||||
return $this->info->getMtime();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,7 +161,7 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
* in the second parameter or to now if the second param is empty.
|
||||
* Even if the modification time is set to a custom value the access time is set to now.
|
||||
*/
|
||||
public function touch($mtime) {
|
||||
public function touch(string $mtime): void {
|
||||
$mtime = $this->sanitizeMtime($mtime);
|
||||
$this->fileView->touch($this->path, $mtime);
|
||||
$this->refreshInfo();
|
||||
|
|
@ -165,37 +175,29 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
* arbitrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getETag() {
|
||||
public function getETag(): string {
|
||||
return '"' . $this->info->getEtag() . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ETag
|
||||
*
|
||||
* @param string $etag
|
||||
*
|
||||
* @return int file id of updated file or -1 on failure
|
||||
*/
|
||||
public function setETag($etag) {
|
||||
public function setETag(string $etag): int {
|
||||
return $this->fileView->putFileInfo($this->path, ['etag' => $etag]);
|
||||
}
|
||||
|
||||
public function setCreationTime(int $time) {
|
||||
public function setCreationTime(int $time): int {
|
||||
return $this->fileView->putFileInfo($this->path, ['creation_time' => $time]);
|
||||
}
|
||||
|
||||
public function setUploadTime(int $time) {
|
||||
return $this->fileView->putFileInfo($this->path, ['upload_time' => $time]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the node, in bytes
|
||||
*
|
||||
* @psalm-suppress UnusedPsalmSuppress psalm:strict actually thinks there is no mismatch, idk lol
|
||||
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
|
||||
* @return int|float
|
||||
*/
|
||||
public function getSize(): int|float {
|
||||
return $this->info->getSize();
|
||||
|
|
@ -203,28 +205,21 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
|
||||
/**
|
||||
* Returns the cache's file id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId() {
|
||||
public function getId(): ?int {
|
||||
return $this->info->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFileId() {
|
||||
if ($id = $this->info->getId()) {
|
||||
public function getFileId(): ?string {
|
||||
$id = $this->info->getId();
|
||||
if ($id !== null) {
|
||||
return DavUtil::getDavFileId($id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getInternalFileId() {
|
||||
public function getInternalFileId(): ?int {
|
||||
return $this->info->getId();
|
||||
}
|
||||
|
||||
|
|
@ -232,30 +227,24 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
return $this->info->getInternalPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @return int
|
||||
*/
|
||||
public function getSharePermissions($user) {
|
||||
public function getSharePermissions(?string $user): int {
|
||||
// check of we access a federated share
|
||||
if ($user !== null) {
|
||||
try {
|
||||
$share = $this->shareManager->getShareByToken($user);
|
||||
return $share->getPermissions();
|
||||
} catch (ShareNotFound $e) {
|
||||
return $this->shareManager->getShareByToken($user)->getPermissions();
|
||||
} catch (ShareNotFound) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$storage = $this->info->getStorage();
|
||||
} catch (StorageNotAvailableException $e) {
|
||||
} catch (StorageNotAvailableException) {
|
||||
$storage = null;
|
||||
}
|
||||
|
||||
if ($storage && $storage->instanceOfStorage(ISharedStorage::class)) {
|
||||
/** @var ISharedStorage $storage */
|
||||
$permissions = (int)$storage->getShare()->getPermissions();
|
||||
$permissions = $storage->getShare()->getPermissions();
|
||||
} else {
|
||||
$permissions = $this->info->getPermissions();
|
||||
}
|
||||
|
|
@ -266,6 +255,10 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
*/
|
||||
$mountpoint = $this->info->getMountPoint();
|
||||
if (!($mountpoint instanceof MoveableMount)) {
|
||||
/**
|
||||
* @psalm-suppress UnnecessaryVarAnnotation Rector doesn't trust the return type annotation
|
||||
* @var string $mountpointpath
|
||||
*/
|
||||
$mountpointpath = $mountpoint->getMountPoint();
|
||||
if (str_ends_with($mountpointpath, '/')) {
|
||||
$mountpointpath = substr($mountpointpath, 0, -1);
|
||||
|
|
@ -286,25 +279,21 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getShareAttributes(): array {
|
||||
try {
|
||||
$storage = $this->node->getStorage();
|
||||
} catch (NotFoundException $e) {
|
||||
} catch (NotFoundException) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
if ($storage->instanceOfStorage(ISharedStorage::class)) {
|
||||
/** @var ISharedStorage $storage */
|
||||
$attributes = $storage->getShare()->getAttributes();
|
||||
if ($attributes === null) {
|
||||
return [];
|
||||
} else {
|
||||
return $attributes->toArray();
|
||||
}
|
||||
|
||||
return $attributes->toArray();
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
|
|
@ -318,63 +307,66 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
}
|
||||
|
||||
if ($storage->instanceOfStorage(ISharedStorage::class)) {
|
||||
/** @var ISharedStorage $storage */
|
||||
$share = $storage->getShare();
|
||||
if ($user === $share->getShareOwner()) {
|
||||
// Note is only for recipient not the owner
|
||||
return null;
|
||||
}
|
||||
|
||||
return $share->getNote();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDavPermissions() {
|
||||
public function getDavPermissions(): string {
|
||||
return DavUtil::getDavPermissions($this->info);
|
||||
}
|
||||
|
||||
public function getOwner() {
|
||||
public function getOwner(): ?IUser {
|
||||
return $this->info->getOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPath
|
||||
*/
|
||||
protected function verifyPath(?string $path = null): void {
|
||||
try {
|
||||
$path = $path ?? $this->info->getPath();
|
||||
$path ??= $this->info->getPath();
|
||||
$this->fileView->verifyPath(
|
||||
dirname($path),
|
||||
basename($path),
|
||||
);
|
||||
} catch (InvalidPathException $ex) {
|
||||
throw new InvalidPath($ex->getMessage());
|
||||
} catch (InvalidPathException $invalidPathException) {
|
||||
throw new InvalidPath($invalidPathException->getMessage(), false, $invalidPathException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
|
||||
* @param ILockingProvider::LOCK_* $type
|
||||
* @throws LockedException
|
||||
*/
|
||||
public function acquireLock($type) {
|
||||
public function acquireLock($type): void {
|
||||
$this->fileView->lockFile($this->path, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
|
||||
* @param ILockingProvider::LOCK_* $type
|
||||
* @throws LockedException
|
||||
*/
|
||||
public function releaseLock($type) {
|
||||
public function releaseLock($type): void {
|
||||
$this->fileView->unlockFile($this->path, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
|
||||
* @param ILockingProvider::LOCK_* $type
|
||||
* @throws LockedException
|
||||
*/
|
||||
public function changeLock($type) {
|
||||
public function changeLock($type): void {
|
||||
$this->fileView->changeLock($this->path, $type);
|
||||
}
|
||||
|
||||
public function getFileInfo() {
|
||||
public function getFileInfo(): FileInfo {
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ class FilesHome extends Directory {
|
|||
throw new Forbidden('Permission denied to delete home folder');
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
public function getName(): string {
|
||||
[,$name] = \Sabre\Uri\split($this->principalInfo['uri']);
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
public function setName($name): void {
|
||||
throw new Forbidden('Permission denied to rename this folder');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,14 +61,14 @@ class CommentsPropertiesPluginTest extends \Test\TestCase {
|
|||
|
||||
public static function baseUriProvider(): array {
|
||||
return [
|
||||
['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/remote.php/files/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/wicked.php/files/', '4567', null]
|
||||
['owncloud/remote.php/webdav/', 4567, 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/remote.php/files/', 4567, 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/wicked.php/files/', 4567, null]
|
||||
];
|
||||
}
|
||||
|
||||
#[\PHPUnit\Framework\Attributes\DataProvider(methodName: 'baseUriProvider')]
|
||||
public function testGetCommentsLink(string $baseUri, string $fid, ?string $expectedHref): void {
|
||||
public function testGetCommentsLink(string $baseUri, int $fid, ?string $expectedHref): void {
|
||||
$node = $this->createMock(File::class);
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
|
|
@ -94,7 +94,7 @@ class CommentsPropertiesPluginTest extends \Test\TestCase {
|
|||
$node = $this->createMock(File::class);
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn('4567');
|
||||
->willReturn(4567);
|
||||
|
||||
if ($user !== null) {
|
||||
$user = $this->createMock($user);
|
||||
|
|
|
|||
|
|
@ -230,6 +230,10 @@ class DirectoryTest extends \Test\TestCase {
|
|||
$info->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(false);
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $info);
|
||||
$dir->getChildren();
|
||||
|
|
@ -242,6 +246,10 @@ class DirectoryTest extends \Test\TestCase {
|
|||
$this->info->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(false);
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/folder')
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $this->info);
|
||||
$dir->getChild('test');
|
||||
|
|
@ -254,6 +262,10 @@ class DirectoryTest extends \Test\TestCase {
|
|||
$this->view->expects($this->once())
|
||||
->method('getFileInfo')
|
||||
->willThrowException(new StorageNotAvailableException());
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/folder')
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $this->info);
|
||||
$dir->getChild('.');
|
||||
|
|
@ -268,6 +280,10 @@ class DirectoryTest extends \Test\TestCase {
|
|||
->willThrowException(new InvalidPathException());
|
||||
$this->view->expects($this->never())
|
||||
->method('getFileInfo');
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/folder')
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $this->info);
|
||||
$dir->getChild('.');
|
||||
|
|
@ -376,6 +392,11 @@ class DirectoryTest extends \Test\TestCase {
|
|||
}
|
||||
|
||||
public function testGetNodeForPathFailsWithNoReadPermissionsForPath(): void {
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/')
|
||||
->willReturn('');
|
||||
|
||||
$directoryNode = $this->createMock(Folder::class);
|
||||
$pathNode = $this->createMock(Folder::class);
|
||||
$storage = $this->createMock(IStorage::class);
|
||||
|
|
@ -396,7 +417,7 @@ class DirectoryTest extends \Test\TestCase {
|
|||
2 => false,
|
||||
};
|
||||
});
|
||||
$directoryNode->expects($this->once())
|
||||
$directoryNode
|
||||
->method('getPath')
|
||||
->willReturn('/admin/files/');
|
||||
$directoryNode->expects($this->once())
|
||||
|
|
|
|||
|
|
@ -673,6 +673,10 @@ class FileTest extends TestCase {
|
|||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
$view->expects($this->once())
|
||||
->method('unlink')
|
||||
|
|
@ -697,6 +701,10 @@ class FileTest extends TestCase {
|
|||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
|
||||
'permissions' => 0,
|
||||
|
|
@ -717,6 +725,10 @@ class FileTest extends TestCase {
|
|||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
// but fails
|
||||
$view->expects($this->once())
|
||||
|
|
@ -742,6 +754,10 @@ class FileTest extends TestCase {
|
|||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
// but fails
|
||||
$view->expects($this->once())
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class FilesPluginTest extends TestCase {
|
|||
->willReturn('00000123instanceid');
|
||||
$node->expects($this->any())
|
||||
->method('getInternalFileId')
|
||||
->willReturn('123');
|
||||
->willReturn(123);
|
||||
$node->expects($this->any())
|
||||
->method('getEtag')
|
||||
->willReturn('"abc"');
|
||||
|
|
@ -455,7 +455,7 @@ class FilesPluginTest extends TestCase {
|
|||
$node->expects($this->once())
|
||||
->method('setEtag')
|
||||
->with('newetag')
|
||||
->willReturn(true);
|
||||
->willReturn(123);
|
||||
|
||||
$node->expects($this->once())
|
||||
->method('setCreationTime')
|
||||
|
|
@ -562,35 +562,11 @@ class FilesPluginTest extends TestCase {
|
|||
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
|
||||
}
|
||||
|
||||
public function testMoveSrcNotExist(): void {
|
||||
$this->expectException(\Sabre\DAV\Exception\NotFound::class);
|
||||
$this->expectExceptionMessage('FolderA/test.txt does not exist');
|
||||
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn(null);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
->willReturn($node);
|
||||
|
||||
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
|
||||
}
|
||||
|
||||
public function testMoveDestinationInvalid(): void {
|
||||
$this->expectException(InvalidPath::class);
|
||||
$this->expectExceptionMessage('Mocked exception');
|
||||
|
||||
$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
|
||||
$fileInfoFolderATestTXT->expects(self::any())
|
||||
->method('isDeletable')
|
||||
->willReturn(true);
|
||||
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn($fileInfoFolderATestTXT);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
|
|
@ -604,31 +580,11 @@ class FilesPluginTest extends TestCase {
|
|||
$this->plugin->checkMove('FolderA/test.txt', 'invalid\\path.txt');
|
||||
}
|
||||
|
||||
public function testCopySrcNotExist(): void {
|
||||
$this->expectException(\Sabre\DAV\Exception\NotFound::class);
|
||||
$this->expectExceptionMessage('FolderA/test.txt does not exist');
|
||||
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn(null);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
->willReturn($node);
|
||||
|
||||
$this->plugin->checkCopy('FolderA/test.txt', 'test.txt');
|
||||
}
|
||||
|
||||
public function testCopyDestinationInvalid(): void {
|
||||
$this->expectException(InvalidPath::class);
|
||||
$this->expectExceptionMessage('Mocked exception');
|
||||
|
||||
$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn($fileInfoFolderATestTXT);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ class FilesReportPluginTest extends \Test\TestCase {
|
|||
|
||||
$this->tree = $this->createMock(Tree::class);
|
||||
$this->view = $this->createMock(View::class);
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$this->server = $this->getMockBuilder(Server::class)
|
||||
->setConstructorArgs([$this->tree])
|
||||
|
|
@ -315,14 +319,14 @@ class FilesReportPluginTest extends \Test\TestCase {
|
|||
|
||||
$node1->expects($this->once())
|
||||
->method('getInternalFileId')
|
||||
->willReturn('111');
|
||||
->willReturn(111);
|
||||
$node1->expects($this->any())
|
||||
->method('getPath')
|
||||
->willReturn('/node1');
|
||||
$node1->method('getFileInfo')->willReturn($fileInfo);
|
||||
$node2->expects($this->once())
|
||||
->method('getInternalFileId')
|
||||
->willReturn('222');
|
||||
->willReturn(222);
|
||||
$node2->expects($this->once())
|
||||
->method('getSize')
|
||||
->willReturn(1024);
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ class NodeTest extends \Test\TestCase {
|
|||
$info->method('getStorage')
|
||||
->willReturn($storage);
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->assertEquals($expected, $node->getDavPermissions());
|
||||
|
|
@ -169,6 +173,10 @@ class NodeTest extends \Test\TestCase {
|
|||
$info->method('getPermissions')->willReturn($permissions);
|
||||
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->invokePrivate($node, 'shareManager', [$shareManager]);
|
||||
|
|
@ -204,6 +212,10 @@ class NodeTest extends \Test\TestCase {
|
|||
|
||||
/** @var View&MockObject $view */
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->invokePrivate($node, 'shareManager', [$shareManager]);
|
||||
|
|
@ -225,6 +237,10 @@ class NodeTest extends \Test\TestCase {
|
|||
|
||||
/** @var View&MockObject */
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->invokePrivate($node, 'shareManager', [$shareManager]);
|
||||
|
|
@ -243,6 +259,10 @@ class NodeTest extends \Test\TestCase {
|
|||
$view = $this->getMockBuilder(View::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
$info = $this->getMockBuilder(FileInfo::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
|
@ -263,6 +283,11 @@ class NodeTest extends \Test\TestCase {
|
|||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$info = $this->createMock(FileInfo::class);
|
||||
|
||||
$node = new File($view, $info);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ class ObjectTreeTest extends \Test\TestCase {
|
|||
->method('getFileInfo')
|
||||
->with($targetParent === '' ? '.' : $targetParent)
|
||||
->willReturn($info);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$rootDir = new Directory($view, $info);
|
||||
$objectTree = $this->getMockBuilder(ObjectTree::class)
|
||||
|
|
@ -104,6 +108,10 @@ class ObjectTreeTest extends \Test\TestCase {
|
|||
->method('getFileInfo')
|
||||
->with($targetParent === '' ? '.' : $targetParent)
|
||||
->willReturn($info);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$rootDir = new Directory($view, $info);
|
||||
$objectTree = $this->getMockBuilder(ObjectTree::class)
|
||||
|
|
@ -141,6 +149,10 @@ class ObjectTreeTest extends \Test\TestCase {
|
|||
$view->method('getFileInfo')
|
||||
->with($fileInfoQueryPath)
|
||||
->willReturn($fileInfo);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$tree = new ObjectTree();
|
||||
$tree->init($rootNode, $view, $mountManager);
|
||||
|
|
|
|||
|
|
@ -616,20 +616,11 @@
|
|||
<code><![CDATA[lockFile]]></code>
|
||||
<code><![CDATA[putFileInfo]]></code>
|
||||
<code><![CDATA[putFileInfo]]></code>
|
||||
<code><![CDATA[putFileInfo]]></code>
|
||||
<code><![CDATA[rename]]></code>
|
||||
<code><![CDATA[touch]]></code>
|
||||
<code><![CDATA[unlockFile]]></code>
|
||||
<code><![CDATA[verifyPath]]></code>
|
||||
</InternalMethod>
|
||||
<InvalidNullableReturnType>
|
||||
<code><![CDATA[int]]></code>
|
||||
<code><![CDATA[integer]]></code>
|
||||
</InvalidNullableReturnType>
|
||||
<NullableReturnStatement>
|
||||
<code><![CDATA[$this->info->getId()]]></code>
|
||||
<code><![CDATA[$this->info->getId()]]></code>
|
||||
</NullableReturnStatement>
|
||||
</file>
|
||||
<file src="apps/dav/lib/Connector/Sabre/ObjectTree.php">
|
||||
<InternalMethod>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ return (require __DIR__ . '/rector-shared.php')
|
|||
$nextcloudDir . '/build/rector-strict.php',
|
||||
$nextcloudDir . '/core/BackgroundJobs/ExpirePreviewsJob.php',
|
||||
$nextcloudDir . '/lib/public/IContainer.php',
|
||||
$nextcloudDir . '/apps/dav/lib/Connector/Sabre/Node.php',
|
||||
])
|
||||
->withPreparedSets(
|
||||
deadCode: true,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<projectFiles>
|
||||
<file name="core/BackgroundJobs/ExpirePreviewsJob.php"/>
|
||||
<file name="lib/public/IContainer.php"/>
|
||||
<file name="apps/dav/lib/Connector/Sabre/Node.php"/>
|
||||
<ignoreFiles>
|
||||
<directory name="apps/**/composer"/>
|
||||
<directory name="apps/**/tests"/>
|
||||
|
|
@ -27,8 +28,13 @@
|
|||
</ignoreFiles>
|
||||
</projectFiles>
|
||||
<extraFiles>
|
||||
<directory name="apps/dav/lib"/>
|
||||
<directory name="3rdparty"/>
|
||||
</extraFiles>
|
||||
<stubs>
|
||||
<!-- Psalm does not find methods in here through <extraFiles/> 🤷♀️ -->
|
||||
<file name="3rdparty/sabre/uri/lib/functions.php"/>
|
||||
</stubs>
|
||||
<issueHandlers>
|
||||
<InternalClass>
|
||||
<errorLevel type="suppress">
|
||||
|
|
|
|||
Loading…
Reference in a new issue