diff --git a/.env b/.env index 372bfd7baa..2cf1275d55 100644 --- a/.env +++ b/.env @@ -86,4 +86,6 @@ _APP_GRAPHQL_MAX_COMPLEXITY=250 _APP_GRAPHQL_MAX_DEPTH=3 DOCKERHUB_PULL_USERNAME= DOCKERHUB_PULL_PASSWORD= -DOCKERHUB_PULL_EMAIL= \ No newline at end of file +DOCKERHUB_PULL_EMAIL= +OPENSRS_KEY=95e4dc58cafc3623f8188d7f1aecbb2259cff4b003b96cfb4ac93d25b5f96e6749c6febfb838fd56e1bcd1026635c0c38e9f40bef0e39585 +OPENSRS_USERNAME=eldadfux \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3151de5adb..d046f94474 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ debug/ app/sdks dev/yasd_init.php .phpunit.result.cache +Makefile \ No newline at end of file diff --git a/app/config/services.php b/app/config/services.php index e0d5e263f2..e8bc3372e2 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -108,6 +108,19 @@ return [ 'optional' => false, 'icon' => '', ], + 'domains' => [ + 'key' => 'domains', + 'name' => 'Domains', + 'subtitle' => 'The Domain service allows you to manage domains in Appwrite server.', + 'description' => '', + 'controller' => 'api/domains.php', + 'sdk' => true, + 'docs' => true, + 'docsUrl' => '', + 'tests' => false, + 'optional' => false, + 'icon' => '', + ], 'storage' => [ 'key' => 'storage', 'name' => 'Storage', diff --git a/app/controllers/api/domains.php b/app/controllers/api/domains.php index 43f34569a5..64820777e4 100644 --- a/app/controllers/api/domains.php +++ b/app/controllers/api/domains.php @@ -42,14 +42,10 @@ App::post('/v1/domains/suggest') ->inject('registrar') ->action(function (string $domain, $response, $registrar) { - $suggestions = $registrar->suggest($domain); - $domains = []; + $domain = new Domain($domain); + $suggestions = $registrar->suggest([$domain->getName()], [$domain->getTLD()]); - foreach($suggestions as $k=>$_v) { - $domains[] = new Domain($k); - } - - $response->dynamic(["domains" => $domains], Response::MODEL_DOMAIN_LIST); + $response->dynamic(new Document(["domains" => $suggestions]), Response::MODEL_DOMAIN_LIST); }); App::post('/v1/domains/available') @@ -68,11 +64,11 @@ App::post('/v1/domains/available') ->action(function (string $domain, $response, $registrar) { $domain = [ - "domain" => new Domain($domain), + "domain" => $domain, "available" => $registrar->available($domain) ]; - $response->dynamic(["domain" => $domain], Response::MODEL_DOMAIN); + $response->dynamic(new Document(["domain" => $domain]), Response::MODEL_DOMAIN); }); App::post('/v1/domains') @@ -99,7 +95,7 @@ App::post('/v1/domains') ) { if($registrar->available($domain)) { - throw new Exception(); + throw new Exception(Exception::DOMAIN_ALREADY_EXISTS); } $project = $dbForConsole->getDocument('projects', $projectId); @@ -392,7 +388,7 @@ App::post('/v1/domains/transfer/in') App::post('/v1/domains/transfer/out') ->desc("Start transfer process for domain and generate code for transfer to 3rd party registrar") ->groups(['api', 'domains']) - ->label('scope', 'domains.write') + ->label('scope', 'projects.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'transferOut') ->label('sdk.method', 'create') @@ -408,7 +404,7 @@ App::post('/v1/domains/transfer/out') App::get('/v1/domains') ->desc("List domains") ->groups(['api', 'domains']) - ->label('scope', 'domains.read') + ->label('scope', 'projects.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'domains') ->label('sdk.method', 'list') @@ -440,7 +436,7 @@ App::get('/v1/domains') App::get('/v1/domains/:domainId') ->desc("Get domain") ->groups(['api', 'domains']) - ->label('scope', 'domains.read') + ->label('scope', 'projects.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'domains') ->label('sdk.method', 'list') @@ -474,7 +470,7 @@ App::get('/v1/domains/:domainId') App::patch('/v1/domains/:domainId/nameservers') ->desc("Check namserver records and update them if needed") ->groups(['api', 'domains']) - ->label('scope', 'domains.write') + ->label('scope', 'projects.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'domains') ->label('sdk.method', 'updateNameservers') @@ -491,7 +487,7 @@ App::patch('/v1/domains/:domainId/nameservers') App::patch('/v1/domains/:domainId/project') ->desc("Move domain to a different project") ->groups(['api', 'domains']) - ->label('scope', 'domains.write') + ->label('scope', 'projects.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'domains') ->label('sdk.method', 'updateProject') diff --git a/app/init.php b/app/init.php index abf79ba173..86f2a2d901 100644 --- a/app/init.php +++ b/app/init.php @@ -744,13 +744,13 @@ App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en'))) App::setResource('registrar', function(){ $opensrs = new OpenSRS( - 'apikey', - 'apisecret', - 'username', - 'password', + App::getEnv('OPENSRS_KEY'), + App::getEnv('OPENSRS_USERNAME'), + 'appwrite', + '0p3n5R5@Appwrite', [ - 'ns1.nameserver.com', - 'ns2.nameserver.com', + 'ns1.appwrite.io', + 'ns2.appwrite.io', ] ); diff --git a/docker-compose.yml b/docker-compose.yml index 8ba1ff0566..71fbbabce6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -176,6 +176,8 @@ services: - _APP_GRAPHQL_MAX_BATCH_SIZE - _APP_GRAPHQL_MAX_COMPLEXITY - _APP_GRAPHQL_MAX_DEPTH + - OPENSRS_KEY + - OPENSRS_USERNAME appwrite-realtime: entrypoint: realtime diff --git a/phpunit.xml b/phpunit.xml index 5b4bcdb99c..a448fcc8c7 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,7 +6,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false" + stopOnFailure="true" > diff --git a/tests/e2e/Services/Domains/DomainsBase.php b/tests/e2e/Services/Domains/DomainsBase.php new file mode 100644 index 0000000000..79a1cd9d0f --- /dev/null +++ b/tests/e2e/Services/Domains/DomainsBase.php @@ -0,0 +1,9 @@ +client->call(Client::METHOD_POST, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'teamId' => ID::unique(), + 'name' => 'Project Test', + ]); + + $this->assertEquals(201, $team['headers']['status-code']); + $this->assertEquals('Project Test', $team['body']['name']); + $this->assertNotEmpty($team['body']['$id']); + + $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => ID::unique(), + 'name' => 'Project Test', + 'teamId' => $team['body']['$id'], + 'region' => 'default', + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertEquals('Project Test', $response['body']['name']); + $this->assertEquals($team['body']['$id'], $response['body']['teamId']); + $this->assertArrayHasKey('platforms', $response['body']); + $this->assertArrayHasKey('webhooks', $response['body']); + $this->assertArrayHasKey('keys', $response['body']); + + $projectId = $response['body']['$id']; + + $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => ID::unique(), + 'name' => 'Project Test', + 'teamId' => $team['body']['$id'], + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertEquals('Project Test', $response['body']['name']); + $this->assertEquals($team['body']['$id'], $response['body']['teamId']); + $this->assertArrayHasKey('platforms', $response['body']); + $this->assertArrayHasKey('webhooks', $response['body']); + $this->assertArrayHasKey('keys', $response['body']); + + return ['projectId' => $projectId]; + } + + /** + * @depends testCreateProject + */ + public function testSuggestDomain($data): void + { + $id = $data['projectId'] ?? ''; + + $response = $this->client->call(Client::METHOD_POST, '/domains/suggest', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => $id, + 'domain' => 'kittens.com', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['domains']); + } + + /** + * @depends testCreateProject + */ + public function testAvailableDomain($data): void + { + $id = $data['projectId'] ?? ''; + + $response = $this->client->call(Client::METHOD_POST, '/domains/available', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => $id, + 'domain' => 'google.com', + ]); + + $available = $response['body']['domain']['available']; + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['domain']); + $this->assertFalse($available); + } + + /** + * @depends testCreateProject + */ + public function testCreate3rdPartyDomain($data): array + { + $id = $data['projectId'] ?? ''; + + $response = $this->client->call(Client::METHOD_POST, '/domains', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => $id, + 'domain' => 'example.com', + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertEquals('example.com', $response['body']['domain']); + $this->assertEquals('com', $response['body']['tld']); + $this->assertEquals('example.com', $response['body']['registerable']); + $this->assertEquals(false, $response['body']['verification']); + + + /** + * Test for FAILURE + */ + $response = $response = $this->client->call(Client::METHOD_POST, '/domains', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => $id, + 'domain' => 'sdkljgfhsdflkjghsdflkgjsh.com', + ]); + + $this->assertEquals(409, $response['headers']['status-code']); + + $response = $response = $this->client->call(Client::METHOD_POST, '/domains', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'type' => 'web', + 'name' => 'Too Long Hostname', + 'key' => '', + 'store' => '', + 'hostname' => \str_repeat("bestdomain", 25) . '.com' // 250 + 4 chars total (exactly above limit) + ]); + + return []; + } + + /** + * @depends testCreateProject + */ + // public function testPurchaseDomain($data): void + // { + // $id = $data['projectId'] ?? ''; + + + // $response = $this->client->call(Client::METHOD_POST, '/domains/purchase', array_merge([ + // 'content-type' => 'application/json', + // 'x-appwrite-project' => $this->getProject()['$id'], + // ], $this->getHeaders()), [ + // 'projectId' => $id, + // 'domain' => 'dfksljgh24rlkgjhvlsdfkjgbhl.org', + // 'firstname' => 'firstname', + // 'lastname' => 'lastname', + // 'phone' => '+18037889693', + // 'email' => 'email@email.com', + // 'address1' => 'address1 st', + // 'address2' => 'unit address2', + // 'address3' => 'apt. address3', + // 'city' => 'city', + // 'state' => 'state', + // 'country' => 'us', + // 'postalcode' => '29223', + // 'org' => 'myorg', + // ]); + + + + // $this->assertEquals(200, $response['headers']['status-code']); + // $this->assertNotEmpty($response['body']); + // $this->assertTrue($response['body']) + // } + +} \ No newline at end of file