Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 0 deletions apps/settings/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,7 @@
'OCA\\Settings\\SetupChecks\\PhpDefaultCharset' => $baseDir . '/../lib/SetupChecks/PhpDefaultCharset.php',
'OCA\\Settings\\SetupChecks\\PhpOutputBuffering' => $baseDir . '/../lib/SetupChecks/PhpOutputBuffering.php',
'OCA\\Settings\\SetupChecks\\SupportedDatabase' => $baseDir . '/../lib/SetupChecks/SupportedDatabase.php',
'OCA\\Settings\\UserMigration\\AccountMigrator' => $baseDir . '/../lib/UserMigration/AccountMigrator.php',
'OCA\\Settings\\UserMigration\\AccountMigratorException' => $baseDir . '/../lib/UserMigration/AccountMigratorException.php',
'OCA\\Settings\\WellKnown\\SecurityTxtHandler' => $baseDir . '/../lib/WellKnown/SecurityTxtHandler.php',
);
2 changes: 2 additions & 0 deletions apps/settings/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class ComposerStaticInitSettings
'OCA\\Settings\\SetupChecks\\PhpDefaultCharset' => __DIR__ . '/..' . '/../lib/SetupChecks/PhpDefaultCharset.php',
'OCA\\Settings\\SetupChecks\\PhpOutputBuffering' => __DIR__ . '/..' . '/../lib/SetupChecks/PhpOutputBuffering.php',
'OCA\\Settings\\SetupChecks\\SupportedDatabase' => __DIR__ . '/..' . '/../lib/SetupChecks/SupportedDatabase.php',
'OCA\\Settings\\UserMigration\\AccountMigrator' => __DIR__ . '/..' . '/../lib/UserMigration/AccountMigrator.php',
'OCA\\Settings\\UserMigration\\AccountMigratorException' => __DIR__ . '/..' . '/../lib/UserMigration/AccountMigratorException.php',
'OCA\\Settings\\WellKnown\\SecurityTxtHandler' => __DIR__ . '/..' . '/../lib/WellKnown/SecurityTxtHandler.php',
);

Expand Down
3 changes: 3 additions & 0 deletions apps/settings/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
use OCA\Settings\Middleware\SubadminMiddleware;
use OCA\Settings\Search\AppSearch;
use OCA\Settings\Search\SectionSearch;
use OCA\Settings\UserMigration\AccountMigrator;
use OCA\Settings\WellKnown\SecurityTxtHandler;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
Expand Down Expand Up @@ -131,6 +132,8 @@ public function register(IRegistrationContext $context): void {
Util::getDefaultEmailAddress('no-reply')
);
});

$context->registerUserMigrator(AccountMigrator::class);
}

public function boot(IBootContext $context): void {
Expand Down
136 changes: 136 additions & 0 deletions apps/settings/lib/UserMigration/AccountMigrator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

declare(strict_types=1);

/**
* @copyright 2022 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @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/>.
*
*/

namespace OCA\Settings\UserMigration;

use InvalidArgumentException;
use OC\Accounts\TAccountsHelper;
use OC\NotSquareException;
use OCP\Accounts\IAccountManager;
use OCP\IAvatarManager;
use OCP\IUser;
use OCP\UserMigration\IExportDestination;
use OCP\UserMigration\IImportSource;
use OCP\UserMigration\IMigrator;
use OCP\UserMigration\TMigratorBasicVersionHandling;
use Symfony\Component\Console\Output\OutputInterface;
use Throwable;

class AccountMigrator implements IMigrator {
use TMigratorBasicVersionHandling;

use TAccountsHelper;

private IAccountManager $accountManager;

private IAvatarManager $avatarManager;

private const EXPORT_ACCOUNT_FILE = 'account.json';

private const EXPORT_AVATAR_BASENAME = 'avatar';

public function __construct(
IAccountManager $accountManager,
IAvatarManager $avatarManager
) {
$this->accountManager = $accountManager;
$this->avatarManager = $avatarManager;
}

/**
* {@inheritDoc}
*/
public function export(IUser $user, IExportDestination $exportDestination, OutputInterface $output): void {
$output->writeln('Exporting account information in ' . AccountMigrator::EXPORT_ACCOUNT_FILE . '…');

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

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

$output->writeln('Exporting avatar to ' . $exportFilename . '…');
if ($exportDestination->addFileAsStream($exportFilename, $avatarFile->read()) === false) {
throw new AccountMigratorException('Could not export avatar');
}
}
}

/**
* {@inheritDoc}
*/
public function import(IUser $user, IImportSource $importSource, OutputInterface $output): void {
if ($importSource->getMigratorVersion(static::class) === null) {
$output->writeln('No version for ' . static::class . ', skipping import…');
return;
}

$output->writeln('Importing account information from ' . AccountMigrator::EXPORT_ACCOUNT_FILE . '…');

$account = $this->accountManager->getAccount($user);

/** @var array<string, array<string, string>>|array<string, array<int, array<string, string>>> $data */
$data = json_decode($importSource->getFileContents(AccountMigrator::EXPORT_ACCOUNT_FILE), true, 512, JSON_THROW_ON_ERROR);

$account->setAllPropertiesFromJson($data);

try {
$this->accountManager->updateAccount($account);
} catch (InvalidArgumentException $e) {
throw new AccountMigratorException('Failed to import account information');
}

$avatarFiles = array_filter(
$importSource->getFolderListing(''),
fn (string $filename) => pathinfo($filename, PATHINFO_FILENAME) === AccountMigrator::EXPORT_AVATAR_BASENAME,
);

if (!empty($avatarFiles)) {
if (count($avatarFiles) >= 2) {
$output->writeln('Expected single avatar image file, using first file found');
}

$importFilename = reset($avatarFiles);

$output->writeln('Importing avatar from ' . $importFilename . '…');
$stream = $importSource->getFileAsStream($importFilename);
$image = new \OC_Image();
$image->loadFromFileHandle($stream);

try {
$avatar = $this->avatarManager->getAvatar($user->getUID());
$avatar->set($image);
} catch (NotSquareException $e) {
throw new AccountMigratorException('Avatar image must be square');
} catch (Throwable $e) {
throw new AccountMigratorException('Failed to import avatar', 0, $e);
}
}
}
}
32 changes: 32 additions & 0 deletions apps/settings/lib/UserMigration/AccountMigratorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/**
* @copyright 2022 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @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/>.
*
*/

namespace OCA\Settings\UserMigration;

use OCP\UserMigration\UserMigrationException;

class AccountMigratorException extends UserMigrationException {
}