Skip to content

Commit

Permalink
feat: Add transfer job
Browse files Browse the repository at this point in the history
Signed-off-by: Christopher Ng <chrng8@gmail.com>
  • Loading branch information
Pytal committed Jun 21, 2024
1 parent bd8713e commit 9d8420f
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 29 deletions.
4 changes: 4 additions & 0 deletions img/account-arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
132 changes: 132 additions & 0 deletions lib/BackgroundJob/TransferJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Guests\BackgroundJob;

use OCA\Guests\AppInfo\Application;
use OCA\Guests\Db\Transfer;
use OCA\Guests\Db\TransferMapper;
use OCA\Guests\GuestManager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\BackgroundJob\QueuedJob;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Notification\IManager as NotificationManager;
use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface;

class TransferJob extends QueuedJob {
public function __construct(
private IUserManager $userManager,
private ISecureRandom $secureRandom,
private NotificationManager $notificationManager,
private IURLGenerator $urlGenerator,
private GuestManager $guestManager,
private TransferMapper $transferMapper,
private LoggerInterface $logger,
)
{
}

private function notifyFailure(Transfer $transfer): void {
$notification = $this->notificationManager->createNotification();
$notification
->setApp(Application::APP_ID)
->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath(Application::APP_ID, 'account-arrow-right.svg')))
->setUser($transfer->getAuthor())
->setDateTime($this->time->getDateTime())
->setObject('guest-transfer', (string)$transfer->getId())
->setSubject('guest-transfer-fail', [
'source' => $transfer->getSource(),
'target' => $transfer->getTarget(),
]);
$this->notificationManager->notify($notification);
}

private function notifySuccess(Transfer $transfer): void {
$notification = $this->notificationManager->createNotification();
$notification
->setApp(Application::APP_ID)
->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath(Application::APP_ID, 'account-arrow-right.svg')))
->setUser($transfer->getAuthor())
->setDateTime($this->time->getDateTime())
->setObject('guest-transfer', (string)$transfer->getId())
->setSubject('guest-transfer-done', [
'source' => $transfer->getSource(),
'target' => $transfer->getTarget(),
]);
$this->notificationManager->notify($notification);
}

public function run($argument): void {
/** @var int $id */
$id = $argument['id'];

try {
$transfer = $this->transferMapper->getById($id);
} catch (DoesNotExistException $e) {
$this->notifyFailure($transfer);
return;
}
$transfer->setStatus(Transfer::STATUS_STARTED);
$this->transferMapper->update($transfer);

$source = $transfer->getSource();
$target = $transfer->getTarget();

$sourceUser = $this->userManager->get($source);
if (!($sourceUser instanceof IUser)) {
$this->logger->error('Failed to transfer missing guest user: ' . $source);
$this->notifyFailure($transfer);
$this->transferMapper->delete($transfer);
return;
}

if ($this->userManager->userExists($target)) {
$this->logger->error("Cannot transfer guest user \"$source\", target user \"$target\" already exists");
$this->notifyFailure($transfer);
$this->transferMapper->delete($transfer);
return;
}

$targetUser = $this->userManager->createUser(
$target,
$this->secureRandom->generate(20), // Password hash will be copied to target user from source user
);

if (!($targetUser instanceof IUser)) {
$this->logger->error('Failed to create new user: ' . $target);
$this->notifyFailure($transfer);
$this->transferMapper->delete($transfer);
return;
}

$targetUser->setSystemEMailAddress($sourceUser->getUID()); // Guest user id is an email

// TODO copy password hash to target user

try {
$this->guestManager->transfer($sourceUser, $targetUser);
$result = $sourceUser->delete();
if (!$result) {
$this->logger->error('Failed to delete user', ['userId' => $sourceUser->getUID()]);
}
$this->notifySuccess($transfer);
} catch (\Throwable $th) {
$this->logger->error($th->getMessage(), ['exception' => $th]);
$result = $targetUser->delete(); // Rollback created user
if (!$result) {
$this->logger->error('Failed to delete user', ['userId' => $targetUser->getUID()]);
}
$this->notifyFailure($transfer);
}
$this->transferMapper->delete($transfer);
}
}
77 changes: 48 additions & 29 deletions lib/Notifications/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,26 @@
declare(strict_types=1);

/**
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Guests\Notifications;

use InvalidArgumentException;
use OCA\Guests\AppInfo\Application;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\L10N\IFactory;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;

class Notifier implements INotifier {

/** @var IFactory */
private $factory;

/** @var IURLGenerator */
private $url;

public function __construct(IFactory $factory,
IURLGenerator $url) {
$this->factory = $factory;
$this->url = $url;
public function __construct(
private IFactory $factory,
private IURLGenerator $url,
private IUserManager $userManager,
) {
}

public function getID(): string {
Expand All @@ -54,6 +33,26 @@ public function getName(): string {
return $this->factory->get(Application::APP_ID)->t('Guests');
}

private function getRichMessageParams(string $source, string $target): array {
$sourceUser = $this->userManager->get($source);
$targetUser = $this->userManager->get($target);
return [
'guest' => [
'type' => $sourceUser ? 'guest' : 'highlight',
'id' => $sourceUser?->getUID() ?? $source,
'name' => $sourceUser?->getDisplayName() ?? $source,
],
'user' => [
'type' => $targetUser ? 'user' : 'highlight',
'id' => $targetUser?->getUID() ?? $source,
'name' => $targetUser?->getDisplayName() ?? $target,
],
];
}

/**
* @throws InvalidArgumentException
*/
public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== Application::APP_ID) {
// Not my app => throw
Expand All @@ -74,6 +73,26 @@ public function prepare(INotification $notification, string $languageCode): INot

return $notification;

case 'guest-transfer-fail':
$params = $notification->getSubjectParameters();
$notification
->setRichSubject($l->t('Guest transfer failed'))
->setRichMessage(
$l->t('Transfer of guest {guest} to {user} failed'),
$this->getRichMessageParams($params['source'], $params['target']),
);
return $notification;

case 'guest-transfer-done':
$params = $notification->getSubjectParameters();
$notification
->setRichSubject($l->t('Guest transfer done'))
->setRichMessage(
$l->t('Transfer of guest {guest} to {user} completed'),
$this->getRichMessageParams($params['source'], $params['target']),
);
return $notification;

default:
// Unknown subject => Unknown notification => throw
throw new InvalidArgumentException();
Expand Down

0 comments on commit 9d8420f

Please sign in to comment.