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:
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\DnsManager;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Repositories\DnsManager\Record\DnsRecordRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class RecordController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DnsRecordRepositoryInterface $recordRepository,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$perPage = min((int) $request->get('per_page', 15), 500);
|
||||
$filter = trim((string) $request->get('filter', ''));
|
||||
$type = trim((string) $request->get('type', ''));
|
||||
|
||||
$query = $this->recordRepository->model
|
||||
->with(['domain.server'])
|
||||
->newQuery();
|
||||
|
||||
if ($filter !== '') {
|
||||
$query->where(function ($subQuery) use ($filter) {
|
||||
$subQuery->where('name', 'like', "%{$filter}%")
|
||||
->orWhere('value', 'like', "%{$filter}%")
|
||||
->orWhereHas('domain', function ($domainQuery) use ($filter) {
|
||||
$domainQuery->where('domain_name', 'like', "%{$filter}%")
|
||||
->orWhereHas('server', function ($serverQuery) use ($filter) {
|
||||
$serverQuery->where('name', 'like', "%{$filter}%")
|
||||
->orWhere('ip_address', 'like', "%{$filter}%");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ($type !== '') {
|
||||
$query->where('type', $type);
|
||||
}
|
||||
|
||||
$paginator = $query->orderByDesc('id')->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
'items' => $paginator->getCollection()->map(fn($record) => $this->formatRecord($record)),
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'last_page' => $paginator->lastPage(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$record = $this->recordRepository->model
|
||||
->with(['domain.server'])
|
||||
->find($id);
|
||||
|
||||
if (! $record) {
|
||||
return response()->json(['error' => true, 'message' => "Không tìm thấy bản ghi DNS #$id"], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $this->formatRecord($record),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(int $id, Request $request): JsonResponse
|
||||
{
|
||||
$record = $this->recordRepository->model
|
||||
->with(['domain.server'])
|
||||
->find($id);
|
||||
|
||||
if (! $record) {
|
||||
return response()->json(['error' => true, 'message' => "Không tìm thấy bản ghi DNS #$id"], 404);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'type' => 'required|string|in:A,AAAA,CNAME,TXT,MX,NS,SRV',
|
||||
'name' => 'required|string|max:255',
|
||||
'value' => 'required|string',
|
||||
'ttl' => 'nullable|integer|min:60',
|
||||
'priority' => 'nullable|integer|min:0',
|
||||
'weight' => 'nullable|integer|min:0',
|
||||
'port' => 'nullable|integer|min:0',
|
||||
'service_name' => 'nullable|string|max:255',
|
||||
'protocol' => 'nullable|string|max:50',
|
||||
]);
|
||||
|
||||
$payload = [
|
||||
'type' => $validated['type'],
|
||||
'type_valid' => $validated['type'],
|
||||
'name' => $validated['name'],
|
||||
'value' => $validated['value'],
|
||||
'ttl' => $validated['ttl'] ?? 300,
|
||||
'priority' => array_key_exists('priority', $validated) ? (string) ($validated['priority'] ?? 0) : $record->priority,
|
||||
'weight' => array_key_exists('weight', $validated) ? (string) ($validated['weight'] ?? 0) : $record->weight,
|
||||
'port' => array_key_exists('port', $validated) ? (string) ($validated['port'] ?? 0) : $record->port,
|
||||
'service_name' => $validated['service_name'] ?? null,
|
||||
'protocol' => $validated['protocol'] ?? null,
|
||||
];
|
||||
|
||||
$this->recordRepository->update($id, $payload);
|
||||
|
||||
return $this->show($id);
|
||||
}
|
||||
|
||||
private function formatRecord($record): array
|
||||
{
|
||||
return [
|
||||
'id' => $record->id,
|
||||
'dns_manager_domain_id' => $record->dns_manager_domain_id,
|
||||
'domain_name' => $record->domain?->domain_name,
|
||||
'dns_manager_server_id' => $record->domain?->dns_manager_server_id,
|
||||
'server_name' => $record->domain?->server?->name,
|
||||
'server_ip_address' => $record->domain?->server?->ip_address,
|
||||
'type' => $record->type,
|
||||
'type_valid' => $record->type_valid,
|
||||
'name' => $record->name,
|
||||
'value' => $record->value,
|
||||
'priority' => $record->priority !== null ? (int) $record->priority : null,
|
||||
'weight' => $record->weight !== null ? (int) $record->weight : null,
|
||||
'port' => $record->port !== null ? (int) $record->port : null,
|
||||
'service_name' => $record->service_name,
|
||||
'protocol' => $record->protocol,
|
||||
'plesk_id' => $record->plesk_id,
|
||||
'ttl' => (int) $record->ttl,
|
||||
'created_at' => $record->created_at,
|
||||
'updated_at' => $record->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -4,46 +4,48 @@ namespace App\Http\Controllers\Api\Admin\DnsManager;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Repositories\DnsManager\Server\DnsServerRepositoryInterface;
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DnsServerRepositoryInterface $serverRepository,
|
||||
private readonly ServerService $serverService,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$perPage = min((int) $request->get('per_page', 15), 500);
|
||||
$filter = $request->get('filter');
|
||||
$status = $request->get('status');
|
||||
$filter = $request->get('filter');
|
||||
$status = $request->get('status');
|
||||
|
||||
$query = $this->serverRepository->model->newQuery();
|
||||
|
||||
if ($filter) {
|
||||
$query->where(function ($q) use ($filter) {
|
||||
$q->where('name', 'like', "%{$filter}%")
|
||||
->orWhere('ip_address', 'like', "%{$filter}%");
|
||||
$query->where(function ($subQuery) use ($filter) {
|
||||
$subQuery->where('name', 'like', "%{$filter}%")
|
||||
->orWhere('ip_address', 'like', "%{$filter}%")
|
||||
->orWhere('username', 'like', "%{$filter}%");
|
||||
});
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
if ($status !== null && $status !== '') {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
|
||||
$paginator = $query->paginate($perPage);
|
||||
$paginator = $query->orderByDesc('id')->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
'items' => $paginator->items(),
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'data' => [
|
||||
'items' => $paginator->getCollection()->map(fn($server) => $this->formatServer($server)),
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'last_page' => $paginator->lastPage(),
|
||||
'last_page' => $paginator->lastPage(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -56,30 +58,44 @@ class ServerController extends Controller
|
||||
return response()->json(['error' => true, 'message' => "Không tìm thấy server #$id"], 404);
|
||||
}
|
||||
|
||||
return response()->json(['error' => false, 'data' => $server]);
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $this->formatServer($server),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'ip_address' => 'required|string|max:255',
|
||||
'username' => 'required|string|max:255',
|
||||
'password' => 'required|string|max:255',
|
||||
'api_key' => 'nullable|string',
|
||||
'status' => 'nullable|string|in:activated,Stopped',
|
||||
'username' => 'required|string|max:255',
|
||||
'password' => 'required|string|max:255',
|
||||
'api_key' => 'nullable|string',
|
||||
'status' => 'nullable|string|in:activated,Stopped',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$data = $request->all();
|
||||
$data['password'] = Crypt::encryptString($request->password);
|
||||
$server = $this->serverRepository->create($data);
|
||||
$server = $this->serverRepository->create([
|
||||
'name' => $validated['name'],
|
||||
'ip_address' => $validated['ip_address'],
|
||||
'username' => $validated['username'],
|
||||
'password' => encrypt($validated['password']),
|
||||
'api_key' => $validated['api_key'] ?? null,
|
||||
'status' => $validated['status'] ?? 'activated',
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json(['error' => false, 'data' => $server], 201);
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => $this->formatServer($server),
|
||||
], 201);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
@@ -92,29 +108,34 @@ class ServerController extends Controller
|
||||
return response()->json(['error' => true, 'message' => "Không tìm thấy server #$id"], 404);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'ip_address' => 'required|string|max:255',
|
||||
'username' => 'required|string|max:255',
|
||||
'password' => 'nullable|string|max:255',
|
||||
'api_key' => 'nullable|string',
|
||||
'status' => 'nullable|string|in:activated,Stopped',
|
||||
$validated = $request->validate([
|
||||
'name' => 'sometimes|required|string|max:255',
|
||||
'ip_address' => 'sometimes|required|string|max:255',
|
||||
'username' => 'sometimes|required|string|max:255',
|
||||
'password' => 'nullable|string|max:255',
|
||||
'api_key' => 'nullable|string',
|
||||
'status' => 'nullable|string|in:activated,Stopped',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$data = $request->except(['password']);
|
||||
|
||||
if (!empty($request->password)) {
|
||||
$data['password'] = Crypt::encryptString($request->password);
|
||||
try {
|
||||
$payload = collect($validated)
|
||||
->except('password')
|
||||
->toArray();
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$payload['password'] = encrypt((string) $request->password);
|
||||
}
|
||||
|
||||
$this->serverRepository->update($id, $data);
|
||||
$this->serverRepository->update($id, $payload);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json(['error' => false, 'data' => $this->serverRepository->find($id)]);
|
||||
return $this->show($id);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
@@ -131,4 +152,37 @@ class ServerController extends Controller
|
||||
|
||||
return response()->json(['error' => false, 'message' => 'Đã xoá server thành công']);
|
||||
}
|
||||
|
||||
public function checkConnection(int $id): JsonResponse
|
||||
{
|
||||
$server = $this->serverRepository->find($id);
|
||||
|
||||
if (!$server) {
|
||||
return response()->json(['error' => true, 'message' => "Không tìm thấy server #$id"], 404);
|
||||
}
|
||||
|
||||
$connected = $this->serverService->checkConnectionByServer($server);
|
||||
|
||||
return response()->json([
|
||||
'error' => !$connected,
|
||||
'data' => ['connected' => $connected],
|
||||
'message' => $connected
|
||||
? 'Kết nối server thành công.'
|
||||
: 'Không thể kết nối tới server. Vui lòng kiểm tra lại IP hoặc tài khoản.',
|
||||
]);
|
||||
}
|
||||
|
||||
private function formatServer($server): array
|
||||
{
|
||||
return [
|
||||
'id' => $server->id,
|
||||
'name' => $server->name,
|
||||
'ip_address' => $server->ip_address,
|
||||
'username' => $server->username,
|
||||
'api_key' => $server->api_key,
|
||||
'status' => $server->status,
|
||||
'created_at' => $server->created_at,
|
||||
'updated_at' => $server->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Client\Service;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\Service\DomainCollection;
|
||||
use App\Http\Resources\Api\Service\DomainDetailResource;
|
||||
use App\Http\Resources\Api\Service\DomainNSResource;
|
||||
use App\Models\DnsDomain;
|
||||
use App\Models\DnsManagerNS;
|
||||
use App\Services\ActivityLogger;
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DomainController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected ActivityLogger $activityLogger,
|
||||
protected ServerService $serverService,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$customer = $request->user();
|
||||
$perPage = min((int) $request->get('per_page', 15), 100);
|
||||
|
||||
$domains = DnsDomain::query()
|
||||
->with('server')
|
||||
->withCount('record')
|
||||
->whereHas('customer', fn ($query) => $query->where('customers.id', $customer->id))
|
||||
->orderByDesc('id')
|
||||
->paginate($perPage);
|
||||
|
||||
return (new DomainCollection($domains))
|
||||
->additional([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service_domain',
|
||||
])
|
||||
->response();
|
||||
}
|
||||
|
||||
public function show(Request $request, int $domainId): JsonResponse
|
||||
{
|
||||
$domain = $this->resolveCustomerDomain($request, $domainId);
|
||||
|
||||
if (! $domain) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy domain'], 404);
|
||||
}
|
||||
|
||||
$perPage = min((int) $request->get('per_page', 15), 100);
|
||||
|
||||
$domain->load('server')->loadCount('record');
|
||||
|
||||
$records = DnsManagerNS::query()
|
||||
->where('dns_manager_domain_id', $domain->id)
|
||||
->orderBy('type')
|
||||
->orderBy('name')
|
||||
->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service_domain_detail',
|
||||
'data' => new DomainDetailResource($domain, $records),
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeRecord(Request $request, int $domainId): JsonResponse
|
||||
{
|
||||
$domain = $this->resolveCustomerDomain($request, $domainId);
|
||||
|
||||
if (! $domain) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy domain'], 404);
|
||||
}
|
||||
|
||||
$payload = $this->validateDomainRecordPayload($request);
|
||||
|
||||
$this->serverService->findServerByID($domain->dns_manager_server_id);
|
||||
$serverPayload = $this->serverService->handlePayload([
|
||||
...$payload,
|
||||
'domain' => $domain->domain_name,
|
||||
])->addRecord();
|
||||
|
||||
if (! empty($serverPayload['error'])) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $serverPayload['message'] ?? 'Không thể tạo DNS record trên server',
|
||||
], 422);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$record = DnsManagerNS::query()->create([
|
||||
'dns_manager_domain_id' => $domain->id,
|
||||
'type' => $payload['type'],
|
||||
'type_valid' => $payload['type'],
|
||||
'name' => $payload['name'],
|
||||
'value' => $payload['value'],
|
||||
'ttl' => $payload['ttl'] ?? 300,
|
||||
'priority' => (string) ($payload['priority'] ?? 0),
|
||||
'weight' => (string) ($payload['weight'] ?? 0),
|
||||
'port' => (string) ($payload['port'] ?? 0),
|
||||
'service_name' => $payload['service_name'] ?? null,
|
||||
'protocol' => $payload['protocol'] ?? null,
|
||||
'plesk_id' => $serverPayload['data']['id'] ?? null,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return response()->json(['error' => true, 'message' => $e->getMessage()], 500);
|
||||
}
|
||||
|
||||
$customer = $request->user();
|
||||
$this->activityLogger->log(
|
||||
event: 'created',
|
||||
logName: 'DNS',
|
||||
description: "Customer {$customer->email} tạo DNS record #{$record->id} của domain {$domain->domain_name}",
|
||||
subject: $record,
|
||||
newValues: [
|
||||
'domain_id' => $domain->id,
|
||||
'domain_name' => $domain->domain_name,
|
||||
'type' => $record->type,
|
||||
'name' => $record->name,
|
||||
'value' => $record->value,
|
||||
],
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Tạo DNS record thành công',
|
||||
'data' => new DomainNSResource($record),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function updateRecord(Request $request, int $domainId, int $recordId): JsonResponse
|
||||
{
|
||||
$domain = $this->resolveCustomerDomain($request, $domainId);
|
||||
|
||||
if (! $domain) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy domain'], 404);
|
||||
}
|
||||
|
||||
$record = DnsManagerNS::query()
|
||||
->where('dns_manager_domain_id', $domain->id)
|
||||
->find($recordId);
|
||||
|
||||
if (! $record) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy bản ghi DNS'], 404);
|
||||
}
|
||||
|
||||
$payload = $this->validateDomainRecordPayload($request);
|
||||
|
||||
if (! empty($record->plesk_id)) {
|
||||
$this->serverService->findServerByID($domain->dns_manager_server_id);
|
||||
$serverPayload = $this->serverService->handlePayload([
|
||||
...$payload,
|
||||
'domain' => $domain->domain_name,
|
||||
])->updateRecord((int) $record->plesk_id);
|
||||
|
||||
if (! empty($serverPayload['error'])) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $serverPayload['message'] ?? 'Không thể cập nhật DNS record trên server',
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
|
||||
$record->update([
|
||||
'type' => $payload['type'],
|
||||
'type_valid' => $record->type_valid ?: $payload['type'],
|
||||
'name' => $payload['name'],
|
||||
'value' => $payload['value'],
|
||||
'ttl' => $payload['ttl'] ?? $record->ttl,
|
||||
'priority' => isset($payload['priority']) ? (string) $payload['priority'] : $record->priority,
|
||||
'weight' => isset($payload['weight']) ? (string) $payload['weight'] : $record->weight,
|
||||
'port' => isset($payload['port']) ? (string) $payload['port'] : $record->port,
|
||||
'service_name' => $payload['service_name'] ?? $record->service_name,
|
||||
'protocol' => $payload['protocol'] ?? $record->protocol,
|
||||
]);
|
||||
|
||||
$customer = $request->user();
|
||||
$this->activityLogger->log(
|
||||
event: 'updated',
|
||||
logName: 'DNS',
|
||||
description: "Customer {$customer->email} cập nhật DNS record #{$record->id} của domain {$domain->domain_name}",
|
||||
subject: $record,
|
||||
newValues: [
|
||||
'domain_id' => $domain->id,
|
||||
'domain_name' => $domain->domain_name,
|
||||
'type' => $record->type,
|
||||
'name' => $record->name,
|
||||
'value' => $record->value,
|
||||
],
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Cập nhật DNS record thành công',
|
||||
'data' => new DomainNSResource($record),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroyRecord(Request $request, int $domainId, int $recordId): JsonResponse
|
||||
{
|
||||
$domain = $this->resolveCustomerDomain($request, $domainId);
|
||||
|
||||
if (! $domain) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy domain'], 404);
|
||||
}
|
||||
|
||||
$record = DnsManagerNS::query()
|
||||
->where('dns_manager_domain_id', $domain->id)
|
||||
->find($recordId);
|
||||
|
||||
if (! $record) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy bản ghi DNS'], 404);
|
||||
}
|
||||
|
||||
if (! empty($record->plesk_id)) {
|
||||
$this->serverService->findServerByID($domain->dns_manager_server_id);
|
||||
$serverPayload = $this->serverService->deleteRecord((int) $record->plesk_id);
|
||||
|
||||
if (! empty($serverPayload['error'])) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $serverPayload['message'] ?? 'Không thể xóa DNS record trên server',
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
|
||||
$snapshot = new DomainNSResource($record);
|
||||
$record->delete();
|
||||
|
||||
$customer = $request->user();
|
||||
$this->activityLogger->log(
|
||||
event: 'deleted',
|
||||
logName: 'DNS',
|
||||
description: "Customer {$customer->email} xóa DNS record #{$recordId} của domain {$domain->domain_name}",
|
||||
subject: $domain,
|
||||
newValues: [
|
||||
'domain_id' => $domain->id,
|
||||
'domain_name' => $domain->domain_name,
|
||||
'record_id' => $recordId,
|
||||
],
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Xóa DNS record thành công',
|
||||
'data' => $snapshot,
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveCustomerDomain(Request $request, int $domainId): ?DnsDomain
|
||||
{
|
||||
$customer = $request->user();
|
||||
|
||||
return DnsDomain::query()
|
||||
->with('server')
|
||||
->where('id', $domainId)
|
||||
->whereHas('customer', fn ($query) => $query->where('customers.id', $customer->id))
|
||||
->first();
|
||||
}
|
||||
|
||||
private function validateDomainRecordPayload(Request $request): array
|
||||
{
|
||||
return $request->validate([
|
||||
'type' => ['required', 'string', 'in:A,AAAA,CNAME,TXT,MX,NS,SRV'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'value' => ['required', 'string'],
|
||||
'ttl' => ['nullable', 'integer', 'min:60', 'max:86400'],
|
||||
'priority' => ['nullable', 'integer', 'min:0', 'max:65535'],
|
||||
'weight' => ['nullable', 'integer', 'min:0', 'max:65535'],
|
||||
'port' => ['nullable', 'integer', 'min:0', 'max:65535'],
|
||||
'service_name' => ['nullable', 'string', 'max:255'],
|
||||
'protocol' => ['nullable', 'string', 'max:255'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Http\Controllers\Api\Client\Service;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\Service\VpsServiceCollection;
|
||||
use App\Http\Resources\Api\Client\Service\ServiceClientDetailResource;
|
||||
use \App\Http\Resources\Api\Client\Service\ServiceClientResource;
|
||||
use App\Http\Services\vCenter;
|
||||
use App\Models\Order;
|
||||
use App\Models\Service;
|
||||
@@ -31,22 +31,75 @@ class ServiceController extends Controller
|
||||
$this->activityLogger = $activityLogger;
|
||||
}
|
||||
|
||||
public function getService(Request $request)
|
||||
public function indexVps(Request $request): JsonResponse
|
||||
{
|
||||
$limit = $request->get('limit', 10);
|
||||
$services = $this->serviceClientService->getActiveServices($limit);
|
||||
$perPage = min((int) $request->get('per_page', 15), 100);
|
||||
$customer = $request->user();
|
||||
|
||||
return ServiceClientResource::collection($services)->additional([
|
||||
$services = $this->serviceClientService->getActiveServices($customer->id, 'vps', $perPage);
|
||||
|
||||
return (new VpsServiceCollection($services))
|
||||
->additional([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service_vps',
|
||||
])
|
||||
->response();
|
||||
}
|
||||
|
||||
public function indexHosting(Request $request): JsonResponse
|
||||
{
|
||||
$perPage = min((int) $request->get('per_page', 15), 100);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service',
|
||||
'page_type' => 'service_hosting',
|
||||
'data' => [
|
||||
'items' => [],
|
||||
'pagination' => [
|
||||
'total' => 0,
|
||||
'per_page' => $perPage,
|
||||
'current_page' => 1,
|
||||
'last_page' => 1,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function indexWebDesign(Request $request): JsonResponse
|
||||
{
|
||||
$perPage = min((int) $request->get('per_page', 15), 100);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service_web_design',
|
||||
'data' => [
|
||||
'items' => [],
|
||||
'pagination' => [
|
||||
'total' => 0,
|
||||
'per_page' => $perPage,
|
||||
'current_page' => 1,
|
||||
'last_page' => 1,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDetail(Request $request, string $uuid)
|
||||
{
|
||||
$service = $this->serviceClientService->getDetailService($uuid);
|
||||
$service = $this->serviceClientService->getDetailService($uuid, $request->user()->id);
|
||||
|
||||
if (!$service) {
|
||||
return response()->json(
|
||||
[
|
||||
'error' => true,
|
||||
'message' => 'Không tìm thấy dịch vụ',
|
||||
],
|
||||
404,
|
||||
);
|
||||
}
|
||||
|
||||
return (new ServiceClientDetailResource($service))->additional([
|
||||
'error' => false,
|
||||
@@ -113,7 +166,7 @@ class ServiceController extends Controller
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'error' => false,
|
||||
'message' => $ticket,
|
||||
]);
|
||||
}
|
||||
@@ -188,7 +241,7 @@ class ServiceController extends Controller
|
||||
$customer = $request->user();
|
||||
|
||||
$service = Service::with([
|
||||
'product.osVersions' => fn ($q) => $q->where('status', 1)->with('osGroup'),
|
||||
'product.osVersions' => fn($q) => $q->where('status', 1)->with('osGroup'),
|
||||
])
|
||||
->where('uuid', $uuid)
|
||||
->where('customer_id', $customer->id)
|
||||
@@ -199,7 +252,10 @@ class ServiceController extends Controller
|
||||
}
|
||||
|
||||
if (!in_array($service->status, ['active', 'suspended'], true)) {
|
||||
return response()->json(['success' => false, 'message' => 'Dịch vụ không ở trạng thái hợp lệ để xem OS'], 422);
|
||||
return response()->json(
|
||||
['success' => false, 'message' => 'Dịch vụ không ở trạng thái hợp lệ để xem OS'],
|
||||
422,
|
||||
);
|
||||
}
|
||||
|
||||
if (!$service->product) {
|
||||
@@ -207,32 +263,38 @@ class ServiceController extends Controller
|
||||
}
|
||||
|
||||
$grouped = $service->product->osVersions
|
||||
->groupBy(fn ($os) => $os->osGroup?->id ?? 0)
|
||||
->map(fn ($items) => [
|
||||
'group' => [
|
||||
'id' => $items->first()->osGroup?->id,
|
||||
'name' => $items->first()->osGroup?->name,
|
||||
'thumbnail' => $items->first()->osGroup?->thumbnail,
|
||||
->groupBy(fn($os) => $os->osGroup?->id ?? 0)
|
||||
->map(
|
||||
fn($items) => [
|
||||
'group' => [
|
||||
'id' => $items->first()->osGroup?->id,
|
||||
'name' => $items->first()->osGroup?->name,
|
||||
'thumbnail' => $items->first()->osGroup?->thumbnail,
|
||||
],
|
||||
'items' => $items
|
||||
->map(
|
||||
fn($os) => [
|
||||
'id' => $os->id,
|
||||
'version' => $os->version,
|
||||
'template_id' => $os->template_id,
|
||||
],
|
||||
)
|
||||
->values(),
|
||||
],
|
||||
'items' => $items->map(fn ($os) => [
|
||||
'id' => $os->id,
|
||||
'version' => $os->version,
|
||||
'template_id' => $os->template_id,
|
||||
])->values(),
|
||||
])
|
||||
)
|
||||
->values();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $grouped,
|
||||
'data' => $grouped,
|
||||
]);
|
||||
}
|
||||
|
||||
public function rebuild(Request $request, string $uuid, vCenter $serviceVCenter): JsonResponse
|
||||
{
|
||||
$customer = $request->user();
|
||||
$payload = $request->validate([
|
||||
'os_id' => ['required', 'integer', 'exists:os,id'],
|
||||
$payload = $request->validate([
|
||||
'os_id' => ['required', 'integer', 'exists:os,id'],
|
||||
'password' => ['nullable', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
@@ -246,18 +308,18 @@ class ServiceController extends Controller
|
||||
}
|
||||
|
||||
if ($service->status === 'suspended') {
|
||||
return response()->json(['success' => false, 'message' => 'Dịch vụ đang bị tạm ngưng, không thể rebuild'], 422);
|
||||
return response()->json(
|
||||
['success' => false, 'message' => 'Dịch vụ đang bị tạm ngưng, không thể rebuild'],
|
||||
422,
|
||||
);
|
||||
}
|
||||
|
||||
if (!$service->isActive()) {
|
||||
return response()->json(['success' => false, 'message' => 'Dịch vụ không ở trạng thái active'], 422);
|
||||
}
|
||||
|
||||
$allowedOsIds = $service->product?->osVersions()
|
||||
->where('status', 1)
|
||||
->pluck('os.id')
|
||||
->map('intval')
|
||||
->toArray() ?? [];
|
||||
$allowedOsIds =
|
||||
$service->product?->osVersions()->where('status', 1)->pluck('os.id')->map('intval')->toArray() ?? [];
|
||||
|
||||
if (!in_array((int) $payload['os_id'], $allowedOsIds, true)) {
|
||||
return response()->json(['success' => false, 'message' => 'OS không hợp lệ cho sản phẩm hiện tại'], 422);
|
||||
@@ -269,31 +331,34 @@ class ServiceController extends Controller
|
||||
}
|
||||
|
||||
DB::table('reinstall_logs')->insert([
|
||||
'product_id' => $vm->id,
|
||||
'product_id' => $vm->id,
|
||||
'product_type' => 4,
|
||||
'custome_id' => $customer->id,
|
||||
'os_id' => $payload['os_id'],
|
||||
'status' => 'pending',
|
||||
'initiator' => 'client',
|
||||
'note' => 'Client rebuild via service UUID: ' . $uuid,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
'custome_id' => $customer->id,
|
||||
'os_id' => $payload['os_id'],
|
||||
'status' => 'pending',
|
||||
'initiator' => 'client',
|
||||
'note' => 'Client rebuild via service UUID: ' . $uuid,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$result = $serviceVCenter->reBuildVPS((string) $vm->name);
|
||||
if (is_string($result) || ($result['error'] ?? false)) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => is_string($result) ? $result : ($result['message'] ?? 'Không thể rebuild VM'),
|
||||
], 400);
|
||||
return response()->json(
|
||||
[
|
||||
'success' => false,
|
||||
'message' => is_string($result) ? $result : $result['message'] ?? 'Không thể rebuild VM',
|
||||
],
|
||||
400,
|
||||
);
|
||||
}
|
||||
|
||||
$this->activityLogger->log(
|
||||
event: 'rebuild',
|
||||
logName: 'VM',
|
||||
event: 'rebuild',
|
||||
logName: 'VM',
|
||||
description: "Customer {$customer->email} rebuild VM: {$vm->name} với OS ID: {$payload['os_id']} qua service UUID: {$uuid}",
|
||||
subject: $vm,
|
||||
newValues: ['os_id' => $payload['os_id'], 'service_uuid' => $uuid],
|
||||
subject: $vm,
|
||||
newValues: ['os_id' => $payload['os_id'], 'service_uuid' => $uuid],
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
@@ -301,5 +366,4 @@ class ServiceController extends Controller
|
||||
'message' => 'Đã gửi yêu cầu rebuild VM',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user