feat: Add DNS management resources and importer

- Implemented DomainCollection, DomainDetailResource, DomainNSCollection, DomainNSResource, and DomainResource for handling DNS domain and record data.
- Created VpsServiceCollection and VpsServiceResource for VPS service management.
- Added DnsManagerNS and DnsManagerUser models to represent DNS records and user associations.
- Developed AdminZoneDnsSqlImporter for importing DNS data from SQL dumps, including customer and DNS domain records.
- Added migration scripts to update the customers table with new fields and sync foreign key references for DNS tables.
- Created a migration preview document outlining the mapping and schema changes for the admin zone DNS import.
This commit is contained in:
baodev0
2026-05-26 13:54:33 +07:00
parent 520f21cb11
commit fccb0c353a
30 changed files with 4030 additions and 105 deletions
@@ -0,0 +1,67 @@
<?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
{
$hasUsername = Schema::hasColumn('customers', 'username');
$hasEmailVerifiedAt = Schema::hasColumn('customers', 'email_verified_at');
$hasType = Schema::hasColumn('customers', 'type');
if (! $hasUsername || ! $hasEmailVerifiedAt || ! $hasType) {
Schema::table('customers', function (Blueprint $table) use ($hasUsername, $hasEmailVerifiedAt, $hasType) {
if (! $hasUsername) {
$table->string('username', 50)->nullable()->after('fullname');
$table->unique('username');
}
if (! $hasEmailVerifiedAt) {
$table->timestamp('email_verified_at')->nullable()->after('email');
}
if (! $hasType) {
$table->string('type', 255)->default('guest')->after('password');
}
});
}
}
public function down(): void
{
$hasUsername = Schema::hasColumn('customers', 'username');
$hasEmailVerifiedAt = Schema::hasColumn('customers', 'email_verified_at');
$hasType = Schema::hasColumn('customers', 'type');
if (! $hasUsername && ! $hasEmailVerifiedAt && ! $hasType) {
return;
}
Schema::table('customers', function (Blueprint $table) use ($hasUsername, $hasEmailVerifiedAt, $hasType) {
if ($hasUsername) {
$table->dropUnique('customers_username_unique');
}
$columns = [];
if ($hasUsername) {
$columns[] = 'username';
}
if ($hasEmailVerifiedAt) {
$columns[] = 'email_verified_at';
}
if ($hasType) {
$columns[] = 'type';
}
if ($columns !== []) {
$table->dropColumn($columns);
}
});
}
};
@@ -0,0 +1,116 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
$serverId = $this->resolveCanonicalServerId();
if ($serverId === null) {
throw new RuntimeException('Không tìm thấy dns_manager_servers để sync foreign key.');
}
DB::statement("
UPDATE dns_manager_domain d
LEFT JOIN dns_manager_servers s ON s.id = d.dns_manager_server_id
SET d.dns_manager_server_id = {$serverId}
WHERE d.dns_manager_server_id = 0 OR s.id IS NULL
");
DB::statement('ALTER TABLE dns_manager_domain MODIFY dns_manager_server_id BIGINT UNSIGNED NOT NULL');
DB::statement('ALTER TABLE dns_manager_ns MODIFY dns_manager_domain_id BIGINT UNSIGNED NOT NULL');
$this->addForeignKeyIfMissing(
'dns_manager_domain',
'dns_manager_domain_dns_manager_server_id_foreign',
'ALTER TABLE dns_manager_domain
ADD CONSTRAINT dns_manager_domain_dns_manager_server_id_foreign
FOREIGN KEY (dns_manager_server_id) REFERENCES dns_manager_servers(id)
ON UPDATE CASCADE
ON DELETE RESTRICT'
);
$this->addForeignKeyIfMissing(
'dns_domain_user',
'dns_domain_user_domain_id_foreign',
'ALTER TABLE dns_domain_user
ADD CONSTRAINT dns_domain_user_domain_id_foreign
FOREIGN KEY (domain_id) REFERENCES dns_manager_domain(id)
ON UPDATE CASCADE
ON DELETE CASCADE'
);
$this->addForeignKeyIfMissing(
'dns_domain_user',
'dns_domain_user_user_id_foreign',
'ALTER TABLE dns_domain_user
ADD CONSTRAINT dns_domain_user_user_id_foreign
FOREIGN KEY (user_id) REFERENCES customers(id)
ON UPDATE CASCADE
ON DELETE CASCADE'
);
$this->addForeignKeyIfMissing(
'dns_manager_ns',
'dns_manager_ns_dns_manager_domain_id_foreign',
'ALTER TABLE dns_manager_ns
ADD CONSTRAINT dns_manager_ns_dns_manager_domain_id_foreign
FOREIGN KEY (dns_manager_domain_id) REFERENCES dns_manager_domain(id)
ON UPDATE CASCADE
ON DELETE CASCADE'
);
}
public function down(): void
{
$this->dropForeignKeyIfExists('dns_manager_ns', 'dns_manager_ns_dns_manager_domain_id_foreign');
$this->dropForeignKeyIfExists('dns_domain_user', 'dns_domain_user_user_id_foreign');
$this->dropForeignKeyIfExists('dns_domain_user', 'dns_domain_user_domain_id_foreign');
$this->dropForeignKeyIfExists('dns_manager_domain', 'dns_manager_domain_dns_manager_server_id_foreign');
DB::statement('ALTER TABLE dns_manager_ns MODIFY dns_manager_domain_id INT NOT NULL');
DB::statement('ALTER TABLE dns_manager_domain MODIFY dns_manager_server_id INT NOT NULL DEFAULT 0');
}
private function resolveCanonicalServerId(): ?int
{
$server = DB::table('dns_manager_servers')
->select('id')
->orderByRaw('CASE WHEN id = 1 THEN 0 ELSE 1 END')
->orderBy('id')
->first();
return $server ? (int) $server->id : null;
}
private function addForeignKeyIfMissing(string $table, string $constraint, string $statement): void
{
$exists = DB::table('information_schema.TABLE_CONSTRAINTS')
->whereRaw('TABLE_SCHEMA = DATABASE()')
->where('TABLE_NAME', $table)
->where('CONSTRAINT_NAME', $constraint)
->where('CONSTRAINT_TYPE', 'FOREIGN KEY')
->exists();
if (! $exists) {
DB::statement($statement);
}
}
private function dropForeignKeyIfExists(string $table, string $constraint): void
{
$exists = DB::table('information_schema.TABLE_CONSTRAINTS')
->whereRaw('TABLE_SCHEMA = DATABASE()')
->where('TABLE_NAME', $table)
->where('CONSTRAINT_NAME', $constraint)
->where('CONSTRAINT_TYPE', 'FOREIGN KEY')
->exists();
if ($exists) {
DB::statement("ALTER TABLE {$table} DROP FOREIGN KEY {$constraint}");
}
}
};