Network presence no longer frees a device slot

This commit is contained in:
2026-08-21 13:07:16 -04:00
parent a74818bdaf
commit 655d8dd50c

View File

@@ -164,28 +164,30 @@ class PortalController extends Controller
return Inertia::render('Unifi/PortalDenied', ['reason' => 'No WiFi access configured for your account.']); return Inertia::render('Unifi/PortalDenied', ['reason' => 'No WiFi access configured for your account.']);
} }
// Check device limit /*
$activeSessions = PortalSession::where('user_id', $user->id) * Presence is NOT the question — a live authorization is.
->where('is_active', true) *
->get(); * This used to walk the user's sessions and mark any device UniFi did not
* currently see as stale, freeing its slot. But UniFi holds an
* authorization for its whole window regardless of whether the device is
* in the building, so a phone that went home had its slot freed while
* still being authorized: the owner then authorized a second device and
* one of the two was an orphan nothing tracked. The longer
* session_minutes is — and it is now meant to be a term — the more of
* those accumulate.
*
* Slots are now freed by eviction, by expiry, or by ReconcilePortal.
*/
$live = PortalSession::live()->where('user_id', $user->id)->get();
foreach ($activeSessions as $session) { // The same device coming back is a renewal, not a new device: it keeps
if ($session->mac_address === $clientMac) { // its slot and its row, and simply gets a fresh window.
// Same device reconnecting — refresh $existing = $live->firstWhere('mac_address', $clientMac);
$session->update(['is_active' => false]);
continue;
}
// Check if other device is still actually connected
if (! $unifi->isClientConnected($session->mac_address)) {
$session->update(['is_active' => false]); // stale session
}
}
$activeCount = PortalSession::where('user_id', $user->id)->where('is_active', true)->count(); if (! $existing && $live->count() >= $mapping->max_devices) {
if ($activeCount >= $mapping->max_devices) {
return Inertia::render('Unifi/PortalDenied', [ return Inertia::render('Unifi/PortalDenied', [
'reason' => "You already have {$activeCount} device(s) connected (limit: {$mapping->max_devices}).", 'reason' => "You already have {$live->count()} device(s) connected (limit: {$mapping->max_devices}).",
'sessions' => $activeSessions->map(fn ($s) => [ 'sessions' => $live->map(fn ($s) => [
'id' => $s->id, 'id' => $s->id,
'mac' => $s->mac_address, 'mac' => $s->mac_address,
'hostname' => $s->device_hostname, 'hostname' => $s->device_hostname,
@@ -200,10 +202,9 @@ class PortalController extends Controller
$minutes = $mapping->session_minutes; $minutes = $mapping->session_minutes;
$unifi->authorizeGuest($clientMac, $minutes); $unifi->authorizeGuest($clientMac, $minutes);
// Record the session PortalSession::updateOrCreate(
PortalSession::create([ ['user_id' => $user->id, 'mac_address' => $clientMac],
'user_id' => $user->id, [
'mac_address' => $clientMac,
'device_hostname' => $request->input('hostname'), 'device_hostname' => $request->input('hostname'),
'device_os' => $request->input('os'), 'device_os' => $request->input('os'),
'device_type' => $request->input('dev_cat'), 'device_type' => $request->input('dev_cat'),
@@ -213,7 +214,8 @@ class PortalController extends Controller
'is_active' => true, 'is_active' => true,
'authorized_at' => now(), 'authorized_at' => now(),
'expires_at' => now()->addMinutes($minutes), 'expires_at' => now()->addMinutes($minutes),
]); ]
);
// Redirect to the original URL the user was trying to reach. // Redirect to the original URL the user was trying to reach.
// //