Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e603353
add srv_target column to cloudflare_domains migration
HarlequinSin Dec 28, 2025
5948e9c
add SRV record and target strings
HarlequinSin Dec 28, 2025
cc76657
add srv_target field to CloudflareDomain model and resource
HarlequinSin Dec 28, 2025
e17c617
add srv_record toggle to SubdomainRelationManager and SubdomainResource
HarlequinSin Dec 28, 2025
2e72466
Adding logic for srv records
HarlequinSin Dec 28, 2025
f20e58e
add error messages for missing SRV target and enhance tooltip logic i…
HarlequinSin Dec 28, 2025
58de843
add zone request status messages and improve logging for missing SRV …
HarlequinSin Dec 28, 2025
2ff7a99
add CloudflareService class for managing DNS records with upsert and …
HarlequinSin Dec 28, 2025
1572187
cleanup
HarlequinSin Dec 28, 2025
eb1a0eb
Remade script to utilize upsert with better error handling
HarlequinSin Dec 28, 2025
6951bc7
Update to CloudflareDomain model to fetch Cloudflare Zone ID with not…
HarlequinSin Dec 28, 2025
f18101a
Changed upsert to require a recordId to be known (prevents changing r…
HarlequinSin Dec 28, 2025
58f73e1
Cleanup
HarlequinSin Dec 28, 2025
89f45b8
Fixing notifications
HarlequinSin Dec 28, 2025
d369cc3
- Fixed issue with create record as SRV
HarlequinSin Dec 28, 2025
7d1b33a
Remove unused Hidden component
HarlequinSin Dec 28, 2025
910b812
- Added default for subdomain selection
HarlequinSin Dec 28, 2025
b42370d
- Fixed erroneous success logic
HarlequinSin Dec 28, 2025
ea4e602
Removed unused classes
HarlequinSin Dec 28, 2025
66d4384
lang support
HarlequinSin Dec 28, 2025
f7b98d3
corrected notification log
HarlequinSin Dec 28, 2025
9804937
Fixed http success logic
HarlequinSin Dec 28, 2025
d004dda
fixed style issues and syntax error
HarlequinSin Dec 28, 2025
a4d9827
fixing blank_line_before_statement
HarlequinSin Dec 28, 2025
c4654fd
append version to 1.1.0
HarlequinSin Dec 28, 2025
348099d
Add notification for missing SRV target in Cloudflare integration
HarlequinSin Dec 29, 2025
d64612d
minor wording updates
HarlequinSin Dec 29, 2025
5bfd8df
Dynamically disable SRV record toggle if domain is missing srv_target
HarlequinSin Dec 29, 2025
e781f6a
lang cleanup, removed redundent strings
HarlequinSin Dec 29, 2025
8a7e932
Make SRV record toggle reactive
HarlequinSin Dec 29, 2025
23c4e39
Fix capitalization in Cloudflare notification titles
HarlequinSin Dec 29, 2025
f31a101
clean up
HarlequinSin Dec 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('cloudflare_domains', function (Blueprint $table) {
$table->string('srv_target')->nullable()->after('cloudflare_id');
});
}

public function down(): void
{
Schema::table('cloudflare_domains', function (Blueprint $table) {
$table->dropColumn('srv_target');
});
}
};
41 changes: 41 additions & 0 deletions subdomains/lang/en/strings.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,47 @@

'name' => 'Name',

'srv_record' => 'SRV Record',
'srv_record_help' => 'Enable this option to create a SRV record instead of an A or AAAA record.',

'srv_target' => 'SRV Target',
'srv_target_help' => 'The hostname that SRV records point to (for example: play.example.com).',

'errors' => [
'srv_target_missing' => 'Cannot enable SRV record because the selected domain does not have an SRV target set.',
],

'api_token' => 'Cloudflare API Token',
'api_token_help' => 'The token needs to have read permissions for Zone.Zone and write for Zone.Dns. For better security you can also set the "Zone Resources" to exclude certain domains and add the panel ip to the "Client IP Adress Filtering".',

