Skip to content

Commit

Permalink
Merge pull request #31945 from nextcloud/fix/user_migration-use-excep…
Browse files Browse the repository at this point in the history
…tions

Adapt user_migration APIs to have information about failures
  • Loading branch information
PVince81 authored Apr 13, 2022
2 parents 964bc57 + 78c8e57 commit 58f5de0
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 63 deletions.
24 changes: 13 additions & 11 deletions apps/dav/lib/UserMigration/CalendarMigrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,18 +225,20 @@ public function export(IUser $user, IExportDestination $exportDestination, Outpu
$output->writeln('No calendars to export…');
}

/**
* @var string $name
* @var VCalendar $vCalendar
*/
foreach ($calendarExports as ['name' => $name, 'vCalendar' => $vCalendar]) {
// Set filename to sanitized calendar name appended with the date
$filename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $name) . '_' . date('Y-m-d') . CalendarMigrator::FILENAME_EXT;
$exportPath = CalendarMigrator::EXPORT_ROOT . $filename;

if ($exportDestination->addFileContents($exportPath, $vCalendar->serialize()) === false) {
throw new CalendarMigratorException('Could not export calendars');
try {
/**
* @var string $name
* @var VCalendar $vCalendar
*/
foreach ($calendarExports as ['name' => $name, 'vCalendar' => $vCalendar]) {
// Set filename to sanitized calendar name appended with the date
$filename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $name) . '_' . date('Y-m-d') . CalendarMigrator::FILENAME_EXT;
$exportPath = CalendarMigrator::EXPORT_ROOT . $filename;

$exportDestination->addFileContents($exportPath, $vCalendar->serialize());
}
} catch (Throwable $e) {
throw new CalendarMigratorException('Could not export calendars', 0, $e);
}
}

Expand Down
38 changes: 19 additions & 19 deletions apps/dav/lib/UserMigration/ContactsMigrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,26 +205,26 @@ public function export(IUser $user, IExportDestination $exportDestination, Outpu
$output->writeln('No contacts to export…');
}

/**
* @var string $name
* @var string $displayName
* @var ?string $description
* @var VCard[] $vCards
*/
foreach ($addressBookExports as ['name' => $name, 'displayName' => $displayName, 'description' => $description, 'vCards' => $vCards]) {
// Set filename to sanitized address book name appended with the date
$basename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $name) . '_' . date('Y-m-d');
$exportPath = ContactsMigrator::PATH_ROOT . $basename . '.' . ContactsMigrator::FILENAME_EXT;
$metadataExportPath = ContactsMigrator::PATH_ROOT . $basename . '.' . ContactsMigrator::METADATA_EXT;

if ($exportDestination->addFileContents($exportPath, $this->serializeCards($vCards)) === false) {
throw new ContactsMigratorException('Could not export address book');
}

$metadata = array_filter(['displayName' => $displayName, 'description' => $description]);
if ($exportDestination->addFileContents($metadataExportPath, json_encode($metadata)) === false) {
throw new ContactsMigratorException('Could not export address book metadata');
try {
/**
* @var string $name
* @var string $displayName
* @var ?string $description
* @var VCard[] $vCards
*/
foreach ($addressBookExports as ['name' => $name, 'displayName' => $displayName, 'description' => $description, 'vCards' => $vCards]) {
// Set filename to sanitized address book name appended with the date
$basename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $name) . '_' . date('Y-m-d');
$exportPath = ContactsMigrator::PATH_ROOT . $basename . '.' . ContactsMigrator::FILENAME_EXT;
$metadataExportPath = ContactsMigrator::PATH_ROOT . $basename . '.' . ContactsMigrator::METADATA_EXT;

$exportDestination->addFileContents($exportPath, $this->serializeCards($vCards));

$metadata = array_filter(['displayName' => $displayName, 'description' => $description]);
$exportDestination->addFileContents($metadataExportPath, json_encode($metadata));
}
} catch (Throwable $e) {
throw new CalendarMigratorException('Could not export address book', 0, $e);
}
}

