Skip to content

Commit 1b4c30e

Browse files
committed
Add domains and dns management
1 parent e128717 commit 1b4c30e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3231
-1
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace App\Actions\DNSProvider;
4+
5+
use App\DNSProviders\DNSProvider as DNSProviderContract;
6+
use App\Models\DNSProvider;
7+
use App\Models\User;
8+
use Illuminate\Support\Facades\Validator;
9+
use Illuminate\Validation\Rule;
10+
use Illuminate\Validation\ValidationException;
11+
use Throwable;
12+
13+
class CreateDNSProvider
14+
{
15+
public function create(User $user, array $input): DNSProvider
16+
{
17+
$this->validate($input);
18+
19+
$provider = self::getProvider($input['provider']);
20+
21+
try {
22+
$provider->connect($provider->credentialData($input));
23+
} catch (Throwable) {
24+
throw ValidationException::withMessages([
25+
'provider' => [
26+
sprintf("Couldn't connect to %s. Please check your credentials.", $input['provider']),
27+
],
28+
]);
29+
}
30+
31+
$dnsProvider = new DNSProvider;
32+
$dnsProvider->user_id = $user->id;
33+
$dnsProvider->name = $input['name'];
34+
$dnsProvider->provider = $input['provider'];
35+
$dnsProvider->credentials = $provider->credentialData($input);
36+
$dnsProvider->project_id = isset($input['global']) && $input['global'] ? null : $user->currentProject?->id;
37+
$dnsProvider->connected = true;
38+
$dnsProvider->save();
39+
40+
return $dnsProvider;
41+
}
42+
43+
private static function getProvider(string $name): DNSProviderContract
44+
{
45+
$providerClass = config('dns-provider.providers.'.$name.'.handler');
46+
/** @var DNSProviderContract $provider */
47+
$provider = new $providerClass(new DNSProvider);
48+
49+
return $provider;
50+
}
51+
52+
private function validate(array $input): void
53+
{
54+
$rules = [
55+
'name' => [
56+
'required',
57+
],
58+
'provider' => [
59+
'required',
60+
Rule::in(array_keys(config('dns-provider.providers'))),
61+
],
62+
];
63+
64+
Validator::make($input, array_merge($rules, $this->providerRules($input)))->validate();
65+
}
66+
67+
private function providerRules(array $input): array
68+
{
69+
if (! isset($input['provider'])) {
70+
return [];
71+
}
72+
73+
return self::getProvider($input['provider'])->validationRules($input);
74+
}
75+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace App\Actions\DNSProvider;
4+
5+
use App\Models\DNSProvider;
6+
7+
class DeleteDNSProvider
8+
{
9+
public function delete(DNSProvider $dnsProvider): void
10+
{
11+
$dnsProvider->delete();
12+
}
13+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace App\Actions\DNSProvider;
4+
5+
use App\Models\DNSProvider;
6+
use Illuminate\Support\Facades\Validator;
7+
use Illuminate\Validation\ValidationException;
8+
9+
class EditDNSProvider
10+
{
11+
/**
12+
* @param array<string, mixed> $input
13+
*
14+
* @throws ValidationException
15+
*/
16+
public function edit(DNSProvider $dnsProvider, array $input): DNSProvider
17+
{
18+
Validator::make($input, [
19+
'name' => [
20+
'required',
21+
],
22+
])->validate();
23+
24+
$dnsProvider->name = $input['name'];
25+
$dnsProvider->connected = true;
26+
$dnsProvider->save();
27+
28+
return $dnsProvider;
29+
}
30+
}

app/Actions/Domain/AddDomain.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace App\Actions\Domain;
4+
5+
use App\Models\DNSProvider;
6+
use App\Models\Domain;
7+
use App\Models\User;
8+
use Illuminate\Support\Facades\Validator;
9+
use Illuminate\Validation\Rule;
10+
use Illuminate\Validation\ValidationException;
11+
12+
class AddDomain
13+
{
14+
/**
15+
* @param array<string, mixed> $input
16+
*
17+
* @throws ValidationException
18+
*/
19+
public function add(User $user, array $input): Domain
20+
{
21+
$this->validate($input);
22+
23+
$dnsProvider = DNSProvider::findOrFail($input['dns_provider_id']);
24+
25+
$this->authorize($user, $dnsProvider);
26+
27+
$provider = $dnsProvider->provider();
28+
$domainData = $provider->getDomain($input['provider_domain_id']);
29+
30+
if (! $domainData) {
31+
throw ValidationException::withMessages([
32+
'domain' => ['Domain not found in DNS provider.'],
33+
]);
34+
}
35+
36+
$domain = new Domain;
37+
$domain->dns_provider_id = $dnsProvider->id;
38+
$domain->user_id = $user->id;
39+
$domain->domain = $domainData['name'];
40+
$domain->provider_domain_id = $domainData['id'];
41+
$domain->metadata = $domainData;
42+
$domain->save();
43+
44+
$domain->syncDnsRecords();
45+
46+
return $domain;
47+
}
48+
49+
private function validate(array $input): void
50+
{
51+
$rules = [
52+
'dns_provider_id' => [
53+
'required',
54+
'exists:dns_providers,id',
55+
],
56+
'provider_domain_id' => [
57+
'required',
58+
'string',
59+
Rule::unique('domains', 'provider_domain_id')->where(function ($query) use ($input) {
60+
return $query->where('dns_provider_id', $input['dns_provider_id'] ?? null);
61+
}),
62+
],
63+
];
64+
65+
Validator::make($input, $rules)->validate();
66+
}
67+
68+
private function authorize(User $user, DNSProvider $dnsProvider): void
69+
{
70+
if ($user->cannot('view', $dnsProvider)) {
71+
abort(403, 'Unauthorized access to DNS provider.');
72+
}
73+
}
74+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace App\Actions\Domain;
4+
5+
use App\Models\DNSRecord;
6+
use App\Models\Domain;
7+
use Illuminate\Support\Facades\Validator;
8+
use Illuminate\Validation\Rule;
9+
use Illuminate\Validation\ValidationException;
10+
use Throwable;
11+
12+
class CreateDNSRecord
13+
{
14+
/**
15+
* @param array<string, mixed> $input
16+
*
17+
* @throws ValidationException
18+
*/
19+
public function create(Domain $domain, array $input): DNSRecord
20+
{
21+
$this->validate($input);
22+
23+
$provider = $domain->dnsProvider->provider();
24+
25+
try {
26+
$recordData = $provider->createRecord($domain->provider_domain_id, $input);
27+
} catch (Throwable $e) {
28+
throw ValidationException::withMessages([
29+
'record' => [$e->getMessage()],
30+
]);
31+
}
32+
33+
$dnsRecord = new DNSRecord;
34+
$dnsRecord->domain_id = $domain->id;
35+
$dnsRecord->type = $input['type'];
36+
$dnsRecord->name = $input['name'];
37+
$dnsRecord->content = $input['content'];
38+
$dnsRecord->ttl = $input['ttl'] ?? 1;
39+
$dnsRecord->proxied = $input['proxied'] ?? false;
40+
$dnsRecord->provider_record_id = $recordData['id'];
41+
$dnsRecord->metadata = $recordData;
42+
$dnsRecord->save();
43+
44+
return $dnsRecord;
45+
}
46+
47+
private function validate(array $input): void
48+
{
49+
$rules = [
50+
'type' => [
51+
'required',
52+
Rule::in([
53+
'A',
54+
'AAAA',
55+
'CNAME',
56+
'TXT',
57+
'MX',
58+
'SRV',
59+
'NS',
60+
'CAA',
61+
'PTR',
62+
'SOA',
63+
]),
64+
],
65+
'name' => [
66+
'required',
67+
'string',
68+
'max:255',
69+
],
70+
'content' => [
71+
'required',
72+
'string',
73+
],
74+
'ttl' => [
75+
'integer',
76+
'min:1',
77+
'max:86400',
78+
],
79+
'proxied' => [
80+
'boolean',
81+
],
82+
];
83+
84+
Validator::make($input, $rules)->validate();
85+
}
86+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Actions\Domain;
4+
5+
use App\Models\DNSRecord;
6+
use Illuminate\Validation\ValidationException;
7+
use Throwable;
8+
9+
class DeleteDNSRecord
10+
{
11+
/**
12+
* @throws ValidationException
13+
*/
14+
public function delete(DNSRecord $dnsRecord): void
15+
{
16+
$provider = $dnsRecord->domain->dnsProvider->provider();
17+
18+
try {
19+
$provider->deleteRecord(
20+
$dnsRecord->domain->provider_domain_id,
21+
$dnsRecord->provider_record_id
22+
);
23+
} catch (Throwable $e) {
24+
throw ValidationException::withMessages([
25+
'record' => [$e->getMessage()],
26+
]);
27+
}
28+
29+
$dnsRecord->delete();
30+
}
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace App\Actions\Domain;
4+
5+
use App\Models\Domain;
6+
7+
class RemoveDomain
8+
{
9+
public function remove(Domain $domain): void
10+
{
11+
$domain->delete();
12+
}
13+
}

0 commit comments

Comments
 (0)