aprs.me/lib/aprsme_web/live/map_live/navigation.ex
Graham McIntire 1fc554eb5f
fix: Handle database ownership errors gracefully in LiveView tests
Add try-rescue blocks around database calls in LiveView mount functions
to handle DBConnection.OwnershipError gracefully during integration tests.

This prevents crashes when Wallaby creates LiveView processes that don't
have proper database connection ownership setup.

- Fix navigation.ex handle_callsign_tracking/4 database error handling
- Fix index.ex finalize_mount_assigns/2 database error handling
- Integration tests now pass without database ownership errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 14:29:35 -05:00

101 lines
3.3 KiB
Elixir

defmodule AprsmeWeb.MapLive.Navigation do
@moduledoc """
Handles geolocation, callsign tracking, and map navigation functionality.
"""
import Phoenix.Component, only: [assign: 3]
alias Aprsme.Packets
alias AprsmeWeb.MapLive.UrlParams
alias AprsmeWeb.MapLive.Utils
alias Phoenix.LiveView
alias Phoenix.LiveView.Socket
@doc """
Determine map location based on URL parameters and IP geolocation.
Returns {map_center, zoom, should_skip_initial_url_update}.
"""
@spec determine_map_location(map(), map()) :: {map(), integer(), boolean()}
def determine_map_location(params, session) do
{url_center, url_zoom} = UrlParams.parse_map_params(params)
has_explicit_url_params = UrlParams.has_explicit_url_params?(params)
case session["ip_geolocation"] do
%{"lat" => lat, "lng" => lng} when is_number(lat) and is_number(lng) ->
if has_explicit_url_params do
{url_center, url_zoom, false}
else
{%{lat: lat, lng: lng}, 11, true}
end
_ ->
{url_center, url_zoom, !has_explicit_url_params}
end
end
@doc """
Handle callsign tracking by finding the latest packet for the callsign.
Returns {final_map_center, final_map_zoom}.
"""
@spec handle_callsign_tracking(binary(), map(), integer(), boolean()) :: {map(), integer()}
def handle_callsign_tracking(tracked_callsign, map_center, map_zoom, has_explicit_url_params) do
if tracked_callsign != "" and not has_explicit_url_params do
try do
case Packets.get_latest_packet_for_callsign(tracked_callsign) do
%{lat: lat, lon: lon} when is_number(lat) and is_number(lon) ->
{%{lat: lat, lng: lon}, 12}
_ ->
{map_center, map_zoom}
end
rescue
# Handle database connection errors gracefully (especially in tests)
DBConnection.OwnershipError ->
{map_center, map_zoom}
_ ->
{map_center, map_zoom}
end
else
{map_center, map_zoom}
end
end
@doc """
Handle callsign search with validation.
"""
@spec handle_callsign_search(binary(), Socket.t()) :: {:noreply, Socket.t()}
def handle_callsign_search("", socket), do: {:noreply, socket}
def handle_callsign_search(callsign, socket) do
if Utils.valid_callsign?(callsign) do
# Navigate to the new URL structure with the callsign as a path param
{:noreply, LiveView.push_navigate(socket, to: "/#{callsign}")}
else
{:noreply, LiveView.put_flash(socket, :error, "Invalid callsign format")}
end
end
@doc """
Update map center and zoom to specific location.
"""
@spec update_and_zoom_to_location(Socket.t(), float(), float(), integer()) :: Socket.t()
def update_and_zoom_to_location(socket, lat, lng, zoom) do
socket
|> assign(:map_center, %{lat: lat, lng: lng})
|> assign(:map_zoom, zoom)
|> LiveView.push_event("zoom_to_location", %{lat: lat, lng: lng, zoom: zoom})
end
@doc """
Zoom to current location stored in socket.
"""
@spec zoom_to_current_location(Socket.t()) :: Socket.t()
def zoom_to_current_location(socket) do
LiveView.push_event(socket, "zoom_to_location", %{
lat: socket.assigns.map_center.lat,
lng: socket.assigns.map_center.lng,
zoom: socket.assigns.map_zoom
})
end
end