Skip to content

Commit

Permalink
Merge pull request #35 from utopia-php/fix-firebase-migrations
Browse files Browse the repository at this point in the history
Fix Firebase Phone User Migrations
  • Loading branch information
abnegate authored Jul 10, 2024
2 parents 4c6f44d + 1fbb8e0 commit f0e7ff0
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ test-service-account.json
.DS_Store
localBackup/
.vscode/
.env.prod
.env.prod
serviceAccount.json
76 changes: 63 additions & 13 deletions bin/MigrationCLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
require_once __DIR__.'/.././vendor/autoload.php';

use Dotenv\Dotenv;
use Utopia\Migration\Destination;
use Utopia\Migration\Destinations\Appwrite as DestinationsAppwrite;
use Utopia\Migration\Destinations\Local;
use Utopia\Migration\Source;
use Utopia\Migration\Sources\Appwrite;
use Utopia\Migration\Sources\Firebase;
use Utopia\Migration\Sources\NHost;
use Utopia\Migration\Sources\Supabase;
use Utopia\Migration\Transfer;

/**
Expand All @@ -14,9 +20,9 @@ class MigrationCLI
{
protected Transfer $transfer;

protected Appwrite $source;
protected mixed $source;

protected DestinationsAppwrite $destination;
protected mixed $destination;

/**
* Prints the current status of migrations as a table after wiping the screen
Expand Down Expand Up @@ -49,11 +55,63 @@ public function drawFrame()
echo "\n\nSource Errors:\n";
foreach ($sourceErrors as $error) {
/** @var Utopia\Migration\Exception $error */
echo $error->getResourceType().'['.$error->getResourceId().'] - '.$error->getMessage()."\n";
echo $error->getResourceGroup().'['.$error->getResourceId().'] - '.$error->getMessage()."\n";
}
}
}

public function getSource(): Source
{
switch ($_ENV['SOURCE_PROVIDER']) {
case 'appwrite':
return new Appwrite(
$_ENV['SOURCE_APPWRITE_TEST_PROJECT'],
$_ENV['SOURCE_APPWRITE_TEST_ENDPOINT'],
$_ENV['SOURCE_APPWRITE_TEST_KEY']
);
case 'supabase':
return new Supabase(
$_ENV['SOURCE_SUPABASE_TEST_ENDPOINT'],
$_ENV['SOURCE_SUPABASE_TEST_KEY'],
$_ENV['SOURCE_SUPABASE_TEST_HOST'],
$_ENV['SOURCE_SUPABASE_TEST_DATBASE_NAME'],
$_ENV['SOURCE_SUPABASE_TEST_DATABASE_USER'],
$_ENV['SOURCE_SUPABASE_TEST_DATABASE_PASSWORD']
);
case 'firebase':
return new Firebase(
json_decode(file_get_contents(__DIR__.'/serviceAccount.json'), true)
);
case 'nhost':
return new NHost(
$_ENV['SOURCE_NHOST_TEST_SUBDOMAIN'],
$_ENV['SOURCE_NHOST_TEST_REGION'],
$_ENV['SOURCE_NHOST_TEST_ADMIN_SECRET'],
$_ENV['SOURCE_NHOST_TEST_DATABASE_NAME'],
$_ENV['SOURCE_NHOST_TEST_DATABASE_USER'],
$_ENV['SOURCE_NHOST_TEST_DATABASE_PASSWORD']
);
default:
throw new Exception('Invalid source provider');
}
}

public function getDestination(): Destination
{
switch ($_ENV['DESTINATION_PROVIDER']) {
case 'appwrite':
return new DestinationsAppwrite(
$_ENV['DESTINATION_APPWRITE_TEST_PROJECT'],
$_ENV['DESTINATION_APPWRITE_TEST_ENDPOINT'],
$_ENV['DESTINATION_APPWRITE_TEST_KEY']
);
case 'local':
return new Local('./localBackup');
default:
throw new Exception('Invalid destination provider');
}
}

