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); $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(); \Log::error('DomainController::storeRecord error: ' . $e->getMessage()); return response()->json(['error' => true, 'message' => 'Có lỗi xảy ra, vui lòng thử lại'], 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); } if ($locked = $this->lockedRecordResponse($record)) { return $locked; } $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 ($locked = $this->lockedRecordResponse($record)) { return $locked; } 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 lockedRecordResponse(DnsManagerNS $record): ?JsonResponse { return in_array(strtoupper((string) $record->type), self::CLIENT_EDITABLE_TYPES, true) ? null : response()->json([ 'error' => true, 'message' => "Bản ghi {$record->type} không thể tự thay đổi. Vui lòng liên hệ bộ phận kỹ thuật.", ], 403); } private function resolveCustomerDomain(Request $request, int $domainId): ?DnsDomain { $customer = $request->user(); return DnsDomain::query() ->notCancelled() ->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', Rule::in(self::CLIENT_EDITABLE_TYPES)], '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'], ]); } }