feat: initial commit — UniFi snap-in package
Full UniFi dashboard snap-in including: - WiFi/client/device stats with time-series snapshots - Client Dashboard with traffic, satisfaction, signal, download charts - Webhook alerting with debounced offline/online detection - AP snapshot collection, client snapshot collection - Device classification (type and OS) from OUI/hostname heuristics - Webhook cooldown, templates, and multi-platform delivery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
117
src/Http/Controllers/UnifiSettingsController.php
Normal file
117
src/Http/Controllers/UnifiSettingsController.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Dashboard\Unifi\Http\Controllers;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Dashboard\Unifi\Services\UnifiApiClient;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class UnifiSettingsController extends Controller
|
||||
{
|
||||
public function edit()
|
||||
{
|
||||
return Inertia::render('Unifi/Settings', [
|
||||
'controllerUrl' => Setting::get('unifi.controller_url', ''),
|
||||
'username' => Setting::get('unifi.username', ''),
|
||||
'hasPassword' => (bool) Setting::get('unifi.password'),
|
||||
'hasApiKey' => (bool) Setting::get('unifi.api_key'),
|
||||
'site' => Setting::get('unifi.site', 'default'),
|
||||
'pollInterval' => (int) Setting::get('unifi.poll_interval', 30),
|
||||
'cacheTtl' => (int) Setting::get('unifi.cache_ttl', 30),
|
||||
'retentionDays' => (int) Setting::get('unifi.retention_days', 30),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'controller_url' => 'required|url|max:500',
|
||||
'username' => 'nullable|string|max:255',
|
||||
'password' => 'nullable|string|max:255',
|
||||
'api_key' => 'nullable|string|max:500',
|
||||
'site' => 'required|string|max:100',
|
||||
'poll_interval' => 'nullable|integer|min:5|max:300',
|
||||
'cache_ttl' => 'nullable|integer|min:5|max:300',
|
||||
'retention_days' => 'nullable|integer|min:1|max:365',
|
||||
]);
|
||||
|
||||
Setting::set('unifi.controller_url', rtrim($request->controller_url, '/'));
|
||||
Setting::set('unifi.site', $request->site);
|
||||
|
||||
// Save the chosen auth method and clear the other
|
||||
Setting::set('unifi.username', $request->username ?? '');
|
||||
if ($request->password && $request->password !== '••••••••') {
|
||||
Setting::set('unifi.password', $request->password);
|
||||
} elseif (! $request->username) {
|
||||
Setting::set('unifi.password', ''); // clear password when switching to API key mode
|
||||
}
|
||||
if ($request->api_key && $request->api_key !== '••••••••') {
|
||||
Setting::set('unifi.api_key', $request->api_key);
|
||||
} elseif ($request->username) {
|
||||
Setting::set('unifi.api_key', ''); // clear API key when switching to local account mode
|
||||
}
|
||||
|
||||
if ($request->has('poll_interval')) Setting::set('unifi.poll_interval', $request->poll_interval ?? 30);
|
||||
if ($request->has('cache_ttl')) Setting::set('unifi.cache_ttl', $request->cache_ttl ?? 30);
|
||||
if ($request->has('retention_days')) Setting::set('unifi.retention_days', $request->retention_days ?? 30);
|
||||
|
||||
// Clear cached sessions so new credentials take effect
|
||||
\Illuminate\Support\Facades\Cache::forget('unifi:session:' . md5(rtrim($request->controller_url, '/') . $request->username));
|
||||
\Illuminate\Support\Facades\Cache::forget('unifi:api_prefix:' . md5(rtrim($request->controller_url, '/')));
|
||||
|
||||
return back()->with('success', 'UniFi settings saved.');
|
||||
}
|
||||
|
||||
public function testConnection(UnifiApiClient $unifi)
|
||||
{
|
||||
try {
|
||||
$info = $unifi->testConnection();
|
||||
$version = $info[0]['version'] ?? 'unknown';
|
||||
return response()->json(['ok' => true, 'version' => $version]);
|
||||
} catch (\Throwable $e) {
|
||||
return response()->json(['ok' => false, 'error' => $e->getMessage()], 422);
|
||||
}
|
||||
}
|
||||
|
||||
public function fetchSites(Request $request, UnifiApiClient $unifi)
|
||||
{
|
||||
$request->validate([
|
||||
'controller_url' => 'required|url',
|
||||
]);
|
||||
|
||||
$url = rtrim($request->controller_url, '/');
|
||||
$user = $request->input('username', '');
|
||||
$pass = $request->input('password', '');
|
||||
$key = $request->input('api_key', '');
|
||||
|
||||
// Use saved credentials if placeholders sent
|
||||
if ($pass === '••••••••') $pass = Setting::get('unifi.password', '');
|
||||
if ($key === '••••••••') $key = Setting::get('unifi.api_key', '');
|
||||
|
||||
try {
|
||||
$sites = $unifi->getSites($url, $user ?: null, $pass ?: null, $key ?: null);
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'sites' => collect($sites)->map(fn ($s) => [
|
||||
'name' => $s['name'] ?? 'default',
|
||||
'desc' => $s['desc'] ?? $s['name'] ?? 'Default',
|
||||
])->values(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
$hint = "Tried URL: {$url}. ";
|
||||
if (str_contains($url, 'unifi.ui.com')) {
|
||||
$hint .= "Use your console's direct URL (*.id.ui.direct or local IP) instead of unifi.ui.com.";
|
||||
} elseif (! $user && ! $key) {
|
||||
$hint .= "Enter either a local account username/password or an API key.";
|
||||
} else {
|
||||
$hint .= $user
|
||||
? "Check that the local account credentials are correct."
|
||||
: "The API key may be read-only. Try using a local admin account instead.";
|
||||
}
|
||||
|
||||
return response()->json(['ok' => false, 'error' => $e->getMessage(), 'hint' => $hint], 422);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user