diff --git a/apps/files/lib/Command/TransferOwnership.php b/apps/files/lib/Command/TransferOwnership.php
index cad1b1b46cbe9..cad007ffa7343 100644
--- a/apps/files/lib/Command/TransferOwnership.php
+++ b/apps/files/lib/Command/TransferOwnership.php
@@ -77,7 +77,12 @@ protected function configure() {
InputOption::VALUE_REQUIRED,
'selectively provide the path to transfer. For example --path="folder_name"',
''
- );
+ )->addOption(
+ 'move',
+ null,
+ InputOption::VALUE_NONE,
+ 'move data from source user to root directory of destination user, which must be empty'
+ );
}
protected function execute(InputInterface $input, OutputInterface $output) {
@@ -99,7 +104,8 @@ protected function execute(InputInterface $input, OutputInterface $output) {
$sourceUserObject,
$destinationUserObject,
ltrim($input->getOption('path'), '/'),
- $output
+ $output,
+ $input->hasArgument('move')
);
} catch (TransferOwnershipException $e) {
$output->writeln("" . $e->getMessage() . "");
diff --git a/apps/files/lib/Service/OwnershipTransferService.php b/apps/files/lib/Service/OwnershipTransferService.php
index 8530edd17b17f..b130910e25b31 100644
--- a/apps/files/lib/Service/OwnershipTransferService.php
+++ b/apps/files/lib/Service/OwnershipTransferService.php
@@ -71,24 +71,32 @@ public function __construct(IEncryptionManager $manager,
* @param IUser $destinationUser
* @param string $path
*
+ * @param OutputInterface|null $output
+ * @param bool $move
* @throws TransferOwnershipException
+ * @throws \OC\User\NoUserException
*/
public function transfer(IUser $sourceUser,
IUser $destinationUser,
string $path,
- ?OutputInterface $output = null): void {
+ ?OutputInterface $output = null,
+ bool $move = false): void {
$output = $output ?? new NullOutput();
$sourceUid = $sourceUser->getUID();
$destinationUid = $destinationUser->getUID();
$sourcePath = rtrim($sourceUid . '/files/' . $path, '/');
// target user has to be ready
- if (!$this->encryptionManager->isReadyForUser($destinationUid)) {
+ if ($destinationUser->getLastLogin() === 0 || !$this->encryptionManager->isReadyForUser($destinationUid)) {
throw new TransferOwnershipException("The target user is not ready to accept files. The user has at least to have logged in once.", 2);
}
- $date = date('Y-m-d H-i-s');
- $finalTarget = "$destinationUid/files/transferred from $sourceUid on $date";
+ if ($move) {
+ $finalTarget = "$destinationUid/files/";
+ } else {
+ $date = date('Y-m-d H-i-s');
+ $finalTarget = "$destinationUid/files/transferred from $sourceUid on $date";
+ }
// setup filesystem
Filesystem::initMountPoints($sourceUid);
@@ -99,6 +107,11 @@ public function transfer(IUser $sourceUser,
throw new TransferOwnershipException("Unknown path provided: $path", 1);
}
+ if ($move && (!$view->is_dir($finalTarget) || count($view->getDirectoryContent($finalTarget)) > 0)) {
+ throw new TransferOwnershipException("Destination path does not exists or is not empty", 1);
+ }
+
+
// analyse source folder
$this->analyse(
$sourceUid,
@@ -273,7 +286,7 @@ private function restoreShares(string $sourceUid,
}
} catch (\OCP\Files\NotFoundException $e) {
$output->writeln('Share with id ' . $share->getId() . ' points at deleted file, skipping');
- } catch (\Exception $e) {
+ } catch (\Throwable $e) {
$output->writeln('Could not restore share with id ' . $share->getId() . ':' . $e->getTraceAsString() . '');
}
$progress->advance();
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 4c94cf26a4d29..36c491d5f4ba9 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -301,7 +301,7 @@ protected function generalCreateChecks(\OCP\Share\IShare $share) {
$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
$permissions = 0;
$mount = $share->getNode()->getMountPoint();
- if (!$isFederatedShare && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
+ if ($mount->getMountType() !== 'group' && !$isFederatedShare && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
// When it's a reshare use the parent share permissions as maximum
$userMountPointId = $mount->getStorageRootId();
$userMountPoints = $userFolder->getById($userMountPointId);
diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php
index 02f779abf51ed..02851d192119d 100644
--- a/tests/lib/Share20/ManagerTest.php
+++ b/tests/lib/Share20/ManagerTest.php
@@ -21,7 +21,6 @@
namespace Test\Share20;
-use OC\Files\Mount\MoveableMount;
use OC\HintException;
use OC\Share20\DefaultShareProvider;
use OC\Share20\Exception;
@@ -53,11 +52,13 @@
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
+use OC\Files\Mount\MountPoint;
use OCP\Share\IShareProvider;
use PHPUnit\Framework\MockObject\MockBuilder;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
+use Test\TestMoveableMountPoint;
/**
* Class ManagerTest
@@ -624,8 +625,8 @@ public function dataGeneralChecks() {
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, null, null, null), 'A share requires permissions', true];
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_LINK, $limitedPermssions, null, $user0, $user0, null, null, null), 'A share requires permissions', true];
- $mount = $this->createMock(MoveableMount::class);
- $limitedPermssions->method('getMountPoint')->willReturn($mount);
+ $movableMount = $this->createMock(TestMoveableMountPoint::class);
+ $limitedPermssions->method('getMountPoint')->willReturn($movableMount);
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $limitedPermssions, $user2, $user0, $user0, 31, null, null), 'Can’t increase permissions of path', true];
@@ -640,6 +641,8 @@ public function dataGeneralChecks() {
->willReturn($owner);
$nonMoveableMountPermssions->method('getStorage')
->willReturn($storage);
+ $nonMoveableMountPoint = $this->createMock(MountPoint::class);
+ $nonMoveableMountPermssions->method('getMountPoint')->willReturn($nonMoveableMountPoint);
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $nonMoveableMountPermssions, $user2, $user0, $user0, 11, null, null), 'Can’t increase permissions of path', false];
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $nonMoveableMountPermssions, $group0, $user0, $user0, 11, null, null), 'Can’t increase permissions of path', false];
@@ -660,6 +663,7 @@ public function dataGeneralChecks() {
->willReturn($owner);
$allPermssions->method('getStorage')
->willReturn($storage);
+ $allPermssions->method('getMountPoint')->willReturn($movableMount);
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_USER, $allPermssions, $user2, $user0, $user0, 30, null, null), 'Shares need at least read permissions', true];
$data[] = [$this->createShare(null, \OCP\Share::SHARE_TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 2, null, null), 'Shares need at least read permissions', true];