|
|
|
|
@@ -149,8 +149,18 @@ class WifiController extends Controller
|
|
|
|
|
$name = $networksById[$nconfId]['name'] ?? null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Match by unifi_id, or by passphrase for a held embedded record re-appearing
|
|
|
|
|
// Match in priority order:
|
|
|
|
|
// 1. by current unifi_id (already-synced row)
|
|
|
|
|
// 2. by name within this wlan (catches rotation: passphrase
|
|
|
|
|
// changed → synthetic id changed → row identity unchanged)
|
|
|
|
|
// 3. by passphrase among held rows (legacy fallback for
|
|
|
|
|
// cases where name wasn't ingested)
|
|
|
|
|
$record = UnifiPpsk::where('unifi_id', $uid)->first()
|
|
|
|
|
?? ($name
|
|
|
|
|
? UnifiPpsk::where('wlan_id', $wlanId)->where('name', $name)
|
|
|
|
|
->orderByRaw("FIELD(state, 'active', 'held')")
|
|
|
|
|
->first()
|
|
|
|
|
: null)
|
|
|
|
|
?? UnifiPpsk::where('wlan_id', $wlanId)
|
|
|
|
|
->where('x_passphrase', $pass)
|
|
|
|
|
->where('state', 'held')
|
|
|
|
|
@@ -174,8 +184,8 @@ class WifiController extends Controller
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only mark as held when we have confirmed live IDs —
|
|
|
|
|
// never wipe on an empty API response (prevents false-holds on API failures)
|
|
|
|
|
// Mark non-matching active rows as held — but ONLY if there's no
|
|
|
|
|
// other active row with the same name we just reconnected.
|
|
|
|
|
if (! empty($liveIds)) {
|
|
|
|
|
UnifiPpsk::where('wlan_id', $wlanId)
|
|
|
|
|
->where('state', 'active')
|
|
|
|
|
@@ -184,6 +194,47 @@ class WifiController extends Controller
|
|
|
|
|
->update(['state' => 'held', 'unifi_id' => null]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For each active row, salvage any rotate_password / schedule
|
|
|
|
|
// settings from the held tombstones with the same name BEFORE
|
|
|
|
|
// we prune them. Otherwise a row that had rotate=on loses the
|
|
|
|
|
// flag every time a rotation changes its synthetic id.
|
|
|
|
|
$activeRows = UnifiPpsk::where('wlan_id', $wlanId)
|
|
|
|
|
->where('state', 'active')
|
|
|
|
|
->whereNotNull('name')
|
|
|
|
|
->get();
|
|
|
|
|
foreach ($activeRows as $active) {
|
|
|
|
|
$heldWithSettings = UnifiPpsk::where('wlan_id', $wlanId)
|
|
|
|
|
->where('state', 'held')
|
|
|
|
|
->where('name', $active->name)
|
|
|
|
|
->where(fn ($q) => $q
|
|
|
|
|
->where('rotate_password', true)
|
|
|
|
|
->orWhereNotNull('schedule'))
|
|
|
|
|
->orderByDesc('updated_at')
|
|
|
|
|
->first();
|
|
|
|
|
if (! $heldWithSettings) continue;
|
|
|
|
|
|
|
|
|
|
$patch = [];
|
|
|
|
|
if ($heldWithSettings->rotate_password && ! $active->rotate_password) {
|
|
|
|
|
$patch['rotate_password'] = true;
|
|
|
|
|
}
|
|
|
|
|
if ($heldWithSettings->schedule && ! $active->schedule) {
|
|
|
|
|
$patch['schedule'] = $heldWithSettings->schedule;
|
|
|
|
|
}
|
|
|
|
|
if ($patch) $active->update($patch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prune obsolete held rows: any held row whose name matches an
|
|
|
|
|
// active row in the same wlan is a stale tombstone — its
|
|
|
|
|
// settings have been salvaged above, and its data has been
|
|
|
|
|
// superseded by the active one.
|
|
|
|
|
$activeNames = $activeRows->pluck('name')->filter()->unique();
|
|
|
|
|
if ($activeNames->isNotEmpty()) {
|
|
|
|
|
UnifiPpsk::where('wlan_id', $wlanId)
|
|
|
|
|
->where('state', 'held')
|
|
|
|
|
->whereIn('name', $activeNames)
|
|
|
|
|
->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$dbRecords = UnifiPpsk::where('wlan_id', $wlanId)
|
|
|
|
|
->orderByRaw("FIELD(state, 'active', 'held')")
|
|
|
|
|
->orderBy('name')
|
|
|
|
|
|