diff --git a/composer.json b/composer.json index 1b4c901ebd..65e44fa934 100644 --- a/composer.json +++ b/composer.json @@ -74,7 +74,7 @@ "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.8.*", "utopia-php/messaging": "0.22.*", - "utopia-php/migration": "dev-add-webhook-migration as 1.12.0", + "utopia-php/migration": "dev-add-auth-methods-migration as 1.12.0", "utopia-php/platform": "^1.0@RC", "utopia-php/pools": "1.*", "utopia-php/span": "1.1.*", diff --git a/composer.lock b/composer.lock index f913336194..575864182d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dbbf6239c2d7c6ddccd86d1c54f74ab4", + "content-hash": "9623d2109a32041ca4e395ab55266038", "packages": [ { "name": "adhocore/jwt", @@ -4606,16 +4606,16 @@ }, { "name": "utopia-php/migration", - "version": "dev-add-webhook-migration", + "version": "dev-add-auth-methods-migration", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "7fca4226ae33a60ec334d0dbdc1353c2464c4306" + "reference": "5224e3ce9a96373dfd83648b5e8e4e4d20b85020" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/7fca4226ae33a60ec334d0dbdc1353c2464c4306", - "reference": "7fca4226ae33a60ec334d0dbdc1353c2464c4306", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/5224e3ce9a96373dfd83648b5e8e4e4d20b85020", + "reference": "5224e3ce9a96373dfd83648b5e8e4e4d20b85020", "shasum": "" }, "require": { @@ -4672,10 +4672,10 @@ "utopia" ], "support": { - "source": "https://github.com/utopia-php/migration/tree/add-webhook-migration", + "source": "https://github.com/utopia-php/migration/tree/add-auth-methods-migration", "issues": "https://github.com/utopia-php/migration/issues" }, - "time": "2026-05-14T19:27:19+00:00" + "time": "2026-05-18T12:08:47+00:00" }, { "name": "utopia-php/mongo", @@ -8585,7 +8585,7 @@ "aliases": [ { "package": "utopia-php/migration", - "version": "dev-add-webhook-migration", + "version": "dev-add-auth-methods-migration", "alias": "1.12.0", "alias_normalized": "1.12.0.0" } diff --git a/src/Appwrite/Utopia/Response/Model/MigrationReport.php b/src/Appwrite/Utopia/Response/Model/MigrationReport.php index f767a28d9a..3db8d6520d 100644 --- a/src/Appwrite/Utopia/Response/Model/MigrationReport.php +++ b/src/Appwrite/Utopia/Response/Model/MigrationReport.php @@ -77,6 +77,12 @@ class MigrationReport extends Model 'default' => 0, 'example' => 5, ]) + ->addRule(Resource::TYPE_AUTH_METHODS, [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Number of auth-method configs to be migrated (always 0 or 1 — the project-level flag bundle).', + 'default' => 0, + 'example' => 1, + ]) ->addRule(Resource::TYPE_SITE, [ 'type' => self::TYPE_INTEGER, 'description' => 'Number of sites to be migrated.', diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index aa7b138190..b629c3962c 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -2697,6 +2697,59 @@ trait MigrationsBase $this->client->call(Client::METHOD_DELETE, '/webhooks/' . $sourceWebhook['$id'], $sourceHeaders); } + public function testAppwriteMigrationAuthMethods(): void + { + $consoleHeaders = [ + 'content-type' => 'application/json', + 'x-appwrite-project' => 'console', + 'origin' => 'http://localhost', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + ]; + + // Flip a couple of auth methods on the source so the round-trip is + // observable. Settling on email-password OFF and JWT OFF — the + // remaining flags stay on their server defaults. + $sourceProjectId = $this->getProject()['$id']; + $this->client->call(Client::METHOD_PATCH, '/projects/' . $sourceProjectId . '/auth/email-password', $consoleHeaders, [ + 'status' => false, + ]); + $this->client->call(Client::METHOD_PATCH, '/projects/' . $sourceProjectId . '/auth/jwt', $consoleHeaders, [ + 'status' => false, + ]); + + $result = $this->performMigrationSync([ + 'resources' => [ + Resource::TYPE_AUTH_METHODS, + ], + 'endpoint' => $this->webEndpoint, + 'projectId' => $sourceProjectId, + 'apiKey' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals('completed', $result['status']); + $this->assertEquals([Resource::TYPE_AUTH_METHODS], $result['resources']); + $this->assertArrayHasKey(Resource::TYPE_AUTH_METHODS, $result['statusCounters']); + $this->assertEquals(0, $result['statusCounters'][Resource::TYPE_AUTH_METHODS]['error']); + $this->assertEquals(0, $result['statusCounters'][Resource::TYPE_AUTH_METHODS]['pending']); + $this->assertEquals(1, $result['statusCounters'][Resource::TYPE_AUTH_METHODS]['success']); + $this->assertEquals(0, $result['statusCounters'][Resource::TYPE_AUTH_METHODS]['processing']); + $this->assertEquals(0, $result['statusCounters'][Resource::TYPE_AUTH_METHODS]['warning']); + + $destinationProjectId = $this->getDestinationProject()['$id']; + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $destinationProjectId, $consoleHeaders); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertFalse($response['body']['authEmailPassword'], 'authEmailPassword should be migrated as false'); + $this->assertFalse($response['body']['authJWT'], 'authJWT should be migrated as false'); + + // Restore source so the test is idempotent. + $this->client->call(Client::METHOD_PATCH, '/projects/' . $sourceProjectId . '/auth/email-password', $consoleHeaders, ['status' => true]); + $this->client->call(Client::METHOD_PATCH, '/projects/' . $sourceProjectId . '/auth/jwt', $consoleHeaders, ['status' => true]); + // Restore destination too. + $this->client->call(Client::METHOD_PATCH, '/projects/' . $destinationProjectId . '/auth/email-password', $consoleHeaders, ['status' => true]); + $this->client->call(Client::METHOD_PATCH, '/projects/' . $destinationProjectId . '/auth/jwt', $consoleHeaders, ['status' => true]); + } + /** * Import documents from a CSV file. */