authorize('viewAny', IpPool::class); $pools = IpPool::query() ->withCount(['vms' => fn ($q) => $q->whereIn('status', ['pending', 'active'])]) ->orderBy('type') ->orderBy('name') ->get() ->map(function (IpPool $pool) { $pool->setAttribute('usage_percent', $pool->totalIps() > 0 ? round(($pool->usedIpsCount() / $pool->totalIps()) * 100, 1) : 0); return $pool; }); $assignments = Customer::query() ->forUser($request->user()) ->with(['owner', 'ipPool']) ->whereIn('status', ['pending', 'active']) ->where(fn ($q) => $q->whereNotNull('ip_address')->orWhereNotNull('public_ip')) ->orderBy('name') ->get(); return view('ip-pools.index', compact('pools', 'assignments')); } public function create(): View { $this->authorize('create', IpPool::class); return view('ip-pools.create', ['types' => IpPoolType::cases()]); } public function store(Request $request): RedirectResponse { $this->authorize('create', IpPool::class); $data = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'type' => ['required', Rule::enum(IpPoolType::class)], 'start_ip' => ['required', 'ip'], 'end_ip' => ['required', 'ip'], 'gateway' => ['nullable', 'ip'], 'cidr' => ['required', 'integer', 'min:8', 'max:32'], 'description' => ['nullable', 'string', 'max:500'], 'is_active' => ['boolean'], ]); if (ip2long($data['start_ip']) > ip2long($data['end_ip'])) { return back()->withErrors(['end_ip' => 'End-IP muss größer als Start-IP sein.'])->withInput(); } IpPool::query()->create([ ...$data, 'is_active' => $request->boolean('is_active', true), ]); return redirect()->route('ip-pools.index')->with('success', 'IP-Pool erstellt.'); } public function edit(IpPool $ipPool): View { $this->authorize('update', $ipPool); return view('ip-pools.edit', [ 'pool' => $ipPool, 'types' => IpPoolType::cases(), ]); } public function update(Request $request, IpPool $ipPool): RedirectResponse { $this->authorize('update', $ipPool); $data = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'type' => ['required', Rule::enum(IpPoolType::class)], 'start_ip' => ['required', 'ip'], 'end_ip' => ['required', 'ip'], 'gateway' => ['nullable', 'ip'], 'cidr' => ['required', 'integer', 'min:8', 'max:32'], 'description' => ['nullable', 'string', 'max:500'], 'is_active' => ['boolean'], ]); $ipPool->update([ ...$data, 'is_active' => $request->boolean('is_active'), ]); return redirect()->route('ip-pools.index')->with('success', 'IP-Pool aktualisiert.'); } public function destroy(IpPool $ipPool): RedirectResponse { $this->authorize('delete', $ipPool); if ($ipPool->vms()->whereIn('status', ['pending', 'active'])->exists()) { return back()->withErrors(['pool' => 'Pool wird noch von aktiven VMs verwendet.']); } $ipPool->delete(); return redirect()->route('ip-pools.index')->with('success', 'IP-Pool gelöscht.'); } }