Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add exportable endpoint
Signed-off-by: Christopher Ng <[email protected]>
  • Loading branch information
Pytal committed Jun 2, 2022
commit 5a9f98de07d874546263eb0aa55e7a6aa5425eee
2 changes: 1 addition & 1 deletion appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
['name' => 'Api#migrators', 'url' => '/api/v{apiVersion}/migrators', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'Api#status', 'url' => '/api/v{apiVersion}/status', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'Api#cancel', 'url' => '/api/v{apiVersion}/cancel', 'verb' => 'PUT', 'requirements' => $requirements],
['name' => 'Api#estimateExportSize', 'url' => '/api/v{apiVersion}/estimate', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'Api#exportable', 'url' => '/api/v{apiVersion}/exportable', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'Api#export', 'url' => '/api/v{apiVersion}/export', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'Api#import', 'url' => '/api/v{apiVersion}/import', 'verb' => 'POST', 'requirements' => $requirements],
],
Expand Down
53 changes: 26 additions & 27 deletions lib/Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use OCA\UserMigration\AppInfo\Application;
use OCA\UserMigration\Db\UserExport;
use OCA\UserMigration\Db\UserImport;
use OCA\UserMigration\Service\NotExportableException;
use OCA\UserMigration\Service\UserMigrationService;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
Expand Down Expand Up @@ -170,6 +171,23 @@ public function cancel(): DataResponse {
return new DataResponse([], Http::STATUS_OK);
}

/**
* @throws OCSException
*/
private function checkMigrators(array $migrators): void {
/** @var string[] $availableMigrators */
$availableMigrators = array_map(
fn (IMigrator $migrator) => $migrator->getId(),
$this->migrationService->getMigrators(),
);

foreach ($migrators as $migrator) {
if (!in_array($migrator, $availableMigrators, true)) {
throw new OCSException("Requested migrator \"$migrator\" not available");
}
}
}

/**
* @throws OCSException
*/
Expand Down Expand Up @@ -199,28 +217,20 @@ private function checkJobAndGetUser(): IUser {
*
* @throws OCSException
*/
public function estimateExportSize(array $migrators): DataResponse {
public function exportable(?array $migrators): DataResponse {
$user = $this->checkJobAndGetUser();

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

foreach ($migrators as $migrator) {
if (!in_array($migrator, $availableMigrators, true)) {
throw new OCSException("Requested migrator \"$migrator\" not available");
}
if (!is_null($migrators)) {
$this->checkMigrators($migrators);
}

try {
$size = $this->migrationService->estimateExportSize($user, $migrators);
} catch (UserMigrationException $e) {
throw new OCSException('Error estimating export size');
$this->migrationService->checkExportability($user, $migrators);
} catch (NotExportableException $e) {
throw new OCSException($e->getMessage());
}

return new DataResponse(['kibibytes' => $size], Http::STATUS_OK);
return new DataResponse([], Http::STATUS_OK);
}

/**
Expand All @@ -232,18 +242,7 @@ public function estimateExportSize(array $migrators): DataResponse {
*/
public function export(array $migrators): DataResponse {
$user = $this->checkJobAndGetUser();

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

foreach ($migrators as $migrator) {
if (!in_array($migrator, $availableMigrators, true)) {
throw new OCSException("Requested migrator \"$migrator\" not available");
}
}
$this->checkMigrators($migrators);

try {
$this->migrationService->queueExportJob($user, $migrators);
Expand Down
32 changes: 32 additions & 0 deletions lib/Service/NotExportableException.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\UserMigration\Service;

use Exception;

class NotExportableException extends Exception {
}
34 changes: 33 additions & 1 deletion lib/Service/UserMigrationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

namespace OCA\UserMigration\Service;

use OC_Helper;
use OC_Util;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\Cache\CappedMemoryCache;
use OCA\UserMigration\BackgroundJob\UserExportJob;
Expand Down Expand Up @@ -104,9 +106,10 @@ public function __construct(

/**
* @param ?string[] $filteredMigratorList If not null, only these migrators will run. If empty only the main account data will be exported.
*
* @return int Estimated size in KiB
*/
public function estimateExportSize(IUser $user, ?array $filteredMigratorList = null): int {
private function estimateExportSize(IUser $user, ?array $filteredMigratorList = null): int {
$cacheKey = $user->getUID();
if ($filteredMigratorList !== null) {
$cacheKey .= '::' . json_encode($filteredMigratorList);
Expand All @@ -132,6 +135,35 @@ public function estimateExportSize(IUser $user, ?array $filteredMigratorList = n

/**
* @param ?string[] $filteredMigratorList If not null, only these migrators will run. If empty only the main account data will be exported.
*
* @throws NotExportableException
*/
public function checkExportability(IUser $user, ?array $filteredMigratorList = null): void {
try {
OC_Util::tearDownFS();
OC_Util::setupFS($user->getUID());
$storageInfo = OC_Helper::getStorageInfo('/');
// TODO safe to cache?
$freeSpace = (int)ceil($storageInfo['free'] / 1024);
} catch (Throwable $e) {
throw new NotExportableException('Error calculating amount of free space available');
}

try {
$exportSize = $this->estimateExportSize($user, $filteredMigratorList);
} catch (UserMigrationException $e) {
throw new NotExportableException('Error estimating export size');
}

$freeSpaceAfterExport = $freeSpace - $exportSize;
if ($freeSpaceAfterExport < 0) {
throw new NotExportableException('Insufficient storage space available to export, please free up ' . (int)abs($freeSpaceAfterExport) . ' KiB or more to be able to export your data');
}
}

/**
* @param ?string[] $filteredMigratorList If not null, only these migrators will run. If empty only the main account data will be exported.
*
* @throws UserMigrationException
*/
public function export(IExportDestination $exportDestination, IUser $user, ?array $filteredMigratorList = null, ?OutputInterface $output = null): void {
Expand Down