# Example code

The code for dns integrations can be found in:

```
app/Framework/Core/Hosting/Ipam\DnsProvider
```

For each dns provider, you have a php class, for example the cloudflare.php. To get started with a new dns provider, you can just copy one and remove the code.&#x20;

## Example (cloudflare)

```php
<?php

namespace App\Framework\Core\Hosting\Ipam\DnsProvider;

use App\Framework\Core\Hosting\Domain\DnsRecordItem;
use App\Framework\Core\Hosting\Ipam\DnsProvider\Responses\ZoneDetails;
use App\Framework\Core\Hosting\Ipam\Models\IpamRdnsHost;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Psr7\Request;
use Illuminate\Support\Facades\Cache;

class cloudflare extends AbstractDnsProvider implements DnsProviderInterface {
	/**
	 * @var Client
	 */
	private $guzzleClient;

	public array $availableTypes = [
		"A" => "A",
		"AAAA" => "AAAA",
		"CNAME" => "CNAME",
		"MX" => "MX",
		"DKIM" => "DKIM",
		"SPF" => "SPF",
		"DMARC" => "DMARC",
		"TXT" => "TXT",
		"CAA" => "CAA",
		"SRV" => "SRV",
		"SVCB" => "SVCB",
		"HTTPS" => "HTTPS",
		"PTR" => "PTR",
		"NS" => "NS",
	];

	public function createZone(IpamRdnsHost $ipamRdnsHost, string $zoneName, ?array $nameservers = null): ZoneDetails {
		try {
			$response = $this->_sendRequest($ipamRdnsHost, "zones", "POST", [
				"name" => $this->getZoneName($zoneName, $ipamRdnsHost, false),
				"type" => "full",
			]);

			return new ZoneDetails(
				$response->result->id,
				$response->result->name,
				null,
				$response->result->name_servers
			);
		} catch (ClientException $e) {
			throw new Exception($this->_getErrorMessage($e));
		}
	}

	public function getAllZones(IpamRdnsHost $ipamRdnsHost): array {
		$return = [];

		try {
			$zoneResponse = $this->_sendRequest($ipamRdnsHost, "zones?per_page=50");
		} catch (ClientException $e) {
			throw new Exception($this->_getErrorMessage($e));
		}

		foreach ($zoneResponse->result as $zone) {
			$return[] = new ZoneDetails(
				$zone->id,
				$zone->name,
				null,
				$zone->name_servers
			);
		}

        Cache::put("cfa", $zoneResponse->result[0]?->account?->id, 3600);

		return $return;
	}

	public function deleteZone(IpamRdnsHost $ipamRdnsHost, string $zoneName): bool {
		$zoneName = $this->getZoneName($zoneName, $ipamRdnsHost);
//		try {
//			$this->_sendRequest($ipamRdnsHost, "servers/localhost/zones/{$zoneName}", "DELETE");
//
//			return true;
//		} catch (ClientException $e) {
//			throw new Exception($e->getResponse()->getBody());
//		}
	}

	public function getZoneDetails(IpamRdnsHost $ipamRdnsHost, string $zoneName): ZoneDetails {
		$dnsRecords = [];
		$zoneName = $this->getZoneName($zoneName, $ipamRdnsHost);

		try {
			$zoneResponse = $this->_sendRequest($ipamRdnsHost, "zones/{$zoneName}");
			$recordsResponse = $this->_sendRequest($ipamRdnsHost, "zones/{$zoneName}/dns_records");
		} catch (ClientException $e) {
			throw new Exception($this->_getErrorMessage($e));
		}

		foreach ($recordsResponse->result as $record) {
			$dnsRecords[] = new DnsRecordItem(
				$record->id,
				$record->type,
				$record->name,
				$record->content,
				$record->ttl,
			);
		}

		return new ZoneDetails(
			$zoneResponse->result->id,
			$zoneResponse->result->name,
			null,
			$zoneResponse->result->name_servers,
			$dnsRecords
		);
	}

	public function createDnsRecord(IpamRdnsHost $ipamRdnsHost, string $zoneName, DnsRecordItem $dnsRecord) {
		$zoneName = $this->getZoneName($zoneName, $ipamRdnsHost);

		try {
			$response = $this->_sendRequest($ipamRdnsHost, "zones/{$zoneName}/dns_records", "POST", [
				"content" => $dnsRecord->content,
				"name" => $dnsRecord->hostname,
				"type" => $dnsRecord->type,
				"ttl" => $dnsRecord->ttl,
			]);

			return $response->result->id;
		} catch (ClientException $e) {
			throw new Exception($this->_getErrorMessage($e));
		}

	}

	public function deleteDnsRecord(IpamRdnsHost $ipamRdnsHost, string $zoneName, DnsRecordItem $dnsRecord) {
		$zoneName = $this->getZoneName($zoneName, $ipamRdnsHost);

		try {
			$this->_sendRequest($ipamRdnsHost, "zones/{$zoneName}/dns_records/{$dnsRecord->id}", "DELETE");
		} catch (ClientException $e) {
			throw new Exception($this->_getErrorMessage($e));
		}

	}

	public function updateDnsRecord(IpamRdnsHost $ipamRdnsHost, string $zoneName, DnsRecordItem $originalDnsRecord, DnsRecordItem $updatedDnsRecord) {
		$zoneName = $this->getZoneName($zoneName, $ipamRdnsHost);

		try {
			$this->_sendRequest($ipamRdnsHost, "zones/{$zoneName}/dns_records/{$originalDnsRecord->id}", "PUT", [
				"content" => $updatedDnsRecord->content,
				"name" => $updatedDnsRecord->hostname,
				"type" => $updatedDnsRecord->type,
				"ttl" => $updatedDnsRecord->ttl,
			]);
		} catch (ClientException $e) {
			throw new Exception($this->_getErrorMessage($e));
		}

	}

	private function _sendRequest(IpamRdnsHost $ipamRdnsHost, string $url, string $method = "GET", array $data = []) {
		$request = new Request($method, $url, [], json_encode($data));

		$res = $this->_getClient($ipamRdnsHost)->sendAsync($request)->wait();

		return json_decode($res->getBody()->getContents());
	}

	private function _getClient(IpamRdnsHost $ipamRdnsHost) {

		if ($this->guzzleClient === null) {
			$this->guzzleClient = new Client([
				'verify' => false,
				'base_uri' => "https://api.cloudflare.com/client/v4/",
				'headers' => [
					'Content-Type' => 'application/json',
					'Authorization' => 'Bearer ' . $ipamRdnsHost->password,
				]
			]);
		}

		return $this->guzzleClient;
	}

	public function getZoneDetailUrl(IpamRdnsHost $ipamRdnsHost, string $zoneName) {
        $accountId = Cache::get("cfa", "n-a");

		return "https://dash.cloudflare.com/{$accountId}/{$zoneName}";
	}

	private function _getErrorMessage(Exception $e): string {
		$content = json_decode((string)$e->getResponse()->getBody());

		if ($content->success === false) {
			return implode(", ", array_column($content->errors, "message"));
		}

		return "Successful response.";
	}

	public function getZoneName($zoneName, IpamRdnsHost $rdnsHost, $searchId = true) {
		if(str_ends_with($zoneName, ".")) {
			$zoneName = trim($zoneName, ".");
		}

		/**
		 * For rdns, search the zone and return the ID
		 */
		if(str_contains($zoneName, "in-addr.arpa") && $searchId === true) {
			try {
				$response = $this->_sendRequest($rdnsHost, "zones?name={$zoneName}", "GET");

				if(isset($response->result[0])) {
					$zoneName = $response->result[0]->id;
				}
			} catch (Exception $e) {

			}
		}

		return $zoneName;
	}
}

```
