diff --git a/src/Domains/Registrar.php b/src/Domains/Registrar.php index 58cbf58..8ee7ab8 100644 --- a/src/Domains/Registrar.php +++ b/src/Domains/Registrar.php @@ -6,6 +6,7 @@ use Utopia\Domains\Registrar\Domain; use Utopia\Domains\Registrar\Renewal; use Utopia\Domains\Registrar\Contact; +use Utopia\Domains\Registrar\Price; use Utopia\Domains\Registrar\TransferStatus; use Utopia\Domains\Registrar\UpdateDetails; @@ -154,9 +155,9 @@ public function updateNameservers(string $domain, array $nameservers): array * @param int $periodYears * @param string $regType * @param int $ttl - * @return float + * @return Price */ - public function getPrice(string $domain, int $periodYears = 1, string $regType = self::REG_TYPE_NEW, int $ttl = 3600): float + public function getPrice(string $domain, int $periodYears = 1, string $regType = self::REG_TYPE_NEW, int $ttl = 3600): Price { return $this->adapter->getPrice($domain, $periodYears, $regType, $ttl); } @@ -178,13 +179,12 @@ public function renew(string $domain, int $periodYears): Renewal * * @param string $domain * @param string $authCode - * @param array|Contact $contacts - * @param array $nameservers + * @param float|null $purchasePrice Required if domain is premium * @return string Order ID */ - public function transfer(string $domain, string $authCode, array|Contact $contacts, int $periodYears = 1, array $nameservers = []): string + public function transfer(string $domain, string $authCode, ?float $purchasePrice = null): string { - return $this->adapter->transfer($domain, $authCode, $contacts, $periodYears, $nameservers); + return $this->adapter->transfer($domain, $authCode, $purchasePrice); } /** diff --git a/src/Domains/Registrar/Adapter.php b/src/Domains/Registrar/Adapter.php index f18beb2..08fe0c7 100644 --- a/src/Domains/Registrar/Adapter.php +++ b/src/Domains/Registrar/Adapter.php @@ -155,9 +155,9 @@ public function updateNameservers(string $domain, array $nameservers): array * @param int $periodYears * @param string $regType * @param int $ttl - * @return float + * @return Price */ - abstract public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): float; + abstract public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): Price; /** * Renew a domain @@ -173,12 +173,10 @@ abstract public function renew(string $domain, int $periodYears): Renewal; * * @param string $domain * @param string $authCode - * @param array|Contact $contacts - * @param int $periodYears - * @param array $nameservers + * @param float|null $purchasePrice Required if domain is premium * @return string Order ID */ - abstract public function transfer(string $domain, string $authCode, array|Contact $contacts, int $periodYears = 1, array $nameservers = []): string; + abstract public function transfer(string $domain, string $authCode, ?float $purchasePrice = null): string; /** * Get the authorization code for an EPP domain diff --git a/src/Domains/Registrar/Adapter/Mock.php b/src/Domains/Registrar/Adapter/Mock.php index 6dae736..47149b4 100644 --- a/src/Domains/Registrar/Adapter/Mock.php +++ b/src/Domains/Registrar/Adapter/Mock.php @@ -14,6 +14,7 @@ use Utopia\Domains\Registrar\Adapter; use Utopia\Domains\Registrar\TransferStatusEnum; use Utopia\Domains\Registrar; +use Utopia\Domains\Registrar\Price; use Utopia\Domains\Registrar\UpdateDetails; class Mock extends Adapter @@ -254,24 +255,25 @@ public function getDomain(string $domain): Domain * @param int $periodYears * @param string $regType * @param int $ttl Time to live for the cache (if set) in seconds - * @return float + * @return Price * @throws PriceNotFoundException */ - public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): float + public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): Price { if ($this->cache) { $cached = $this->cache->load($domain, $ttl); - if ($cached !== null && is_array($cached)) { - return $cached['price']; + if (is_array($cached) && isset($cached['price'])) { + return new Price($cached['price'], $cached['premium'] ?? false); } } - if (isset($this->premiumDomains[$domain])) { - $result = $this->premiumDomains[$domain] * $periodYears; + $isPremium = isset($this->premiumDomains[$domain]); + + if ($isPremium) { + $price = $this->premiumDomains[$domain] * $periodYears; + $result = new Price($price, true); if ($this->cache) { - $this->cache->save($domain, [ - 'price' => $result, - ]); + $this->cache->save($domain, ['price' => $result->price, 'premium' => $result->premium]); } return $result; @@ -296,11 +298,10 @@ public function getPrice(string $domain, int $periodYears = 1, string $regType = default => 1.0, }; - $result = $basePrice * $periodYears * $multiplier; + $price = $basePrice * $periodYears * $multiplier; + $result = new Price($price, false); if ($this->cache) { - $this->cache->save($domain, [ - 'price' => $result, - ]); + $this->cache->save($domain, ['price' => $result->price, 'premium' => $result->premium]); } return $result; @@ -356,21 +357,16 @@ public function updateDomain(string $domain, UpdateDetails $details): bool * * @param string $domain * @param string $authCode - * @param array|Contact $contacts - * @param int $periodYears - * @param array $nameservers + * @param float|null $purchasePrice Required if domain is premium * @return string Order ID * @throws DomainTakenException - * @throws InvalidContactException */ - public function transfer(string $domain, string $authCode, array|Contact $contacts, int $periodYears = 1, array $nameservers = []): string + public function transfer(string $domain, string $authCode, ?float $purchasePrice = null): string { if (in_array($domain, $this->purchasedDomains)) { throw new DomainTakenException("Domain {$domain} is already in this account", self::RESPONSE_CODE_DOMAIN_TAKEN); } - $this->validateContacts($contacts); - $this->transferredDomains[] = $domain; $this->purchasedDomains[] = $domain; diff --git a/src/Domains/Registrar/Adapter/NameCom.php b/src/Domains/Registrar/Adapter/NameCom.php index 530ee63..765855b 100644 --- a/src/Domains/Registrar/Adapter/NameCom.php +++ b/src/Domains/Registrar/Adapter/NameCom.php @@ -7,11 +7,12 @@ use Utopia\Domains\Registrar\Contact; use Utopia\Domains\Exception as DomainsException; use Utopia\Domains\Registrar\Exception\DomainTakenException; -use Utopia\Domains\Registrar\Exception\DomainNotTransferableException; +use Utopia\Domains\Registrar\Exception\InvalidAuthCodeException; use Utopia\Domains\Registrar\Exception\InvalidContactException; use Utopia\Domains\Registrar\Exception\AuthException; use Utopia\Domains\Registrar\Exception\PriceNotFoundException; use Utopia\Domains\Registrar\Exception\DomainNotFoundException; +use Utopia\Domains\Registrar\Exception\UnsupportedTldException; use Utopia\Domains\Registrar\Adapter; use Utopia\Domains\Registrar\Renewal; use Utopia\Domains\Registrar\TransferStatus; @@ -19,17 +20,39 @@ use Utopia\Domains\Registrar\TransferStatusEnum; use Utopia\Domains\Registrar\UpdateDetails; use Utopia\Domains\Registrar; +use Utopia\Domains\Registrar\Price; class NameCom extends Adapter { /** - * Name.com API Error Messages + * Name.com API Error Keys */ - public const ERROR_MESSAGE_NOT_FOUND = 'Not Found'; - public const ERROR_MESSAGE_DOMAIN_TAKEN = 'Domain is not available'; - public const ERROR_MESSAGE_DOMAIN_NOT_TRANSFERABLE = 'we were unable to get authoritative domain information from the registry. this usually means that the domain name or auth code provided was not correct.'; - public const ERROR_MESSAGE_INVALID_CONTACT = 'invalid value for $country when calling'; - public const ERROR_MESSAGE_INVALID_DOMAIN = 'Invalid Domain Name'; + public const ERROR_NOT_FOUND = 'Not Found'; + public const ERROR_DOMAIN_TAKEN = 'Domain is not available'; + public const ERROR_INVALID_AUTH_CODE = 'we were unable to get authoritative domain information from the registry. this usually means that the domain name or auth code provided was not correct.'; + public const ERROR_INVALID_CONTACT = 'invalid value for'; + public const ERROR_INVALID_DOMAIN = 'Invalid Domain Name'; + public const ERROR_INVALID_DOMAINS = 'None of the submitted domains are valid'; + public const ERROR_UNSUPPORTED_TLD = 'unsupported tld'; + public const ERROR_TLD_NOT_SUPPORTED = 'TLD not supported'; + public const ERROR_UNSUPPORTED_TRANSFER = 'do not support transfers for'; + public const ERROR_UNAUTHORIZED = 'Unauthorized'; + + /** + * Name.com API Error Map: [message => code] + */ + public const ERROR_MAP = [ + self::ERROR_NOT_FOUND => 404, + self::ERROR_DOMAIN_TAKEN => null, + self::ERROR_INVALID_AUTH_CODE => null, + self::ERROR_INVALID_CONTACT => null, + self::ERROR_INVALID_DOMAIN => null, + self::ERROR_INVALID_DOMAINS => null, + self::ERROR_UNSUPPORTED_TLD => 422, + self::ERROR_TLD_NOT_SUPPORTED => null, + self::ERROR_UNSUPPORTED_TRANSFER => 400, + self::ERROR_UNAUTHORIZED => 401, + ]; /** * Contact Types @@ -89,9 +112,18 @@ public function getName(): string */ public function available(string $domain): bool { - $result = $this->send('POST', '/core/v1/domains:checkAvailability', [ - 'domainNames' => [$domain], - ]); + try { + $result = $this->send('POST', '/core/v1/domains:checkAvailability', [ + 'domainNames' => [$domain], + ]); + } catch (Exception $e) { + switch ($this->matchError($e)) { + case self::ERROR_INVALID_DOMAINS: + return false; + default: + throw $e; + } + } return $result['results'][0]['purchasable'] ?? false; } @@ -151,21 +183,27 @@ public function purchase(string $domain, array|Contact $contacts, int $periodYea $result = $this->send('POST', '/core/v1/domains', $data); return (string) ($result['order'] ?? ''); - } catch (AuthException $e) { - throw $e; - } catch (Exception $e) { $message = 'Failed to purchase domain: ' . $e->getMessage(); $code = $e->getCode(); - $errorLower = strtolower($e->getMessage()); - if (str_contains($errorLower, strtolower(self::ERROR_MESSAGE_DOMAIN_TAKEN))) { - throw new DomainTakenException($message, $e->getCode(), $e); - } - if (str_contains($errorLower, strtolower(self::ERROR_MESSAGE_INVALID_CONTACT))) { - throw new InvalidContactException($message, $e->getCode(), $e); + switch ($this->matchError($e)) { + case self::ERROR_UNAUTHORIZED: + throw new AuthException($message, $code, $e); + + case self::ERROR_DOMAIN_TAKEN: + throw new DomainTakenException($message, $code, $e); + + case self::ERROR_INVALID_CONTACT: + throw new InvalidContactException($message, $code, $e); + + case self::ERROR_UNSUPPORTED_TLD: + case self::ERROR_UNSUPPORTED_TRANSFER: + throw new UnsupportedTldException($message, $code, $e); + + default: + throw new DomainsException($message, $code, $e); } - throw new DomainsException($message, $code, $e); } } @@ -174,55 +212,45 @@ public function purchase(string $domain, array|Contact $contacts, int $periodYea * * @param string $domain The domain name to transfer * @param string $authCode Authorization code for the transfer - * @param array|Contact $contacts Contact information - * @param int $periodYears Transfer period in years - * @param array $nameservers Nameservers to use + * @param float|null $purchasePrice Required if domain is premium * @return string Order ID */ - public function transfer(string $domain, string $authCode, array|Contact $contacts, int $periodYears = 1, array $nameservers = []): string + public function transfer(string $domain, string $authCode, ?float $purchasePrice = null): string { try { - $contacts = is_array($contacts) ? $contacts : [$contacts]; - $nameservers = empty($nameservers) ? $this->defaultNameservers : $nameservers; - - $contactData = $this->sanitizeContacts($contacts); - $data = [ 'domainName' => $domain, 'authCode' => $authCode, - 'years' => $periodYears, - 'contacts' => $contactData, ]; - if (!empty($nameservers)) { - $data['nameservers'] = $nameservers; + if ($purchasePrice !== null) { + $data['purchasePrice'] = $purchasePrice; } $result = $this->send('POST', '/core/v1/transfers', $data); return (string) ($result['order'] ?? ''); - } catch (AuthException $e) { - throw $e; - } catch (Exception $e) { $message = 'Failed to transfer domain: ' . $e->getMessage(); $code = $e->getCode(); - $errorLower = strtolower($e->getMessage()); - if ($code === 422 || - str_contains($errorLower, strtolower(self::ERROR_MESSAGE_INVALID_CONTACT)) - ) { - throw new InvalidContactException($message, $e->getCode(), $e); - } - if ($code === 409 || - str_contains($errorLower, strtolower(self::ERROR_MESSAGE_DOMAIN_NOT_TRANSFERABLE)) - ) { - throw new DomainNotTransferableException($message, $code, $e); - } - if (str_contains($errorLower, strtolower(self::ERROR_MESSAGE_DOMAIN_TAKEN))) { - throw new DomainTakenException($message, $e->getCode(), $e); + switch ($this->matchError($e)) { + case self::ERROR_UNAUTHORIZED: + throw new AuthException($message, $code, $e); + + case self::ERROR_UNSUPPORTED_TLD: + case self::ERROR_UNSUPPORTED_TRANSFER: + throw new UnsupportedTldException($message, $code, $e); + + case self::ERROR_INVALID_AUTH_CODE: + throw new InvalidAuthCodeException($message, $code, $e); + + case self::ERROR_DOMAIN_TAKEN: + throw new DomainTakenException($message, $code, $e); + + default: + throw new DomainsException($message, $code, $e); } - throw new DomainsException($message, $code, $e); } } @@ -320,59 +348,75 @@ public function suggest(array|string $query, array $tlds = [], int|null $limit = * @param int $periodYears Registration period in years * @param string $regType Type of registration * @param int $ttl Time to live for the cache - * @return float The price of the domain + * @return Price The price and premium status of the domain */ - public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): float + public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): Price { if ($this->cache) { $cacheKey = $domain . '_' . $periodYears; $cached = $this->cache->load($cacheKey, $ttl); - if ($cached !== null && is_array($cached) && isset($cached[$regType])) { - return (float) $cached[$regType]; + if (is_array($cached) && isset($cached[$regType]) && is_array($cached[$regType])) { + return new Price($cached[$regType]['price'], $cached[$regType]['premium']); } } try { $result = $this->send('GET', '/core/v1/domains/' . $domain . ':getPricing' . '?years=' . $periodYears); - $purchasePrice = (float) ($result['purchasePrice'] ?? 0); - $renewalPrice = (float) ($result['renewalPrice'] ?? 0); - $transferPrice = (float) ($result['transferPrice'] ?? 0); + $purchasePrice = isset($result['purchasePrice']) ? (float) $result['purchasePrice'] : null; + $renewalPrice = isset($result['renewalPrice']) ? (float) $result['renewalPrice'] : null; + $transferPrice = isset($result['transferPrice']) ? (float) $result['transferPrice'] : null; + $isPremium = isset($result['premium']) && $result['premium'] === true; + + if ($purchasePrice === null && $renewalPrice === null && $transferPrice === null) { + throw new PriceNotFoundException('Price not found for domain: ' . $domain, 400); + } if ($this->cache) { $cacheKey = $domain . '_' . $periodYears; $this->cache->save($cacheKey, [ - Registrar::REG_TYPE_NEW => $purchasePrice, - Registrar::REG_TYPE_RENEWAL => $renewalPrice, - Registrar::REG_TYPE_TRANSFER => $transferPrice, + Registrar::REG_TYPE_NEW => ['price' => $purchasePrice ?? 0, 'premium' => $isPremium], + Registrar::REG_TYPE_RENEWAL => ['price' => $renewalPrice ?? 0, 'premium' => $isPremium], + Registrar::REG_TYPE_TRANSFER => ['price' => $transferPrice ?? 0, 'premium' => $isPremium], ]); } switch ($regType) { case Registrar::REG_TYPE_NEW: - return $purchasePrice; + if ($purchasePrice === null) { + throw new PriceNotFoundException('Purchase price not found for domain: ' . $domain, 400); + } + return new Price($purchasePrice, $isPremium); case Registrar::REG_TYPE_RENEWAL: - return $renewalPrice; + if ($renewalPrice === null) { + throw new PriceNotFoundException('Renewal price not found for domain: ' . $domain, 400); + } + return new Price($renewalPrice, $isPremium); case Registrar::REG_TYPE_TRANSFER: - return $transferPrice; + if ($transferPrice === null) { + throw new PriceNotFoundException('Transfer price not found for domain: ' . $domain, 400); + } + return new Price($transferPrice, $isPremium); + default: + throw new PriceNotFoundException('Price not found for domain: ' . $domain, 400); } - throw new PriceNotFoundException('Price not found for domain: ' . $domain, 400); - - } catch (PriceNotFoundException $e) { - throw $e; - } catch (Exception $e) { $message = 'Failed to get price for domain: ' . $domain . ' - ' . $e->getMessage(); - $errorLower = strtolower($e->getMessage()); + $code = $e->getCode(); - if ( - str_contains($errorLower, strtolower(self::ERROR_MESSAGE_NOT_FOUND)) || - str_contains($errorLower, strtolower(self::ERROR_MESSAGE_INVALID_DOMAIN)) - ) { - throw new PriceNotFoundException($message, $e->getCode(), $e); - } + switch (true) { + case $e instanceof PriceNotFoundException: + throw $e; - throw new DomainsException($message, $e->getCode(), $e); + case in_array($this->matchError($e), [self::ERROR_UNSUPPORTED_TLD, self::ERROR_TLD_NOT_SUPPORTED]): + throw new UnsupportedTldException($message, $code, $e); + + case in_array($this->matchError($e), [self::ERROR_NOT_FOUND, self::ERROR_INVALID_DOMAIN]): + throw new PriceNotFoundException($message, $code, $e); + + default: + throw new DomainsException($message, $code, $e); + } } } @@ -623,16 +667,37 @@ private function send(string $method, string $path, ?array $data = null): array $message .= '(' . $details . ')'; } - if ($httpCode === 401 && $message === 'Unauthorized') { - throw new AuthException('Failed to send request to Name.com: ' . $message, $httpCode); - } - throw new Exception($message, $httpCode); } return $response ?? []; } + /** + * Match an exception against the error map. + * Returns the matched error key, or null if no match is found. + * + * @param Exception $e The exception to check + * @return string|null The matched error key from ERROR_MAP, or null + */ + private function matchError(Exception $e): ?string + { + $errorLower = strtolower($e->getMessage()); + $code = $e->getCode(); + + foreach (self::ERROR_MAP as $message => $expectedCode) { + if ($expectedCode !== null && $code !== $expectedCode) { + continue; + } + + if (str_contains($errorLower, strtolower($message))) { + return $message; + } + } + + return null; + } + /** * Sanitize contacts array to Name.com format * diff --git a/src/Domains/Registrar/Adapter/OpenSRS.php b/src/Domains/Registrar/Adapter/OpenSRS.php index 1fcd6fd..f3d7f85 100644 --- a/src/Domains/Registrar/Adapter/OpenSRS.php +++ b/src/Domains/Registrar/Adapter/OpenSRS.php @@ -18,6 +18,7 @@ use Utopia\Domains\Registrar\TransferStatusEnum; use Utopia\Domains\Registrar\UpdateDetails; use Utopia\Domains\Registrar; +use Utopia\Domains\Registrar\Price; class OpenSRS extends Adapter { @@ -136,7 +137,7 @@ public function updateNameservers(string $domain, array $nameservers): array ]; } - private function register(string $domain, string $regType, array $user, array $contacts, array $nameservers = [], int $periodYears = 1, ?string $authCode = null): string + private function register(string $domain, string $regType, array $user, array $contacts, array $nameservers = [], int $periodYears = 1, ?string $authCode = null, ?float $purchasePrice = null): string { $hasNameservers = empty($nameservers) ? 0 : 1; @@ -166,6 +167,10 @@ private function register(string $domain, string $regType, array $user, array $c $message['attributes']['nameserver_list'] = $nameservers; } + if ($purchasePrice !== null) { + $message['attributes']['premium_price_to_display'] = $purchasePrice; + } + $result = $this->send($message); return $result; @@ -205,21 +210,12 @@ public function purchase(string $domain, array|Contact $contacts, int $periodYea } } - public function transfer(string $domain, string $authCode, array|Contact $contacts, int $periodYears = 1, array $nameservers = []): string + public function transfer(string $domain, string $authCode, ?float $purchasePrice = null): string { - $contacts = is_array($contacts) ? $contacts : [$contacts]; - - $nameservers = - empty($nameservers) - ? $this->defaultNameservers - : $nameservers; - - $contacts = $this->sanitizeContacts($contacts); - $regType = Registrar::REG_TYPE_TRANSFER; try { - $result = $this->register($domain, $regType, $this->user, $contacts, $nameservers, $periodYears, $authCode); + $result = $this->register($domain, $regType, $this->user, [], [], 1, $authCode, $purchasePrice); $result = $this->response($result); return $result['id']; @@ -230,9 +226,6 @@ public function transfer(string $domain, string $authCode, array|Contact $contac $reason = $parts[1] ?? $parts[0]; throw new DomainNotTransferableException('Domain is not transferable: ' . $reason, $e->getCode(), $e); } - if ($code === self::RESPONSE_CODE_INVALID_CONTACT) { - throw new InvalidContactException('Failed to transfer domain: ' . $e->getMessage(), $code, $e); - } if ($code === self::RESPONSE_CODE_DOMAIN_TAKEN) { throw new DomainTakenException('Domain is already in this account', $code, $e); } @@ -452,16 +445,16 @@ public function suggest(array|string $query, array $tlds = [], int|null $limit = * @param int $periodYears Registration periodYears in years (default 1) * @param string $regType Type of registration: 'new', 'renewal', 'transfer', or 'trade' * @param int $ttl Time to live for the cache (if set) in seconds (default 3600 seconds = 1 hour) - * @return float The price of the domain + * @return Price The price and premium status of the domain * @throws PriceNotFoundException When pricing information is not found or unavailable for the domain * @throws DomainsException When other errors occur during price retrieval */ - public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): float + public function getPrice(string $domain, int $periodYears = 1, string $regType = Registrar::REG_TYPE_NEW, int $ttl = 3600): Price { if ($this->cache) { $cached = $this->cache->load($domain, $ttl); - if ($cached !== null && is_array($cached)) { - return $cached['price']; + if (is_array($cached) && isset($cached['price'])) { + return new Price($cached['price'], $cached['premium'] ?? false); } } @@ -487,14 +480,12 @@ public function getPrice(string $domain, int $periodYears = 1, string $regType = throw new PriceNotFoundException('Price not found for domain: ' . $domain, self::RESPONSE_CODE_DOMAIN_PRICE_NOT_FOUND); } - $result = $price; + $priceObj = new Price($price, false); if ($this->cache) { - $this->cache->save($domain, [ - 'price' => $result, - ]); + $this->cache->save($domain, ['price' => $priceObj->price, 'premium' => $priceObj->premium]); } - return $result; + return $priceObj; } catch (Exception $e) { $message = 'Failed to get price for domain: ' . $e->getMessage(); diff --git a/src/Domains/Registrar/Exception/InvalidAuthCodeException.php b/src/Domains/Registrar/Exception/InvalidAuthCodeException.php new file mode 100644 index 0000000..74ff590 --- /dev/null +++ b/src/Domains/Registrar/Exception/InvalidAuthCodeException.php @@ -0,0 +1,9 @@ +getRegistrar()->getPrice($domain, 1, Registrar::REG_TYPE_NEW); $this->assertNotNull($result); - $this->assertIsFloat($result); - $this->assertGreaterThan(0, $result); + $this->assertInstanceOf(Price::class, $result); + $this->assertIsFloat($result->price); + $this->assertGreaterThan(0, $result->price); + $this->assertIsBool($result->premium); } public function testGetPriceWithInvalidDomain(): void @@ -237,7 +241,8 @@ public function testGetPriceWithCache(): void $result1 = $registrar->getPrice($domain, 1, Registrar::REG_TYPE_NEW, 3600); $this->assertNotNull($result1); - $this->assertIsFloat($result1); + $this->assertInstanceOf(Price::class, $result1); + $this->assertIsFloat($result1->price); $result2 = $registrar->getPrice($domain, 1, Registrar::REG_TYPE_NEW, 3600); $this->assertEquals($result1, $result2); @@ -248,8 +253,10 @@ public function testGetPriceWithCustomTtl(): void $domain = $this->getPricingTestDomain(); $result = $this->getRegistrarWithCache()->getPrice($domain, 1, Registrar::REG_TYPE_NEW, 7200); - $this->assertIsFloat($result); - $this->assertGreaterThan(0, $result); + $this->assertInstanceOf(Price::class, $result); + $this->assertIsFloat($result->price); + $this->assertGreaterThan(0, $result->price); + $this->assertIsBool($result->premium); } public function testUpdateNameservers(): void @@ -296,12 +303,15 @@ public function testTransfer(): void $domain = $this->generateRandomString() . '.' . $this->getDefaultTld(); try { - $result = $this->getRegistrar()->transfer($domain, 'test-auth-code', $this->getPurchaseContact()); + $result = $this->getRegistrar()->transfer($domain, 'test-auth-code'); $this->assertIsString($result); $this->assertNotEmpty($result); } catch (\Exception $e) { - $this->assertInstanceOf(DomainNotTransferableException::class, $e); + $this->assertTrue( + $e instanceof InvalidAuthCodeException || $e instanceof DomainNotTransferableException, + 'Expected InvalidAuthCodeException or DomainNotTransferableException, got ' . get_class($e) + ); } } diff --git a/tests/Registrar/MockTest.php b/tests/Registrar/MockTest.php index 342c508..ba17e47 100644 --- a/tests/Registrar/MockTest.php +++ b/tests/Registrar/MockTest.php @@ -6,9 +6,7 @@ use Utopia\Cache\Adapter\None as NoneAdapter; use Utopia\Domains\Cache; use Utopia\Domains\Registrar; -use Utopia\Domains\Registrar\Contact; use Utopia\Domains\Registrar\Exception\DomainTakenException; -use Utopia\Domains\Registrar\Exception\InvalidContactException; use Utopia\Domains\Registrar\Adapter\Mock; use Utopia\Domains\Registrar\UpdateDetails; @@ -83,19 +81,6 @@ public function testPurchaseWithNameservers(): void $this->assertNotEmpty($result); } - public function testTransferWithNameservers(): void - { - $domain = 'transferdomain.com'; - $contact = $this->getPurchaseContact(); - $authCode = 'test-auth-code-12345'; - $nameservers = ['ns1.example.com', 'ns2.example.com']; - - $result = $this->registrar->transfer($domain, $authCode, $contact, 1, $nameservers); - - $this->assertIsString($result); - $this->assertNotEmpty($result); - } - public function testTransferAlreadyExists(): void { $domain = 'alreadyexists.com'; @@ -106,30 +91,7 @@ public function testTransferAlreadyExists(): void $this->expectException(DomainTakenException::class); $this->expectExceptionMessage('Domain ' . $domain . ' is already in this account'); - $this->registrar->transfer($domain, $authCode, $contact); - } - - public function testTransferWithInvalidContact(): void - { - $this->expectException(InvalidContactException::class); - $this->expectExceptionMessage('missing required field'); - - $invalidContact = new Contact( - 'John', - 'Doe', - '+1.5551234567', - 'john.doe@example.com', - '123 Main St', - 'Suite 100', - '', - '', // Empty city - 'CA', - 'US', - '94105', - 'Test Inc' - ); - - $this->registrar->transfer('transfer.com', 'auth-code', [$invalidContact]); + $this->registrar->transfer($domain, $authCode); } public function testCheckTransferStatusWithRequestAddress(): void diff --git a/tests/Registrar/NameComTest.php b/tests/Registrar/NameComTest.php index b38a33e..654aee2 100644 --- a/tests/Registrar/NameComTest.php +++ b/tests/Registrar/NameComTest.php @@ -7,6 +7,7 @@ use Utopia\Domains\Cache; use Utopia\Domains\Registrar; use Utopia\Domains\Registrar\Exception\AuthException; +use Utopia\Domains\Registrar\Exception\UnsupportedTldException; use Utopia\Domains\Registrar\Adapter\NameCom; use Utopia\Domains\Registrar\UpdateDetails; @@ -114,7 +115,7 @@ public function testPurchaseWithInvalidCredentials(): void $domain = $this->generateRandomString() . '.com'; $this->expectException(AuthException::class); - $this->expectExceptionMessage("Failed to send request to Name.com: Unauthorized"); + $this->expectExceptionMessage("Failed to purchase domain: Unauthorized"); $registrar->purchase($domain, $this->getPurchaseContact(), 1); } @@ -157,6 +158,22 @@ public function testSuggestWithFilter(): void } } + public function testTransferUnsupportedTldDotIn(): void + { + $domain = $this->generateRandomString() . '.in'; + + $this->expectException(UnsupportedTldException::class); + $this->registrar->transfer($domain, 'test-auth-code'); + } + + public function testTransferUnsupportedTldDotXYZ(): void + { + $domain = $this->generateRandomString() . '.xyz'; + + $this->expectException(UnsupportedTldException::class); + $this->registrar->transfer($domain, 'test-auth-code'); + } + public function testCheckTransferStatus(): void { $this->markTestSkipped('Name.com for some reason always returning 404 (Not Found) for transfer status check. Investigate later.'); diff --git a/tests/Registrar/OpenSRSTest.php b/tests/Registrar/OpenSRSTest.php index 480e9bd..4547f6b 100644 --- a/tests/Registrar/OpenSRSTest.php +++ b/tests/Registrar/OpenSRSTest.php @@ -174,7 +174,7 @@ public function testTransferNotRegistered(): void $domain = $this->generateRandomString() . '.net'; try { - $result = $this->registrar->transfer($domain, 'test-auth-code', $this->getPurchaseContact()); + $result = $this->registrar->transfer($domain, 'test-auth-code'); $this->assertIsString($result); $this->assertNotEmpty($result); } catch (DomainNotTransferableException $e) { @@ -186,7 +186,7 @@ public function testTransferNotRegistered(): void public function testTransferAlreadyExists(): void { try { - $result = $this->registrar->transfer($this->testDomain, 'test-auth-code', $this->getPurchaseContact()); + $result = $this->registrar->transfer($this->testDomain, 'test-auth-code'); $this->assertIsString($result); $this->assertNotEmpty($result); } catch (DomainNotTransferableException $e) {