From c3becdac9f491f8d63ead658d84c12aa72157c20 Mon Sep 17 00:00:00 2001
From: Graham McIntire
Date: Sat, 11 Apr 2026 18:07:56 -0500
Subject: [PATCH] Show beacon submitter callsign, add donate link, prefer
8-char grids
- Add belongs_to :user on Beacon schema, preload in get_beacon!/1
- Show "Submitted by {callsign}" on beacon detail page
- Add NTMS donation link on the about page
- Change grid preference text to 8 characters (e.g. EM12kp37)
---
lib/microwaveprop/beacons.ex | 2 +-
lib/microwaveprop/beacons/beacon.ex | 3 +-
lib/microwaveprop/radio.ex | 8 +++---
lib/microwaveprop/radio/adif_import.ex | 11 ++++++--
lib/microwaveprop_web/live/about_live.ex | 9 ++++++
.../live/beacon_live/show.ex | 5 ++++
lib/microwaveprop_web/live/submit_live.ex | 28 +++++++++++++------
test/microwaveprop/radio/adif_import_test.exs | 4 ++-
8 files changed, 53 insertions(+), 17 deletions(-)
diff --git a/lib/microwaveprop/beacons.ex b/lib/microwaveprop/beacons.ex
index afa2051f..b73fa213 100644
--- a/lib/microwaveprop/beacons.ex
+++ b/lib/microwaveprop/beacons.ex
@@ -47,7 +47,7 @@ defmodule Microwaveprop.Beacons do
end
@doc "Gets a single beacon. Raises if not found."
- def get_beacon!(id), do: Repo.get!(Beacon, id)
+ def get_beacon!(id), do: Beacon |> Repo.get!(id) |> Repo.preload(:user)
@doc """
Creates a beacon. When a user is provided they are recorded as the
diff --git a/lib/microwaveprop/beacons/beacon.ex b/lib/microwaveprop/beacons/beacon.ex
index dc74be5d..cac204a5 100644
--- a/lib/microwaveprop/beacons/beacon.ex
+++ b/lib/microwaveprop/beacons/beacon.ex
@@ -152,7 +152,8 @@ defmodule Microwaveprop.Beacons.Beacon do
field :bearing, :string, default: "omni"
field :beamwidth_deg, :float
field :notes, :string
- field :user_id, :binary_id
+
+ belongs_to :user, Microwaveprop.Accounts.User
timestamps(type: :utc_datetime)
end
diff --git a/lib/microwaveprop/radio.ex b/lib/microwaveprop/radio.ex
index fa9c9bac..6f5717ae 100644
--- a/lib/microwaveprop/radio.ex
+++ b/lib/microwaveprop/radio.ex
@@ -363,10 +363,10 @@ defmodule Microwaveprop.Radio do
end
defp find_duplicate_contact(changeset) do
- s1 = Ecto.Changeset.get_field(changeset, :station1) |> to_string() |> String.upcase()
- s2 = Ecto.Changeset.get_field(changeset, :station2) |> to_string() |> String.upcase()
- g1 = Ecto.Changeset.get_field(changeset, :grid1) |> to_string() |> String.upcase()
- g2 = Ecto.Changeset.get_field(changeset, :grid2) |> to_string() |> String.upcase()
+ s1 = changeset |> Ecto.Changeset.get_field(:station1) |> to_string() |> String.upcase()
+ s2 = changeset |> Ecto.Changeset.get_field(:station2) |> to_string() |> String.upcase()
+ g1 = changeset |> Ecto.Changeset.get_field(:grid1) |> to_string() |> String.upcase()
+ g2 = changeset |> Ecto.Changeset.get_field(:grid2) |> to_string() |> String.upcase()
band = Ecto.Changeset.get_field(changeset, :band)
ts = Ecto.Changeset.get_field(changeset, :qso_timestamp)
diff --git a/lib/microwaveprop/radio/adif_import.ex b/lib/microwaveprop/radio/adif_import.ex
index 2740ed4f..e3f1cca0 100644
--- a/lib/microwaveprop/radio/adif_import.ex
+++ b/lib/microwaveprop/radio/adif_import.ex
@@ -86,7 +86,7 @@ defmodule Microwaveprop.Radio.AdifImport do
# Value starts right after the closing >
# Find the > after the tag
tag_text = String.slice(record_string, tag_start, 999)
- value_offset = tag_start + byte_size(String.split(tag_text, ">", parts: 2) |> List.first()) + 1
+ value_offset = tag_start + (tag_text |> String.split(">", parts: 2) |> List.first() |> byte_size()) + 1
value = String.slice(record_string, value_offset, size)
Map.put(acc, name, value)
@@ -229,7 +229,14 @@ defmodule Microwaveprop.Radio.AdifImport do
defp dedupe(rows, db_map) do
{accepted, _in_batch, duplicates} =
Enum.reduce(rows, {[], %{}, []}, fn row, {accepted, in_batch, dups} ->
- key = dedup_key(row.attrs["station1"], row.attrs["grid1"], row.attrs["station2"], row.attrs["grid2"], row.attrs["band"])
+ key =
+ dedup_key(
+ row.attrs["station1"],
+ row.attrs["grid1"],
+ row.attrs["station2"],
+ row.attrs["grid2"],
+ row.attrs["band"]
+ )
cond do
conflict_in_map?(db_map, key, row.timestamp) ->
diff --git a/lib/microwaveprop_web/live/about_live.ex b/lib/microwaveprop_web/live/about_live.ex
index 8bf1c546..aeb738b6 100644
--- a/lib/microwaveprop_web/live/about_live.ex
+++ b/lib/microwaveprop_web/live/about_live.ex
@@ -170,6 +170,15 @@ defmodule MicrowavepropWeb.AboutLive do
+
+
+ If this tool is useful to you, consider
+
+ donating to NTMS
+
+ to help keep the project running.
+
+
"""
diff --git a/lib/microwaveprop_web/live/beacon_live/show.ex b/lib/microwaveprop_web/live/beacon_live/show.ex
index 229b9be6..b9c3fef5 100644
--- a/lib/microwaveprop_web/live/beacon_live/show.ex
+++ b/lib/microwaveprop_web/live/beacon_live/show.ex
@@ -131,6 +131,11 @@ defmodule MicrowavepropWeb.BeaconLive.Show do
{@beacon.notes}
+
+
+ Submitted by
+ {@beacon.user.callsign}
+
"""
diff --git a/lib/microwaveprop_web/live/submit_live.ex b/lib/microwaveprop_web/live/submit_live.ex
index 56b5302f..bb7acb3c 100644
--- a/lib/microwaveprop_web/live/submit_live.ex
+++ b/lib/microwaveprop_web/live/submit_live.ex
@@ -5,8 +5,8 @@ defmodule MicrowavepropWeb.SubmitLive do
alias Microwaveprop.Propagation.BandConfig
alias Microwaveprop.Radio
- alias Microwaveprop.Radio.Contact
alias Microwaveprop.Radio.AdifImport
+ alias Microwaveprop.Radio.Contact
alias Microwaveprop.Radio.CsvImport
alias Microwaveprop.Workers.ContactWeatherEnqueueWorker
@@ -355,7 +355,7 @@ defmodule MicrowavepropWeb.SubmitLive do
- Be as specific as possible with grid squares (6 characters preferred, e.g. EM12kp).
+ Be as specific as possible with grid squares (8 characters preferred, e.g. EM12kp37).
@@ -375,7 +375,13 @@ defmodule MicrowavepropWeb.SubmitLive do
options={@mode_options}
required
/>
- <.input field={@form[:qso_timestamp]} type="datetime-local" label="Timestamp (UTC)" lang="en-GB" required />
+ <.input
+ field={@form[:qso_timestamp]}
+ type="datetime-local"
+ label="Timestamp (UTC)"
+ lang="en-GB"
+ required
+ />
<%= if @current_user do %>
@@ -416,7 +422,7 @@ defmodule MicrowavepropWeb.SubmitLive do
Timestamps in most formats accepted (e.g. 2024-06-15T14:30:00Z, 6/15/2024 2:30 PM, 2024-06-15 14:30). All times assumed UTC.
- Grid squares should be as detailed as possible (6 characters preferred, e.g. EM12kp)
+ Grid squares should be as detailed as possible (8 characters preferred, e.g. EM12kp37)
Band in MHz (e.g. 10000, 24000)
@@ -502,9 +508,10 @@ defmodule MicrowavepropWeb.SubmitLive do
-
- Required fields:
CALL, STATION_CALLSIGN (or OPERATOR),
- GRIDSQUARE, MY_GRIDSQUARE, QSO_DATE, TIME_ON,
- and FREQ or BAND
+ Required fields: CALL, STATION_CALLSIGN
+ (or OPERATOR), GRIDSQUARE, MY_GRIDSQUARE, QSO_DATE, TIME_ON,
+ and FREQ
+ or BAND
- Only microwave contacts (902 MHz and up) will be imported
- Sub-microwave contacts are silently skipped
@@ -512,7 +519,12 @@ defmodule MicrowavepropWeb.SubmitLive do
-