public function start()
{
$dotenv = Dotenv::createImmutable(__DIR__);
Expand All @@ -62,19 +120,11 @@ public function start()
/**
* Initialise All Source Adapters
*/
$this->source = new Appwrite(
$_ENV['SOURCE_APPWRITE_TEST_PROJECT'],
$_ENV['SOURCE_APPWRITE_TEST_ENDPOINT'],
$_ENV['SOURCE_APPWRITE_TEST_KEY']
);
$this->source = $this->getSource();

// $source->report();

$this->destination = new DestinationsAppwrite(
$_ENV['DESTINATION_APPWRITE_TEST_PROJECT'],
$_ENV['DESTINATION_APPWRITE_TEST_ENDPOINT'],
$_ENV['DESTINATION_APPWRITE_TEST_KEY']
);
$this->destination = $this->getDestination();

/**
* Initialise Transfer Class
Expand Down
18 changes: 13 additions & 5 deletions src/Migration/Sources/Firebase.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,26 @@ private function exportUsers(int $batchSize)
$nextPageToken = $response['nextPageToken'] ?? null;

foreach ($result as $user) {
$users[] = new User(
$transferUser = new User(
$user['localId'] ?? '',
$user['email'] ?? '',
$user['displayName'] ?? $user['email'] ?? '',
new Hash($user['passwordHash'] ?? '', $user['salt'] ?? '', Hash::ALGORITHM_SCRYPT_MODIFIED, $hashConfig['saltSeparator'] ?? '', $hashConfig['signerKey'] ?? ''),
$user['phoneNumber'] ?? '',
$user['email'] ?? null,
$user['displayName'] ?? $user['email'] ?? null,
null,
$user['phoneNumber'] ?? null,
[],
'',
$user['emailVerified'] ?? false,
false, // Can't get phone number status on firebase :/
$user['disabled'] ?? false
);

if (array_key_exists('passwordHash', $user)) {
$transferUser->setPasswordHash(
new Hash($user['passwordHash'], $user['salt'] ?? '', Hash::ALGORITHM_SCRYPT_MODIFIED, $hashConfig['saltSeparator'] ?? '', $hashConfig['signerKey'] ?? '')
);
}

$users[] = $transferUser;
}

$this->callback($users);
Expand Down
16 changes: 11 additions & 5 deletions src/Migration/Sources/NHost.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,19 +248,25 @@ private function exportUsers(int $batchSize)
$transferUsers = [];

foreach ($users as $user) {
$transferUsers[] = new User(
$transferUser = new User(
$user['id'],
$user['email'] ?? '',
$user['display_name'] ?? '',
new Hash($user['password_hash'], '', Hash::ALGORITHM_BCRYPT),
$user['phone_number'] ?? '',
$user['email'] ?? null,
$user['display_name'] ?? null,
null,
$user['phone_number'] ?? null,
[],
'',
$user['email_verified'] ?? false,
$user['phone_number_verified'] ?? false,
$user['disabled'] ?? false,
[]
);

if (array_key_exists('password_hash', $user)) {
$transferUser->setPasswordHash(new Hash($user['password_hash'], '', Hash::ALGORITHM_BCRYPT));
}

$transferUsers[] = $transferUser;
}

$this->callback($transferUsers);
Expand Down
14 changes: 10 additions & 4 deletions src/Migration/Sources/Supabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -382,19 +382,25 @@ private function exportUsers(int $batchSize)
$transferUsers = [];

foreach ($users as $user) {
$transferUsers[] = new User(
$transferUser = new User(
$user['id'],
$user['email'] ?? '',
$user['email'] ?? null,
'',
new Hash($user['encrypted_password'], '', Hash::ALGORITHM_BCRYPT),
$user['phone'] ?? '',
null,
$user['phone'] ?? null,
[],
'',
! empty($user['email_confirmed_at']),
! empty($user['phone_confirmed_at']),
false,
[]
);

if (array_key_exists('encrypted_password', $user)) {
$transferUser->setPasswordHash(new Hash($user['encrypted_password'], '', Hash::ALGORITHM_BCRYPT));
}

$transferUsers[] = $transferUser;
}

$this->callback($transferUsers);
Expand Down
5 changes: 3 additions & 2 deletions src/Migration/Transfer.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ public function getStatusCounters()

// Process Destination Errors
foreach ($this->destination->getErrors() as $error) {
if (isset($status[$error->getResourceType()])) {
$status[$error->getResourceType()][Resource::STATUS_ERROR]++;
/** @var Exception $error */
if (isset($status[$error->getResourceGroup()])) {
$status[$error->getResourceGroup()][Resource::STATUS_ERROR]++;
}
}

Expand Down
3 changes: 1 addition & 2 deletions tests/Migration/E2E/Sources/NHostTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ public function testRunTransfer($state)
{
$this->transfer->run(
$this->source->getSupportedResources(),
function () {
}
function () {}
);

$this->assertEquals(0, count($this->transfer->getReport('error')));
Expand Down
3 changes: 1 addition & 2 deletions tests/Migration/E2E/Sources/SupabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ public function testSourceReport()
public function testRunTransfer($state)
{
$this->transfer->run($this->source->getSupportedResources(),
function () {
}
function () {}
);

$this->assertEquals(0, count($this->transfer->getReport('error')));
Expand Down

0 comments on commit f0e7ff0

Please sign in to comment.