'notifications' => [
'cloudflare_missing_zone_title' => 'Cloudflare: Missing Zone ID',
'cloudflare_missing_zone' => 'Cloudflare zone ID is not configured for :domain. Cannot save DNS record for :subdomain.',

'cloudflare_missing_srv_port_title' => 'Cloudflare: Missing SRV Port',
'cloudflare_missing_srv_port' => 'SRV port is missing for :subdomain. Cannot save SRV record.',

'cloudflare_missing_srv_target_title' => 'Cloudflare: Missing SRV Target',
'cloudflare_missing_srv_target' => 'SRV target is missing for :subdomain. Cannot save SRV record.',

'cloudflare_record_updated_title' => 'Cloudflare: Record Updated',
'cloudflare_record_updated' => 'Successfully updated :subdomain record to :record_type',

'cloudflare_missing_ip_title' => 'Cloudflare: Missing IP',
'cloudflare_missing_ip' => 'Server allocation IP is missing or invalid for :subdomain. Cannot save A/AAAA record.',

'cloudflare_upsert_failed_title' => 'Cloudflare: Save Failed',
'cloudflare_upsert_failed' => 'Failed to save record for :subdomain. See logs for details. Errors: :errors',

'cloudflare_delete_success_title' => 'Cloudflare: Record Deleted',
'cloudflare_delete_success' => 'Successfully deleted Cloudflare record for :subdomain.',

'cloudflare_delete_failed_title' => 'Cloudflare: Delete Failed',
'cloudflare_delete_failed' => 'Failed to delete Cloudflare record for :subdomain. See logs for details. Errors: :errors',

'cloudflare_zone_fetch_failed' => 'Failed to fetch Cloudflare Zone ID for domain: :domain',
'cloudflare_domain_saved' => 'Successfully saved domain: :domain',

'settings_saved' => 'Settings saved',
],
];
2 changes: 1 addition & 1 deletion subdomains/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "subdomains",
"name": "Subdomains",
"author": "Boy132",
"version": "1.0.0",
"version": "1.1.0",
"description": "Allows users to create subdomains for their servers",
"category": "plugin",
"url": "https://github.com/pelican-dev/plugins/tree/main/subdomains",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public static function table(Table $table): Table
->columns([
TextColumn::make('name')
->label(trans('subdomains::strings.name')),
TextColumn::make('srv_target')
->label(trans('subdomains::strings.srv_target')),
TextColumn::make('subdomains_count')
->label(trans_choice('subdomains::strings.subdomain', 2))
->counts('subdomains'),
Expand All @@ -77,6 +79,11 @@ public static function form(Schema $schema): Schema
->label(trans('subdomains::strings.name'))
->required()
->unique(),
TextInput::make('srv_target')
->label(trans('subdomains::strings.srv_target'))
->helperText(trans('subdomains::strings.srv_target_help'))
->placeholder('play.example.com')
->rules(['nullable', 'string', 'regex:/^(?=.{1,253}$)(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*$/']),
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ protected function getHeaderActions(): array
{
return [
CreateAction::make()
->createAnother(false),
->createAnother(false)
->successNotification(null),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;
Expand Down Expand Up @@ -83,8 +83,10 @@ public function form(Schema $schema): Schema
->relationship('domain', 'name')
->preload()
->searchable(),
Hidden::make('record_type')
->default(fn () => is_ipv6($this->getOwnerRecord()->allocation->ip) ? 'AAAA' : 'A'),
Toggle::make('srv_record')
->label(trans('subdomains::strings.srv_record'))
->helperText(trans('subdomains::strings.srv_record_help'))
->default(false),
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Facades\Filament;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Enums\IconSize;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ToggleColumn;
use Filament\Tables\Table;

class SubdomainResource extends Resource
Expand Down Expand Up @@ -78,10 +79,16 @@ public static function table(Table $table): Table
TextColumn::make('label')
->label(trans('subdomains::strings.name'))
->state(fn (Subdomain $subdomain) => $subdomain->getLabel()),
ToggleColumn::make('srv_record')
->label(trans('subdomains::strings.srv_record'))
->tooltip(fn (Subdomain $record) => $record->domain && $record->domain->srv_target ? trans('subdomains::strings.srv_record_help') : trans('subdomains::strings.srv_target_missing'))
->disabled(fn (Subdomain $record) => !$record->domain || empty($record->domain->srv_target)),
])
->recordActions([
EditAction::make(),
DeleteAction::make(),
EditAction::make()
->successNotification(null),
DeleteAction::make()
->successNotification(null),
])
->toolbarActions([
CreateAction::make()
Expand All @@ -92,6 +99,7 @@ public static function table(Table $table): Table
->createAnother(false)
->hiddenLabel()
->iconButton()
->successNotification(null)
->iconSize(IconSize::ExtraLarge),
]);
}
Expand All @@ -110,14 +118,14 @@ public static function form(Schema $schema): Schema
->required()
->relationship('domain', 'name')
->preload()
->default(fn () => CloudflareDomain::first()?->id ?? null)
->searchable(),
Hidden::make('record_type')
->default(function () {
/** @var Server $server */
$server = Filament::getTenant();

return is_ipv6($server->allocation->ip) ? 'AAAA' : 'A';
}),
Toggle::make('srv_record')
->label(trans('subdomains::strings.srv_record'))
->helperText(trans('subdomains::strings.srv_record_help'))
->reactive()
->disabled(fn (callable $get) => (empty($get('domain_id')) || empty(CloudflareDomain::find($get('domain_id'))?->srv_target)))
->default(false),
]);
}

Expand Down
41 changes: 22 additions & 19 deletions subdomains/src/Models/CloudflareDomain.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,53 @@

namespace Boy132\Subdomains\Models;

use Boy132\Subdomains\Services\CloudflareService;
use Filament\Notifications\Notification;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Http;

/**
* @property int $id
* @property string $name
* @property ?string $cloudflare_id
* @property ?string $srv_target
*/
class CloudflareDomain extends Model
{
protected $fillable = [
'name',
'cloudflare_id',
'srv_target',
];

protected static function boot(): void
{
parent::boot();

static::created(function (self $model) {
$model->fetchCloudflareId();
$service = new CloudflareService();

$zoneId = $service->getZoneId($model->name);
if (!$zoneId) {
Notification::make()
->title(trans('subdomains::strings.notifications.cloudflare_zone_fetch_failed', ['domain' => $model->name]))
->danger()
->send();
} else {
Notification::make()
->title(trans('subdomains::strings.notifications.cloudflare_domain_saved', ['domain' => $model->name]))
->success()
->send();

$model->update([
'cloudflare_id' => $zoneId,
]);
}
});
}

public function subdomains(): HasMany
{
return $this->hasMany(Subdomain::class, 'domain_id');
}

public function fetchCloudflareId(): void
{
$response = Http::cloudflare()->get('zones', [
'name' => $this->name,
])->json();

if ($response['success']) {
$zones = $response['result'];

if (count($zones) > 0) {
$this->update([
'cloudflare_id' => $zones[0]['id'],
]);
}
}
}
}
Loading