Expand Down
18 changes: 9 additions & 9 deletions apps/files_trashbin/lib/UserMigration/TrashbinMigrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,16 @@ public function export(IUser $user, IExportDestination $exportDestination, Outpu
try {
$trashbinFolder = $this->root->get('/'.$uid.'/files_trashbin');
if (!$trashbinFolder instanceof Folder) {
throw new UserMigrationException('Could not export trashbin, /'.$uid.'/files_trashbin is not a folder');
throw new UserMigrationException('/'.$uid.'/files_trashbin is not a folder');
}
$output->writeln("Exporting trashbin files…");
if ($exportDestination->copyFolder($trashbinFolder, static::PATH_FILES_FOLDER) === false) {
throw new UserMigrationException("Could not export trashbin.");
}
$exportDestination->copyFolder($trashbinFolder, static::PATH_FILES_FOLDER);
$originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($uid);
if ($exportDestination->addFileContents(static::PATH_LOCATIONS_FILE, json_encode($originalLocations)) === false) {
throw new UserMigrationException("Could not export trashbin.");
}
$exportDestination->addFileContents(static::PATH_LOCATIONS_FILE, json_encode($originalLocations));
} catch (NotFoundException $e) {
$output->writeln("No trashbin to export…");
} catch (\Throwable $e) {
throw new UserMigrationException("Could not export trashbin: ".$e->getMessage(), 0, $e);
}
}

