get('per_page', 15), 500); $filter = $request->get('filter'); $networkId = $request->get('network_id'); $query = IpPool::with('network:id,name,type,network'); if ($filter) { $query->where('ip_address', 'like', "%{$filter}%"); } if ($networkId) { $query->where('module_network_id', $networkId); } $paginator = $query->paginate($perPage); // Enrich each item with usage info $usedIps = ModuleIpAddress::whereIn('ip', $paginator->pluck('ip_address')->toArray()) ->where('status', 1) ->with('host:id,name') ->select(['id', 'ip', 'vm_name', 'module_host_id', 'module_network_id', 'status']) ->get() ->keyBy('ip'); // Get vmware info for used IPs $vmwareMap = []; if ($usedIps->isNotEmpty()) { $vmwares = DB::table('module_vmware as mv') ->join('module_ip_address as mia', 'mv.module_ip_address', '=', 'mia.id') ->whereIn('mia.ip', $usedIps->keys()->toArray()) ->leftJoin('services as s', 's.id', '=', 'mv.service_id') ->leftJoin('customers as c', 'c.id', '=', 'mv.customer_id') ->select([ 'mia.ip', 'mv.name as vm_name', 'mv.id as vm_id', 's.id as service_id', 's.status as service_status', 'c.fullname', 'c.email', ]) ->get(); foreach ($vmwares as $vm) { $vmwareMap[$vm->ip] = $vm; } } $items = $paginator->map(function (IpPool $pool) use ($usedIps, $vmwareMap) { $data = $pool->toArray(); $ip = $pool->ip_address; if (isset($usedIps[$ip])) { $mia = $usedIps[$ip]; $vm = $vmwareMap[$ip] ?? null; $data['usage'] = [ 'assigned' => true, 'vm_name' => $vm?->vm_name ?? $mia->vm_name, 'vm_id' => $vm?->vm_id ?? null, 'service_id' => $vm?->service_id ?? null, 'service_status' => $vm?->service_status ?? null, 'customer_name' => $vm?->fullname ?? null, 'customer_email' => $vm?->email ?? null, ]; } else { $data['usage'] = ['assigned' => false]; } return $data; }); return response()->json([ 'error' => false, 'data' => [ 'items' => $items->values(), 'total' => $paginator->total(), 'per_page' => $paginator->perPage(), 'current_page' => $paginator->currentPage(), 'last_page' => $paginator->lastPage(), ], ]); } public function show(int $id): JsonResponse { $pool = IpPool::with('network:id,name,type,network')->find($id); if (!$pool) { return response()->json(['error' => true, 'message' => "Không tìm thấy IP Pool #{$id}"], 404); } return response()->json(['error' => false, 'data' => $pool]); } /** * Bulk create: ip_address may be comma-separated (e.g. "10.0.0.1,10.0.0.2"). */ public function store(Request $request): JsonResponse { $request->validate([ 'ip_address' => 'required|string', 'module_network_id' => 'required|integer|exists:module_network,id', ]); $networkId = (int) $request->module_network_id; $rawIps = $request->ip_address; $ips = array_filter(array_map('trim', explode(',', $rawIps))); if (empty($ips)) { return response()->json(['error' => true, 'message' => 'Không có địa chỉ IP hợp lệ'], 422); } // Validate each IP $invalid = []; foreach ($ips as $ip) { if (!filter_var($ip, FILTER_VALIDATE_IP)) { $invalid[] = $ip; } } if (!empty($invalid)) { return response()->json([ 'error' => true, 'message' => 'Địa chỉ IP không hợp lệ: ' . implode(', ', $invalid), ], 422); } // Check duplicates already in pool $existing = IpPool::where('module_network_id', $networkId) ->whereIn('ip_address', $ips) ->pluck('ip_address') ->toArray(); if (!empty($existing)) { return response()->json([ 'error' => true, 'message' => 'Địa chỉ IP đã tồn tại trong pool: ' . implode(', ', $existing), ], 422); } DB::beginTransaction(); try { $created = []; foreach ($ips as $ip) { $created[] = IpPool::create([ 'ip_address' => $ip, 'module_network_id' => $networkId, ]); } DB::commit(); return response()->json(['error' => false, 'data' => $created, 'count' => count($created)], 201); } catch (\Exception $e) { DB::rollBack(); return response()->json(['error' => true, 'message' => $e->getMessage()], 500); } } public function update(int $id, Request $request): JsonResponse { $pool = IpPool::find($id); if (!$pool) { return response()->json(['error' => true, 'message' => "Không tìm thấy IP Pool #{$id}"], 404); } $request->validate([ 'ip_address' => 'required|string|max:45', 'module_network_id' => 'required|integer|exists:module_network,id', ]); if (!filter_var($request->ip_address, FILTER_VALIDATE_IP)) { return response()->json(['error' => true, 'message' => 'Địa chỉ IP không hợp lệ'], 422); } // Check duplicate (excluding self) $duplicate = IpPool::where('module_network_id', $request->module_network_id) ->where('ip_address', $request->ip_address) ->where('id', '!=', $id) ->exists(); if ($duplicate) { return response()->json([ 'error' => true, 'message' => 'Địa chỉ IP đã tồn tại trong pool này', ], 422); } DB::beginTransaction(); try { $pool->update($request->only(['ip_address', 'module_network_id'])); DB::commit(); return response()->json(['error' => false, 'data' => $pool->fresh('network')]); } catch (\Exception $e) { DB::rollBack(); return response()->json(['error' => true, 'message' => $e->getMessage()], 500); } } public function destroy(int $id): JsonResponse { $pool = IpPool::find($id); if (!$pool) { return response()->json(['error' => true, 'message' => "Không tìm thấy IP Pool #{$id}"], 404); } // Check if IP is currently assigned $inUse = ModuleIpAddress::where('ip', $pool->ip_address) ->where('module_network_id', $pool->module_network_id) ->where('status', 1) ->exists(); if ($inUse) { return response()->json([ 'error' => true, 'message' => 'Không thể xoá — IP này đang được gán cho một máy chủ', ], 422); } $pool->delete(); return response()->json(['error' => false, 'message' => 'Đã xoá IP Pool thành công']); } public function networks(): JsonResponse { $networks = ModuleNetwork::select(['id', 'name', 'type', 'network']) ->orderBy('name') ->get(); return response()->json(['error' => false, 'data' => $networks]); } }