Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions js/user_migration-personal-settings.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/user_migration-personal-settings.js.map

Large diffs are not rendered by default.

40 changes: 30 additions & 10 deletions lib/BackgroundJob/UserImportJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@
use OCA\UserMigration\Db\UserImport;
use OCA\UserMigration\Db\UserImportMapper;
use OCA\UserMigration\Service\UserMigrationService;
use OCA\UserMigration\UserFolderImportSource;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\QueuedJob;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Notification\IManager as NotificationManager;
Expand All @@ -43,14 +46,18 @@ class UserImportJob extends QueuedJob {
private LoggerInterface $logger;
private NotificationManager $notificationManager;
private UserImportMapper $mapper;
private IConfig $config;
private IRootFolder $root;

public function __construct(
ITimeFactory $timeFactory,
IUserManager $userManager,
UserMigrationService $migrationService,
LoggerInterface $logger,
NotificationManager $notificationManager,
UserImportMapper $mapper
UserImportMapper $mapper,
IConfig $config,
IRootFolder $root
) {
parent::__construct($timeFactory);

Expand All @@ -59,19 +66,27 @@ public function __construct(
$this->logger = $logger;
$this->notificationManager = $notificationManager;
$this->mapper = $mapper;
$this->config = $config;
$this->root = $root;
}

public function run($argument): void {
$id = $argument['id'];

$import = $this->mapper->getById($id);
$user = $import->getSourceUser();
$author = $import->getAuthor();
$targetUser = $import->getTargetUser();
$path = $import->getPath();

$userObject = $this->userManager->get($user);
$authorObject = $this->userManager->get($author);
$targetUserObject = $this->userManager->get($targetUser);

if (!$userObject instanceof IUser) {
$this->logger->error('Could not import: Unknown user ' . $user);
if (!($authorObject instanceof IUser) || !($targetUserObject instanceof IUser)) {
if (!($authorObject instanceof IUser)) {
$this->logger->error('Could not import: Unknown author ' . $author);
} elseif (!($targetUserObject instanceof IUser)) {
$this->logger->error('Could not import: Unknown target user ' . $targetUser);
}
$this->failedNotication($import);
$this->mapper->delete($import);
return;
Expand All @@ -80,8 +95,9 @@ public function run($argument): void {
try {
$import->setStatus(UserImport::STATUS_STARTED);
$this->mapper->update($import);
$importSource = new UserFolderImportSource($this->root->getUserFolder($author), $path);

$this->migrationService->import($path, $userObject);
$this->migrationService->import($importSource, $targetUserObject);
$this->successNotification($import);
} catch (\Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
Expand All @@ -94,11 +110,13 @@ public function run($argument): void {
private function failedNotication(UserImport $import): void {
// Send notification to user
$notification = $this->notificationManager->createNotification();
$notification->setUser($import->getSourceUser())
$notification->setUser($import->getAuthor())
->setApp(Application::APP_ID)
->setDateTime($this->time->getDateTime())
->setSubject('importFailed', [
'sourceUser' => $import->getSourceUser(),
'author' => $import->getAuthor(),
'targetUser' => $import->getTargetUser(),
'path' => $import->getPath(),
])
->setObject('import', (string)$import->getId());
$this->notificationManager->notify($notification);
Expand All @@ -107,11 +125,13 @@ private function failedNotication(UserImport $import): void {
private function successNotification(UserImport $import): void {
// Send notification to user
$notification = $this->notificationManager->createNotification();
$notification->setUser($import->getSourceUser())
$notification->setUser($import->getAuthor())
->setApp(Application::APP_ID)
->setDateTime($this->time->getDateTime())
->setSubject('importDone', [
'sourceUser' => $import->getSourceUser(),
'author' => $import->getAuthor(),
'targetUser' => $import->getTargetUser(),
'path' => $import->getPath(),
])
->setObject('import', (string)$import->getId());
$this->notificationManager->notify($notification);
Expand Down
7 changes: 6 additions & 1 deletion lib/Command/Import.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

namespace OCA\UserMigration\Command;

use OCA\UserMigration\ImportSource;
use OCA\UserMigration\Service\UserMigrationService;
use OCP\IUserManager;
use Symfony\Component\Console\Command\Command;
Expand Down Expand Up @@ -90,7 +91,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
} else {
$user = null;
}
$this->migrationService->import($input->getArgument('archive'), $user, $output);
$path = $input->getArgument('archive');
$output->writeln("Importing from ${path}…");
$importSource = new ImportSource($path);
$this->migrationService->import($importSource, $user, $output);
$output->writeln("Successfully imported from ${path}");
} catch (\Exception $e) {
$output->writeln("$e");
$output->writeln("<error>" . $e->getMessage() . "</error>");
Expand Down
97 changes: 88 additions & 9 deletions lib/Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@

use OCA\UserMigration\AppInfo\Application;
use OCA\UserMigration\BackgroundJob\UserExportJob;
use OCA\UserMigration\BackgroundJob\UserImportJob;
use OCA\UserMigration\Db\UserExport;
use OCA\UserMigration\Db\UserExportMapper;
use OCA\UserMigration\Db\UserImport;
use OCA\UserMigration\Db\UserImportMapper;
use OCA\UserMigration\Service\UserMigrationService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
Expand All @@ -38,29 +41,38 @@
use OCP\AppFramework\OCSController;
use OCP\BackgroundJob\IJobList;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\UserMigration\IMigrator;

class ApiController extends OCSController {
private IUserSession $userSession;

private IUserManager $userManager;

private UserMigrationService $migrationService;

private UserExportMapper $exportMapper;

private UserImportMapper $importMapper;

private IJobList $jobList;

public function __construct(
IRequest $request,
IUserSession $userSession,
IUserManager $userManager,
UserMigrationService $migrationService,
UserExportMapper $exportMapper,
UserImportMapper $importMapper,
IJobList $jobList
) {
parent::__construct(Application::APP_ID, $request);
$this->userSession = $userSession;
$this->userManager = $userManager;
$this->migrationService = $migrationService;
$this->exportMapper = $exportMapper;
$this->importMapper = $importMapper;
$this->jobList = $jobList;
}

Expand Down Expand Up @@ -99,9 +111,7 @@ public function status(): DataResponse {
// Allow this exception as this just means the user has no export jobs queued currently
}

// TODO handle import job status

$statusMap = [
$exportStatusMap = [
UserExport::STATUS_WAITING => 'waiting',
UserExport::STATUS_STARTED => 'started',
];
Expand All @@ -110,7 +120,26 @@ public function status(): DataResponse {
return new DataResponse([
'current' => 'export',
'migrators' => $userExport->getMigratorsArray(),
'status' => $statusMap[$userExport->getStatus()],
'status' => $exportStatusMap[$userExport->getStatus()],
], Http::STATUS_OK);
}

try {
$userImport = $this->importMapper->getByTargetUser($user->getUID());
} catch (DoesNotExistException $e) {
// Allow this exception as this just means the user has no import jobs queued currently
}

$importStatusMap = [
UserImport::STATUS_WAITING => 'waiting',
UserImport::STATUS_STARTED => 'started',
];

if (!empty($userImport)) {
return new DataResponse([
'current' => 'import',
'migrators' => $userImport->getMigratorsArray(),
'status' => $importStatusMap[$userImport->getStatus()],
], Http::STATUS_OK);
}

Expand Down Expand Up @@ -148,6 +177,13 @@ public function export(array $migrators): DataResponse {
// Allow this exception to proceed with adding user export job
}

try {
$userImport = $this->importMapper->getByTargetUser($user->getUID());
throw new OCSException('User import already queued');
} catch (DoesNotExistException $e) {
// Allow this exception to proceed with adding user import job
}

$userExport = new UserExport();
$userExport->setSourceUser($user->getUID());
$userExport->setMigratorsArray($migrators);
Expand All @@ -167,15 +203,58 @@ public function export(array $migrators): DataResponse {
* @NoSubAdminRequired
* @PasswordConfirmationRequired
*/
public function import(string $path): DataResponse {
$user = $this->userSession->getUser();
public function import(string $path, string $targetUserId): DataResponse {
$author = $this->userSession->getUser();

if (empty($user)) {
if (empty($author)) {
throw new OCSException('No user currently logged in');
}

// TODO queue import job
$targetUser = $this->userManager->get($targetUserId);
if (empty($targetUser)) {
throw new OCSException('Target user does not exist');
}

// Importing into another user's account is not allowed for now
if ($author->getUID() !== $targetUser->getUID()) {
throw new OCSException('Users may only import into their own account');
}

/** @var string[] $availableMigrators */
$availableMigrators = array_map(
fn (IMigrator $migrator) => $migrator->getId(),
$this->migrationService->getMigrators(),
);

try {
$userImport = $this->importMapper->getByTargetUser($targetUser->getUID());
throw new OCSException('User import already queued');
} catch (DoesNotExistException $e) {
// Allow this exception to proceed with adding user import job
}

return new DataResponse();
try {
$userExport = $this->exportMapper->getBySourceUser($targetUser->getUID());
throw new OCSException('User export already queued');
} catch (DoesNotExistException $e) {
// Allow this exception to proceed with adding user export job
}

$userImport = new UserImport();
$userImport->setAuthor($author->getUID());
$userImport->setTargetUser($targetUser->getUID());
// Path is relative to the author folder
$userImport->setPath($path);
// All available migrators are added as migrator selection for import is not allowed for now
$userImport->setMigratorsArray($availableMigrators);
$userImport->setStatus(UserImport::STATUS_WAITING);
/** @var UserImport $userImport */
$userImport = $this->importMapper->insert($userImport);

$this->jobList->add(UserImportJob::class, [
'id' => $userImport->getId(),
]);

return new DataResponse([], Http::STATUS_OK);
}
}
8 changes: 4 additions & 4 deletions lib/Db/UserImport.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
use OCP\AppFramework\Db\Entity;

/**
* @method void setSourceUser(string $uid)
* @method string getSourceUser()
* @method void setAuthor(string $uid)
* @method string getAuthor()
* @method void setTargetUser(string $uid)
* @method string getTargetUser()
* @method void setPath(string $path)
Expand All @@ -45,7 +45,7 @@ class UserImport extends Entity {
public const STATUS_STARTED = 1;

/** @var string */
protected $sourceUser;
protected $author;
/** @var string */
protected $targetUser;
/** @var string */
Expand All @@ -56,7 +56,7 @@ class UserImport extends Entity {
protected $status;

public function __construct() {
$this->addType('sourceUser', 'string');
$this->addType('author', 'string');
$this->addType('targetUser', 'string');
$this->addType('path', 'string');
$this->addType('migrators', 'string');
Expand Down
4 changes: 2 additions & 2 deletions lib/Db/UserImportMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ public function getById(int $id): UserImport {
return $this->findEntity($qb);
}

public function getBySourceUser(string $userId): UserImport {
public function getByAuthor(string $userId): UserImport {
$qb = $this->db->getQueryBuilder();

$qb->select('*')
->from($this->getTableName())
->where(
$qb->expr()->eq('source_user', $qb->createNamedParameter($userId))
$qb->expr()->eq('author', $qb->createNamedParameter($userId))
);

return $this->findEntity($qb);
Expand Down
2 changes: 1 addition & 1 deletion lib/Migration/Version00001Date20220412116131.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
'length' => 20,
'unsigned' => true,
]);
$table->addColumn('source_user', Types::STRING, [
$table->addColumn('author', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
Expand Down
Loading