From 01ee6eada5c44ada31a49816cb2e3f1cca7cfd85 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sun, 22 Jun 2025 16:21:17 -0500 Subject: [PATCH] api tweaks --- lib/aprs_web/live/api_docs_live.ex | 290 +++++++++++------------------ 1 file changed, 105 insertions(+), 185 deletions(-) diff --git a/lib/aprs_web/live/api_docs_live.ex b/lib/aprs_web/live/api_docs_live.ex index 670be32..261315d 100644 --- a/lib/aprs_web/live/api_docs_live.ex +++ b/lib/aprs_web/live/api_docs_live.ex @@ -44,12 +44,12 @@ defmodule AprsWeb.ApiDocsLive do @impl true def handle_info({:call_api, callsign}, socket) do - case call_api(callsign) do - {:ok, result} -> + case make_http_request(callsign) do + {:ok, json_result} -> {:noreply, socket |> assign(loading: false) - |> assign(api_result: result)} + |> assign(api_result: json_result)} {:error, error_message} -> {:noreply, @@ -59,13 +59,23 @@ defmodule AprsWeb.ApiDocsLive do end end - defp call_api(callsign) do - # Use the same validation and lookup logic as the API controller + defp make_http_request(callsign) do alias Aprs.Packets - # Validate callsign format - if validate_callsign_format(callsign) do - # Try to get the most recent packet for this callsign + # Validate callsign format (same as controller) + callsign_regex = ~r/^[A-Z0-9]{1,3}[0-9][A-Z]{1,4}(-[0-9]{1,2})?$/ + + if not String.match?(callsign, callsign_regex) or String.length(callsign) > 12 do + response = %{ + "error" => %{ + "message" => "Invalid callsign format", + "code" => "bad_request" + } + } + + {:ok, Jason.encode!(response, pretty: true)} + else + # Get packet data (same logic as controller) thirty_days_ago = DateTime.add(DateTime.utc_now(), -30, :day) opts = %{ @@ -76,88 +86,91 @@ defmodule AprsWeb.ApiDocsLive do case Packets.get_recent_packets(opts) do [] -> - {:ok, %{"data" => nil, "message" => "No packets found for callsign #{callsign}"}} + response = %{ + "data" => nil, + "message" => "No packets found for callsign #{callsign}" + } + + {:ok, Jason.encode!(response, pretty: true)} [packet | _] -> - # Format the packet data similar to the JSON view - packet_data = format_packet_for_display(packet) - {:ok, %{"data" => packet_data}} + # Format packet data using the same logic as CallsignJSON + packet_data = %{ + "id" => packet.id, + "callsign" => format_callsign(packet.base_callsign, packet.ssid), + "base_callsign" => packet.base_callsign, + "ssid" => packet.ssid, + "sender" => packet.sender, + "destination" => packet.destination, + "path" => packet.path, + "data_type" => packet.data_type, + "information_field" => packet.information_field, + "raw_packet" => packet.raw_packet, + "received_at" => packet.received_at, + "region" => packet.region, + "position" => format_position(packet), + "symbol" => format_symbol(packet), + "comment" => packet.comment, + "timestamp" => packet.timestamp, + "aprs_messaging" => packet.aprs_messaging, + "weather" => format_weather(packet), + "equipment" => format_equipment(packet), + "message" => format_message(packet), + "has_position" => packet.has_position, + "inserted_at" => packet.inserted_at, + "updated_at" => packet.updated_at + } + + response = %{"data" => packet_data} + {:ok, Jason.encode!(response, pretty: true)} {:error, _reason} -> - {:error, "Database error occurred while fetching packet data"} + response = %{ + "error" => %{ + "message" => "Database error occurred", + "code" => "internal_server_error" + } + } + + {:ok, Jason.encode!(response, pretty: true)} end - else - {:error, "Invalid callsign format"} end rescue error -> - {:error, "An error occurred: #{inspect(error)}"} - end - - defp validate_callsign_format(callsign) do - # Same validation as in the controller - callsign_regex = ~r/^[A-Z0-9]{1,3}[0-9][A-Z]{1,4}(-[0-9]{1,2})?$/ - String.match?(callsign, callsign_regex) and String.length(callsign) <= 12 - end - - defp format_packet_for_display(%Aprs.Packet{} = packet) do - %{ - "id" => packet.id, - "callsign" => format_callsign(packet.base_callsign, packet.ssid), - "base_callsign" => packet.base_callsign, - "ssid" => packet.ssid, - "sender" => packet.sender, - "destination" => packet.destination, - "path" => packet.path, - "data_type" => packet.data_type, - "information_field" => packet.information_field, - "raw_packet" => packet.raw_packet, - "received_at" => packet.received_at, - "region" => packet.region, - "position" => position_data(packet), - "symbol" => symbol_data(packet), - "comment" => packet.comment, - "timestamp" => packet.timestamp, - "aprs_messaging" => packet.aprs_messaging, - "weather" => weather_data(packet), - "equipment" => equipment_data(packet), - "message" => message_data(packet), - "has_position" => packet.has_position, - "inserted_at" => packet.inserted_at, - "updated_at" => packet.updated_at - } + {:error, "Request error: #{inspect(error)}"} end defp format_callsign(base_callsign, nil), do: base_callsign defp format_callsign(base_callsign, "0"), do: base_callsign defp format_callsign(base_callsign, ssid), do: "#{base_callsign}-#{ssid}" - defp position_data(%Aprs.Packet{has_position: false}), do: nil - defp position_data(%Aprs.Packet{lat: nil, lon: nil}), do: nil + defp format_position(%{has_position: false}), do: nil + defp format_position(%{lat: nil, lon: nil}), do: nil - defp position_data(%Aprs.Packet{} = packet) do - base_position = %{ - "latitude" => to_float(packet.lat), - "longitude" => to_float(packet.lon) - } + defp format_position(packet) do + base = + %{ + "latitude" => to_float(packet.lat), + "longitude" => to_float(packet.lon) + } + |> maybe_add("course", packet.course) + |> maybe_add("speed", packet.speed) + |> maybe_add("altitude", packet.altitude) - base_position - |> maybe_add("course", packet.course) - |> maybe_add("speed", packet.speed) - |> maybe_add("altitude", packet.altitude) + if map_size(base) == 2, do: base, else: base end - defp symbol_data(%Aprs.Packet{symbol_code: nil, symbol_table_id: nil}), do: nil + defp format_symbol(%{symbol_code: nil, symbol_table_id: nil}), do: nil - defp symbol_data(%Aprs.Packet{} = packet) do + defp format_symbol(packet) do %{ "code" => packet.symbol_code, "table_id" => packet.symbol_table_id } end - defp weather_data(%Aprs.Packet{} = packet) do - weather_data = + defp format_weather(packet) do + weather = %{} |> maybe_add("temperature", packet.temperature) |> maybe_add("humidity", packet.humidity) @@ -169,31 +182,28 @@ defmodule AprsWeb.ApiDocsLive do |> maybe_add("rain_24h", packet.rain_24h) |> maybe_add("rain_since_midnight", packet.rain_since_midnight) - case weather_data do - empty when empty == %{} -> nil - data -> data - end + if map_size(weather) == 0, do: nil, else: weather end - defp equipment_data(%Aprs.Packet{} = packet) do - equipment_data = + defp format_equipment(packet) do + equipment = %{} |> maybe_add("manufacturer", packet.manufacturer) |> maybe_add("equipment_type", packet.equipment_type) - case equipment_data do - empty when empty == %{} -> nil - data -> data - end + if map_size(equipment) == 0, do: nil, else: equipment end - defp message_data(%Aprs.Packet{addressee: nil, message_text: nil, message_number: nil}), do: nil + defp format_message(%{addressee: nil, message_text: nil, message_number: nil}), do: nil - defp message_data(%Aprs.Packet{} = packet) do - %{} - |> maybe_add("addressee", packet.addressee) - |> maybe_add("text", packet.message_text) - |> maybe_add("number", packet.message_number) + defp format_message(packet) do + message = + %{} + |> maybe_add("addressee", packet.addressee) + |> maybe_add("text", packet.message_text) + |> maybe_add("number", packet.message_number) + + if map_size(message) == 0, do: nil, else: message end defp maybe_add(map, _key, nil), do: map @@ -719,96 +729,22 @@ defmodule AprsWeb.ApiDocsLive do

API Response

- <%= if @api_result["data"] do %> - -
-
- - - - Packet Found! -
+
+
+ + + + JSON Response +
-
-
-
- Callsign: - {@api_result["data"]["callsign"]} -
-
- Received: - - {format_datetime(@api_result["data"]["received_at"])} - -
- <%= if @api_result["data"]["position"] do %> -
- Position: - - {Float.round(@api_result["data"]["position"]["latitude"], 4)}, {Float.round( - @api_result["data"]["position"]["longitude"], - 4 - )} - -
- <% end %> - <%= if @api_result["data"]["comment"] do %> -
- Comment: - {@api_result["data"]["comment"]} -
- <% end %> -
-
- - -
- - View Raw JSON Response - -
-
<%= Jason.encode!(@api_result, pretty: true) %>
-
-
+
+
<%= @api_result %>
- <% else %> - -
-
- - - - No Packets Found -
-

{@api_result["message"]}

- - -
- - View Raw JSON Response - -
-
<%= Jason.encode!(@api_result, pretty: true) %>
-
-
-
- <% end %> +
<% end %>
@@ -844,20 +780,4 @@ defmodule AprsWeb.ApiDocsLive do """ end - - defp format_datetime(nil), do: "N/A" - - defp format_datetime(datetime_string) do - case DateTime.from_iso8601(datetime_string) do - {:ok, datetime, _} -> - datetime - |> DateTime.shift_zone!("America/New_York") - |> Calendar.strftime("%Y-%m-%d %H:%M:%S %Z") - - _ -> - datetime_string - end - rescue - _ -> datetime_string - end end