2019-12-03 13:57:53 -05:00
< ? php
declare ( strict_types = 1 );
2015-11-18 07:14:48 -05:00
/**
2024-05-28 10:42:42 -04:00
* SPDX - FileCopyrightText : 2016 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2015-11-18 07:14:48 -05:00
*/
2021-08-27 11:55:37 -04:00
2015-11-18 07:14:48 -05:00
namespace OCA\Files\Command ;
2019-11-20 05:41:31 -05:00
use OCA\Files\Exception\TransferOwnershipException ;
use OCA\Files\Service\OwnershipTransferService ;
2025-04-23 11:28:05 -04:00
use OCA\Files_External\Config\ConfigAdapter ;
use OCP\Files\Mount\IMountManager ;
use OCP\Files\Mount\IMountPoint ;
2021-08-27 11:55:37 -04:00
use OCP\IConfig ;
2016-10-17 05:42:54 -04:00
use OCP\IUser ;
2015-11-18 07:14:48 -05:00
use OCP\IUserManager ;
use Symfony\Component\Console\Command\Command ;
2025-04-23 11:28:05 -04:00
use Symfony\Component\Console\Helper\QuestionHelper ;
2015-11-18 07:14:48 -05:00
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputInterface ;
2019-11-22 14:52:10 -05:00
use Symfony\Component\Console\Input\InputOption ;
2015-11-18 07:14:48 -05:00
use Symfony\Component\Console\Output\OutputInterface ;
2025-04-23 11:28:05 -04:00
use Symfony\Component\Console\Question\ConfirmationQuestion ;
2015-11-18 07:14:48 -05:00
class TransferOwnership extends Command {
2023-07-04 14:43:32 -04:00
public function __construct (
private IUserManager $userManager ,
private OwnershipTransferService $transferService ,
private IConfig $config ,
2025-04-23 11:28:05 -04:00
private IMountManager $mountManager ,
2023-07-04 14:43:32 -04:00
) {
2015-11-18 07:14:48 -05:00
parent :: __construct ();
}
2023-07-04 14:43:32 -04:00
protected function configure () : void {
2015-11-18 07:14:48 -05:00
$this
-> setName ( 'files:transfer-ownership' )
2021-08-27 11:55:37 -04:00
-> setDescription ( 'All files and folders are moved to another user - outgoing shares and incoming user file shares (optionally) are moved as well.' )
2015-11-18 07:14:48 -05:00
-> addArgument (
'source-user' ,
InputArgument :: REQUIRED ,
'owner of files which shall be moved'
)
-> addArgument (
'destination-user' ,
InputArgument :: REQUIRED ,
'user who will be the new owner of the files'
2017-03-09 04:54:33 -05:00
)
-> addOption (
'path' ,
null ,
InputOption :: VALUE_REQUIRED ,
2017-03-22 19:39:08 -04:00
'selectively provide the path to transfer. For example --path="folder_name"' ,
''
2020-01-03 02:43:39 -05:00
) -> addOption (
'move' ,
null ,
InputOption :: VALUE_NONE ,
'move data from source user to root directory of destination user, which must be empty'
2021-08-27 11:55:37 -04:00
) -> addOption (
'transfer-incoming-shares' ,
null ,
InputOption :: VALUE_OPTIONAL ,
2025-06-03 10:16:19 -04:00
'Incoming shares are always transferred now, so this option does not affect the ownership transfer anymore' ,
2021-08-27 11:55:37 -04:00
'2'
2025-04-23 11:28:05 -04:00
) -> addOption (
'include-external-storage' ,
null ,
InputOption :: VALUE_NONE ,
'include files on external storages, this will _not_ setup an external storage for the target user, but instead moves all the files from the external storages into the target users home directory' ,
) -> addOption (
'force-include-external-storage' ,
null ,
InputOption :: VALUE_NONE ,
'don\'t ask for confirmation for transferring external storages' ,
2025-11-25 09:45:40 -05:00
)
-> addOption (
'use-user-id' ,
null ,
InputOption :: VALUE_NONE ,
'use user ID instead of display name in the transferred folder name' ,
2020-01-03 02:43:39 -05:00
);
2015-11-18 07:14:48 -05:00
}
2020-06-26 09:12:11 -04:00
protected function execute ( InputInterface $input , OutputInterface $output ) : int {
2020-10-09 01:20:03 -04:00
/**
* Check if source and destination users are same . If they are same then just ignore the transfer .
*/
if ( $input -> getArgument (( 'source-user' )) === $input -> getArgument ( 'destination-user' )) {
$output -> writeln ( " <error>Ownership can't be transferred when Source and Destination users are the same user. Please check your input.</error> " );
2023-07-04 14:43:32 -04:00
return self :: FAILURE ;
2020-10-09 01:20:03 -04:00
}
2016-10-04 06:28:41 -04:00
$sourceUserObject = $this -> userManager -> get ( $input -> getArgument ( 'source-user' ));
$destinationUserObject = $this -> userManager -> get ( $input -> getArgument ( 'destination-user' ));
2016-10-17 05:42:54 -04:00
2016-10-04 06:28:41 -04:00
if ( ! $sourceUserObject instanceof IUser ) {
2019-11-20 05:41:31 -05:00
$output -> writeln ( '<error>Unknown source user ' . $input -> getArgument ( 'source-user' ) . '</error>' );
2023-07-04 14:43:32 -04:00
return self :: FAILURE ;
2015-11-18 07:14:48 -05:00
}
2016-10-17 05:42:54 -04:00
2016-10-04 06:28:41 -04:00
if ( ! $destinationUserObject instanceof IUser ) {
2019-11-20 05:41:31 -05:00
$output -> writeln ( '<error>Unknown destination user ' . $input -> getArgument ( 'destination-user' ) . '</error>' );
2023-07-04 14:43:32 -04:00
return self :: FAILURE ;
2016-04-14 11:32:25 -04:00
}
2016-10-17 05:42:54 -04:00
2025-04-23 11:28:05 -04:00
$path = ltrim ( $input -> getOption ( 'path' ), '/' );
$includeExternalStorage = $input -> getOption ( 'include-external-storage' );
if ( $includeExternalStorage ) {
$mounts = $this -> mountManager -> findIn ( '/' . rtrim ( $sourceUserObject -> getUID () . '/files/' . $path , '/' ));
/** @var IMountPoint[] $mounts */
$mounts = array_filter ( $mounts , fn ( $mount ) => $mount -> getMountProvider () === ConfigAdapter :: class );
if ( count ( $mounts ) > 0 ) {
$output -> writeln ( count ( $mounts ) . ' external storages will be transferred:' );
foreach ( $mounts as $mount ) {
$output -> writeln ( ' - <info>' . $mount -> getMountPoint () . '</info>' );
}
$output -> writeln ( '' );
$output -> writeln ( '<comment>Any other users with access to these external storages will lose access to the files.</comment>' );
$output -> writeln ( '' );
if ( ! $input -> getOption ( 'force-include-external-storage' )) {
/** @var QuestionHelper $helper */
$helper = $this -> getHelper ( 'question' );
$question = new ConfirmationQuestion ( 'Are you sure you want to transfer external storages? (y/N) ' , false );
if ( ! $helper -> ask ( $input , $output , $question )) {
return self :: FAILURE ;
}
}
}
}
2019-11-20 05:41:31 -05:00
try {
$this -> transferService -> transfer (
$sourceUserObject ,
$destinationUserObject ,
2025-04-23 11:28:05 -04:00
$path ,
2020-01-03 02:43:39 -05:00
$output ,
2021-08-27 11:55:37 -04:00
$input -> getOption ( 'move' ) === true ,
false ,
2025-04-23 11:28:05 -04:00
$includeExternalStorage ,
2025-11-25 09:45:40 -05:00
$input -> getOption ( 'use-user-id' ) === true ,
2019-11-20 05:41:31 -05:00
);
} catch ( TransferOwnershipException $e ) {
$output -> writeln ( '<error>' . $e -> getMessage () . '</error>' );
2023-07-04 14:43:32 -04:00
return $e -> getCode () !== 0 ? $e -> getCode () : self :: FAILURE ;
2015-11-18 07:14:48 -05:00
}
2023-07-04 14:43:32 -04:00
return self :: SUCCESS ;
2015-11-18 07:14:48 -05:00
}
}