Link to existing contact on duplicate submission
Return the conflicting contact from create_contact so the UI can redirect to it with a flash message instead of just showing a form error.
This commit is contained in:
parent
231f1d9a14
commit
25c703401b
3 changed files with 27 additions and 20 deletions
|
|
@ -338,11 +338,8 @@ defmodule Microwaveprop.Radio do
|
||||||
grid1 = Ecto.Changeset.get_change(changeset, :grid1)
|
grid1 = Ecto.Changeset.get_change(changeset, :grid1)
|
||||||
grid2 = Ecto.Changeset.get_change(changeset, :grid2)
|
grid2 = Ecto.Changeset.get_change(changeset, :grid2)
|
||||||
|
|
||||||
if duplicate_contact_exists?(changeset) do
|
if existing = find_duplicate_contact(changeset) do
|
||||||
changeset =
|
{:error, :duplicate, existing}
|
||||||
Ecto.Changeset.add_error(changeset, :station1, "a matching contact already exists within the last hour")
|
|
||||||
|
|
||||||
{:error, %{changeset | action: :insert}}
|
|
||||||
else
|
else
|
||||||
case {Maidenhead.to_latlon(grid1), Maidenhead.to_latlon(grid2)} do
|
case {Maidenhead.to_latlon(grid1), Maidenhead.to_latlon(grid2)} do
|
||||||
{{:ok, {lat1, lon1}}, {:ok, {lat2, lon2}}} ->
|
{{:ok, {lat1, lon1}}, {:ok, {lat2, lon2}}} ->
|
||||||
|
|
@ -365,7 +362,7 @@ defmodule Microwaveprop.Radio do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp duplicate_contact_exists?(changeset) do
|
defp find_duplicate_contact(changeset) do
|
||||||
s1 = Ecto.Changeset.get_field(changeset, :station1) |> to_string() |> String.upcase()
|
s1 = Ecto.Changeset.get_field(changeset, :station1) |> to_string() |> String.upcase()
|
||||||
s2 = Ecto.Changeset.get_field(changeset, :station2) |> 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()
|
g1 = Ecto.Changeset.get_field(changeset, :grid1) |> to_string() |> String.upcase()
|
||||||
|
|
@ -377,8 +374,8 @@ defmodule Microwaveprop.Radio do
|
||||||
min_ts = DateTime.add(ts, -@dedup_window_seconds, :second)
|
min_ts = DateTime.add(ts, -@dedup_window_seconds, :second)
|
||||||
max_ts = DateTime.add(ts, @dedup_window_seconds, :second)
|
max_ts = DateTime.add(ts, @dedup_window_seconds, :second)
|
||||||
|
|
||||||
# Query for contacts with same band in the time window, then check
|
expected_pair = Enum.sort([{s1, g1}, {s2, g2}])
|
||||||
# station/grid pair match (order-independent) in Elixir
|
|
||||||
from(c in Contact,
|
from(c in Contact,
|
||||||
where:
|
where:
|
||||||
c.band == ^band_decimal and
|
c.band == ^band_decimal and
|
||||||
|
|
@ -387,11 +384,14 @@ defmodule Microwaveprop.Radio do
|
||||||
c.flagged_invalid == false
|
c.flagged_invalid == false
|
||||||
)
|
)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|> Enum.any?(fn c ->
|
|> Enum.find(fn c ->
|
||||||
a = {String.upcase(c.station1), String.upcase(c.grid1)}
|
pair =
|
||||||
b = {String.upcase(c.station2), String.upcase(c.grid2)}
|
Enum.sort([
|
||||||
pair = Enum.sort([a, b])
|
{String.upcase(c.station1), String.upcase(c.grid1)},
|
||||||
pair == Enum.sort([{s1, g1}, {s2, g2}])
|
{String.upcase(c.station2), String.upcase(c.grid2)}
|
||||||
|
])
|
||||||
|
|
||||||
|
pair == expected_pair
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,15 @@ defmodule MicrowavepropWeb.SubmitLive do
|
||||||
|> put_flash(:info, "Contact submitted successfully!")
|
|> put_flash(:info, "Contact submitted successfully!")
|
||||||
|> push_navigate(to: ~p"/contacts/#{contact.id}")}
|
|> push_navigate(to: ~p"/contacts/#{contact.id}")}
|
||||||
|
|
||||||
|
{:error, :duplicate, existing} ->
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> put_flash(
|
||||||
|
:error,
|
||||||
|
"A matching contact already exists: #{existing.station1} ↔ #{existing.station2} on #{existing.band} MHz"
|
||||||
|
)
|
||||||
|
|> push_navigate(to: ~p"/contacts/#{existing.id}")}
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
{:noreply, assign(socket, form: to_form(changeset))}
|
{:noreply, assign(socket, form: to_form(changeset))}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,10 @@ defmodule Microwaveprop.Radio.ContactSubmissionTest do
|
||||||
describe "create_contact/1 deduplication" do
|
describe "create_contact/1 deduplication" do
|
||||||
alias Microwaveprop.Radio
|
alias Microwaveprop.Radio
|
||||||
|
|
||||||
test "rejects duplicate contact within 1-hour window" do
|
test "rejects duplicate and returns the existing contact" do
|
||||||
assert {:ok, _contact} = Radio.create_contact(@valid_attrs)
|
assert {:ok, original} = Radio.create_contact(@valid_attrs)
|
||||||
|
|
||||||
assert {:error, changeset} = Radio.create_contact(@valid_attrs)
|
assert {:error, :duplicate, ^original} = Radio.create_contact(@valid_attrs)
|
||||||
assert "a matching contact already exists within the last hour" in errors_on(changeset).station1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "allows same stations on a different band" do
|
test "allows same stations on a different band" do
|
||||||
|
|
@ -121,11 +120,10 @@ defmodule Microwaveprop.Radio.ContactSubmissionTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "detects duplicates regardless of station order" do
|
test "detects duplicates regardless of station order" do
|
||||||
assert {:ok, _} = Radio.create_contact(@valid_attrs)
|
assert {:ok, original} = Radio.create_contact(@valid_attrs)
|
||||||
|
|
||||||
swapped = %{@valid_attrs | station1: "K5TR", grid1: "EM00", station2: "W5XD", grid2: "EM12"}
|
swapped = %{@valid_attrs | station1: "K5TR", grid1: "EM00", station2: "W5XD", grid2: "EM12"}
|
||||||
assert {:error, changeset} = Radio.create_contact(swapped)
|
assert {:error, :duplicate, ^original} = Radio.create_contact(swapped)
|
||||||
assert "a matching contact already exists within the last hour" in errors_on(changeset).station1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue