diff --git a/lib/BackgroundJob/TransferJob.php b/lib/BackgroundJob/TransferJob.php index 17923014..c9d0e0d3 100644 --- a/lib/BackgroundJob/TransferJob.php +++ b/lib/BackgroundJob/TransferJob.php @@ -12,7 +12,7 @@ use OCA\Guests\AppInfo\Application; use OCA\Guests\Db\Transfer; use OCA\Guests\Db\TransferMapper; -use OCA\Guests\GuestManager; +use OCA\Guests\TransferService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\BackgroundJob\QueuedJob; use OCP\IURLGenerator; @@ -28,7 +28,7 @@ public function __construct( private ISecureRandom $secureRandom, private NotificationManager $notificationManager, private IURLGenerator $urlGenerator, - private GuestManager $guestManager, + private TransferService $transferService, private TransferMapper $transferMapper, private LoggerInterface $logger, ) @@ -113,7 +113,7 @@ public function run($argument): void { // TODO copy password hash to target user try { - $this->guestManager->transfer($sourceUser, $targetUser); + $this->transferService->transfer($sourceUser, $targetUser); $result = $sourceUser->delete(); if (!$result) { $this->logger->error('Failed to delete user', ['userId' => $sourceUser->getUID()]); diff --git a/lib/Controller/UsersController.php b/lib/Controller/UsersController.php index 08c2da2f..9cd22e59 100644 --- a/lib/Controller/UsersController.php +++ b/lib/Controller/UsersController.php @@ -1,14 +1,21 @@ userManager->get($email); - if (!($user instanceof IUser)) { - throw new OCSNotFoundException(); + private function getStatusMessage(string $status): string { + return match ($status) { + Transfer::STATUS_WAITING => $this->l10n->t('Waiting'), + Transfer::STATUS_STARTED => $this->l10n->t('Started'), + }; + } + + /** + * Transfer guest to a full account + * + * @param string $email Guest email + * @param string $userId User id for full account + */ + public function transfer(string $email, string $userId): DataResponse { + $author = $this->userSession->getUser(); + if (!($author instanceof IUser)) { + return new DataResponse([], Http::STATUS_UNAUTHORIZED); } - if (!$this->guestManager->isGuest($user)) { - return new DataResponse([], Http::STATUS_CONFLICT); + $sourceUser = $this->userManager->get($email); + if (!($sourceUser instanceof IUser)) { + return new DataResponse([], Http::STATUS_NOT_FOUND); } if ($this->userManager->userExists($userId)) { - throw new OCSException($this->l10n->t('User already exists'), 102); + return new DataResponse([ + 'message' => $this->l10n->t('User already exists') + ], Http::STATUS_CONFLICT); } - $newUser = $this->userManager->createUser( - $userId, - $password, - ); - - if (!($newUser instanceof IUser)) { - throw new OCSException($this->l10n->t('Failed to create new user')); + if (!$this->guestManager->isGuest($sourceUser)) { + return new DataResponse([], Http::STATUS_CONFLICT); } - $newUser->setSystemEMailAddress($email); - - try { - $this->guestManager->transfer($user, $newUser); - $result = $user->delete(); - if (!$result) { - $this->logger->error('Failed to delete user', [ 'userId' => $user->getUID() ]); - } - } catch (\Throwable $th) { - $this->logger->error('Failed to transfer guest', [ 'error' => $th ]); - $result = $newUser->delete(); // Rollback created user - if (!$result) { - $this->logger->error('Failed to delete user', [ 'userId' => $newUser->getUID() ]); - } - throw new OCSException($this->l10n->t('Failed to transfer guest')); + $transfer = $this->transferService->getTransfer($sourceUser, $userId); + if ($transfer instanceof Transfer) { + return new DataResponse([ + 'status' => $this->getStatusMessage($transfer->getStatus()), + 'message' => $this->l10n->t("Guest \"{$transfer->getSource()}\" is already pending a transfer to \"{$transfer->getTarget()}\""), + ], Http::STATUS_ACCEPTED); } + + $this->transferService->addTransferJob($author, $sourceUser, $userId); return new DataResponse([], Http::STATUS_CREATED); } } diff --git a/lib/GuestManager.php b/lib/GuestManager.php index 61494779..cc8c288f 100644 --- a/lib/GuestManager.php +++ b/lib/GuestManager.php @@ -21,10 +21,6 @@ namespace OCA\Guests; -use OCA\Files\Exception\TransferOwnershipException; -use OCA\Files\Service\OwnershipTransferService; -use OCA\Guests\AppInfo\Application; -use OCP\AppFramework\QueryException; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; @@ -32,14 +28,11 @@ use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; -use OCP\Notification\IManager as INotificationManager; use OCP\Security\Events\GenerateSecurePasswordEvent; use OCP\Security\ICrypto; use OCP\Security\ISecureRandom; use OCP\Share\IManager; use OCP\Share\IShare; -use Psr\Container\ContainerInterface; -use Psr\Log\LoggerInterface; class GuestManager { public function __construct( @@ -52,10 +45,8 @@ public function __construct( private IUserSession $userSession, private IEventDispatcher $eventDispatcher, private IUserManager $userManager, - private ContainerInterface $container, - private LoggerInterface $logger, - private INotificationManager $notificationManager, - ) {} + ) { + } /** * @param IUser|string $user @@ -182,48 +173,4 @@ public function getGuestInfo($userId): array { }, $shares), ]; } - - public function transfer(IUser $guestUser, IUser $user): void { - try { - /** @var OwnershipTransferService $ownershipTransferService */ - $ownershipTransferService = $this->container->get(OwnershipTransferService::class); - } catch (QueryException $e) { - $this->logger->error('Could not resolve ownership transfer service to import guest user data', [ - 'exception' => $e, - ]); - throw $e; - } - - try { - $ownershipTransferService->transfer( - $guestUser, - $user, - '/', - null, - true, - true - ); - } catch (TransferOwnershipException $e) { - $this->logger->error('Could not import guest user data', [ - 'exception' => $e, - ]); - throw $e; - } - - // Update incomming shares - $shares = $this->shareManager->getSharedWith($guestUser->getUID(), IShare::TYPE_USER); - foreach ($shares as $share) { - $share->setSharedWith($user->getUID()); - $this->shareManager->updateShare($share); - } - - $notification = $this->notificationManager->createNotification(); - $notification - ->setApp(Application::APP_ID) - ->setSubject('data_migrated_to_system_user') - ->setObject('user', $user->getEMailAddress()) - ->setDateTime(new \DateTime()) - ->setUser($user->getUID()); - $this->notificationManager->notify($notification); - } } diff --git a/lib/Hooks.php b/lib/Hooks.php index 01991cba..8e9026fe 100644 --- a/lib/Hooks.php +++ b/lib/Hooks.php @@ -49,6 +49,7 @@ public function __construct( private GuestManager $guestManager, private UserBackend $userBackend, private IAppContainer $container, + private TransferService $transferService, ) {} public function handlePostShare(ShareCreatedEvent $event): void { @@ -172,7 +173,7 @@ public function handleFirstLogin(UserFirstTimeLoggedInEvent $event): void { return; } - $this->guestManager->transfer($guestUser, $user); + $this->transferService->transfer($guestUser, $user); if (!$this->config->getSystemValueBool('remove_guest_account_on_conversion', false)) { // Disable previous account diff --git a/lib/TransferService.php b/lib/TransferService.php new file mode 100644 index 00000000..8d21858a --- /dev/null +++ b/lib/TransferService.php @@ -0,0 +1,114 @@ +container->get(OwnershipTransferService::class); + } catch (QueryException $e) { + $this->logger->error('Could not resolve ownership transfer service to import guest user data', [ + 'exception' => $e, + ]); + throw $e; + } + + try { + $ownershipTransferService->transfer( + $guestUser, + $user, + '/', + null, + true, + true + ); + } catch (TransferOwnershipException $e) { + $this->logger->error('Could not import guest user data', [ + 'exception' => $e, + ]); + throw $e; + } + + // Update incomming shares + $shares = $this->shareManager->getSharedWith($guestUser->getUID(), IShare::TYPE_USER); + foreach ($shares as $share) { + $share->setSharedWith($user->getUID()); + $this->shareManager->updateShare($share); + } + + $notification = $this->notificationManager->createNotification(); + $notification + ->setApp(Application::APP_ID) + ->setSubject('data_migrated_to_system_user') + ->setObject('user', $user->getEMailAddress()) + ->setDateTime(new \DateTime()) + ->setUser($user->getUID()); + $this->notificationManager->notify($notification); + } + + public function addTransferJob(IUser $author, IUser $source, string $target): void { + $transfer = new Transfer(); + $transfer->setAuthor($author->getUID()); + $transfer->setSource($source->getUID()); + $transfer->setTarget($target); + $transfer->setStatus(Transfer::STATUS_WAITING); + /** @var Transfer $transfer */ + $transfer = $this->transferMapper->insert($transfer); + + $this->jobList->add(TransferJob::class, [ + 'id' => $transfer->getId(), + ]); + } + + public function getTransfer(IUser $source, string $target): ?Transfer { + try { + $transfer = $this->transferMapper->getBySource($source->getUID()); + return $transfer; + } catch (DoesNotExistException $e) { + // Allow as this just means there is no pending transfer + } + + try { + $transfer = $this->transferMapper->getByTarget($target); + return $transfer; + } catch (DoesNotExistException $e) { + // Allow as this just means there is no pending transfer + } + + return null; + } +}