Expand All @@ -112,8 +110,10 @@ public function import(IUser $user, IImportSource $importSource, OutputInterface
$trashbinFolder = $this->root->newFolder('/'.$uid.'/files_trashbin');
}
$output->writeln("Importing trashbin files…");
if ($importSource->copyToFolder($trashbinFolder, static::PATH_FILES_FOLDER) === false) {
throw new UserMigrationException("Could not import trashbin.");
try {
$importSource->copyToFolder($trashbinFolder, static::PATH_FILES_FOLDER);
} catch (\Throwable $e) {
throw new UserMigrationException("Could not import trashbin.", 0, $e);
}
$locations = json_decode($importSource->getFileContents(static::PATH_LOCATIONS_FILE), true, 512, JSON_THROW_ON_ERROR);
$qb = $this->dbc->getQueryBuilder();
Expand Down
22 changes: 11 additions & 11 deletions apps/settings/lib/UserMigration/AccountMigrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,20 @@ public function __construct(
public function export(IUser $user, IExportDestination $exportDestination, OutputInterface $output): void {
$output->writeln('Exporting account information in ' . AccountMigrator::PATH_ACCOUNT_FILE . '');

$account = $this->accountManager->getAccount($user);
if ($exportDestination->addFileContents(AccountMigrator::PATH_ACCOUNT_FILE, json_encode($account)) === false) {
throw new AccountMigratorException('Could not export account information');
}
try {
$account = $this->accountManager->getAccount($user);
$exportDestination->addFileContents(AccountMigrator::PATH_ACCOUNT_FILE, json_encode($account));

$avatar = $this->avatarManager->getAvatar($user->getUID());
if ($avatar->isCustomAvatar()) {
$avatarFile = $avatar->getFile(-1);
$exportPath = AccountMigrator::PATH_ROOT . AccountMigrator::AVATAR_BASENAME . '.' . $avatarFile->getExtension();
$avatar = $this->avatarManager->getAvatar($user->getUID());
if ($avatar->isCustomAvatar()) {
$avatarFile = $avatar->getFile(-1);
$exportPath = AccountMigrator::PATH_ROOT . AccountMigrator::AVATAR_BASENAME . '.' . $avatarFile->getExtension();

$output->writeln('Exporting avatar to ' . $exportPath . '');
if ($exportDestination->addFileAsStream($exportPath, $avatarFile->read()) === false) {
throw new AccountMigratorException('Could not export avatar');
$output->writeln('Exporting avatar to ' . $exportPath . '');
$exportDestination->addFileAsStream($exportPath, $avatarFile->read());
}
} catch (Throwable $e) {
throw new AccountMigratorException('Could not export account information', 0, $e);
}
}

Expand Down
6 changes: 2 additions & 4 deletions apps/settings/tests/UserMigration/AccountMigratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,12 @@ public function testImportExportAccount(string $userId, array $importData, strin
$this->exportDestination
->expects($this->once())
->method('addFileContents')
->with($this->matchesRegularExpression(self::REGEX_ACCOUNT_FILE), json_encode($exportData))
->willReturn(true);
->with($this->matchesRegularExpression(self::REGEX_ACCOUNT_FILE), json_encode($exportData));

$this->exportDestination
->expects($this->once())
->method('addFileAsStream')
->with($this->matchesRegularExpression(self::REGEX_AVATAR_FILE), $this->isType('resource'))
->willReturn(true);
->with($this->matchesRegularExpression(self::REGEX_AVATAR_FILE), $this->isType('resource'));

$this->migrator->export($user, $this->exportDestination, $this->output);
}
Expand Down
17 changes: 10 additions & 7 deletions lib/public/UserMigration/IExportDestination.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,47 @@ interface IExportDestination {
*
* @param string $path Full path to the file in the export archive. Parent directories will be created if needed.
* @param string $content The full content of the file.
* @return bool whether the file contents were successfully added.
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function addFileContents(string $path, string $content): bool;
public function addFileContents(string $path, string $content): void;

/**
* Adds a file to the export as a stream
*
* @param string $path Full path to the file in the export archive. Parent directories will be created if needed.
* @param resource $stream A stream resource to read from to get the file content.
* @return bool whether the file stream was successfully added.
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function addFileAsStream(string $path, $stream): bool;
public function addFileAsStream(string $path, $stream): void;

/**
* Copy a folder to the export
*
* @param Folder $folder folder to copy to the export archive.
* @param string $destinationPath Full path to the folder in the export archive. Parent directories will be created if needed.
* @return bool whether the folder was successfully added.
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function copyFolder(Folder $folder, string $destinationPath): bool;
public function copyFolder(Folder $folder, string $destinationPath): void;

/**
* @param array<string,int> $versions Migrators and their versions.
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function setMigratorVersions(array $versions): bool;
public function setMigratorVersions(array $versions): void;

/**
* Called after export is complete
*
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function close(): void;
Expand Down
16 changes: 14 additions & 2 deletions lib/public/UserMigration/IImportSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface IImportSource {
*
* @param string $path Full path to the file in the export archive.
* @return string The full content of the file.
* @throws UserMigrationException
*
* @since 24.0.0
*/
Expand All @@ -49,6 +50,7 @@ public function getFileContents(string $path): string;
*
* @param string $path Full path to the file in the export archive.
* @return resource A stream resource to read from to get the file content.
* @throws UserMigrationException
*
* @since 24.0.0
*/
Expand All @@ -59,6 +61,7 @@ public function getFileAsStream(string $path);
*
* @param string $path Full path to the folder in the export archive.
* @return array The list of files.
* @throws UserMigrationException
*
* @since 24.0.0
*/
Expand All @@ -67,6 +70,8 @@ public function getFolderListing(string $path): array;
/**
* Test if a path exists, which may be a file or a folder
*
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function pathExists(string $path): bool;
Expand All @@ -77,20 +82,23 @@ public function pathExists(string $path): bool;
* Folder $destination folder to copy into
* string $sourcePath path in the export archive
*
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function copyToFolder(Folder $destination, string $sourcePath): bool;
public function copyToFolder(Folder $destination, string $sourcePath): void;

/**
* @return array<string,int> Migrators and their versions from the export archive.
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function getMigratorVersions(): array;

/**
* @return ?int Version for this migrator from the export archive. Null means migrator missing.
*
* @throws UserMigrationException
* @param string $migrator Migrator id (as returned by IMigrator::getId)
*
* @since 24.0.0
Expand All @@ -100,13 +108,17 @@ public function getMigratorVersion(string $migrator): ?int;
/**
* Get original uid of the imported account
*
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function getOriginalUid(): string;

/**
* Called after import is complete
*
* @throws UserMigrationException
*
* @since 24.0.0
*/
public function close(): void;
Expand Down

0 comments on commit 58f5de0

Please sign in to comment.