From b4f85bf12c698d5060dcfeb96a4d2f6c680bed1e Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Thu, 19 Feb 2026 13:19:58 -0600 Subject: [PATCH] Fix callsign registration to be case-insensitive Users could register duplicate callsigns with different casing (e.g., "w1aw" and "W1AW") because the database unique index was case-sensitive. Additionally, live validation showed false "already taken" errors on every keystroke. Changes: - Add case-insensitive unique index using lower(callsign) - Skip callsign uniqueness validation during live form changes - Add test verifying case-insensitive uniqueness enforcement --- lib/aprsme/accounts.ex | 2 +- ...9191058_make_callsign_case_insensitive.exs | 11 ++++++++++ .../live/user_registration_live_test.exs | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 priv/repo/migrations/20260219191058_make_callsign_case_insensitive.exs diff --git a/lib/aprsme/accounts.ex b/lib/aprsme/accounts.ex index f9ee88e..8347a9f 100644 --- a/lib/aprsme/accounts.ex +++ b/lib/aprsme/accounts.ex @@ -103,7 +103,7 @@ defmodule Aprsme.Accounts do """ def change_user_registration(%User{} = user, attrs \\ %{}) do - User.registration_changeset(user, attrs, hash_password: false, validate_email: false) + User.registration_changeset(user, attrs, hash_password: false, validate_email: false, validate_callsign: false) end ## Settings diff --git a/priv/repo/migrations/20260219191058_make_callsign_case_insensitive.exs b/priv/repo/migrations/20260219191058_make_callsign_case_insensitive.exs new file mode 100644 index 0000000..1960406 --- /dev/null +++ b/priv/repo/migrations/20260219191058_make_callsign_case_insensitive.exs @@ -0,0 +1,11 @@ +defmodule Aprsme.Repo.Migrations.MakeCallsignCaseInsensitive do + use Ecto.Migration + + def change do + # Drop the existing case-sensitive unique index + drop unique_index(:users, [:callsign]) + + # Create a case-insensitive unique index using LOWER() + create unique_index(:users, ["lower(callsign)"], name: :users_callsign_lower_index) + end +end diff --git a/test/aprsme_web/live/user_registration_live_test.exs b/test/aprsme_web/live/user_registration_live_test.exs index 7487b3e..fc859db 100644 --- a/test/aprsme_web/live/user_registration_live_test.exs +++ b/test/aprsme_web/live/user_registration_live_test.exs @@ -69,6 +69,26 @@ defmodule AprsmeWeb.UserRegistrationLiveTest do assert result =~ "has already been taken" end + + test "renders errors for duplicated callsign (case-insensitive)", %{conn: conn} do + {:ok, lv, _html} = live(conn, ~p"/users/register", on_error: :warn) + + _user = user_fixture(%{callsign: "W1AW"}) + + # Try to register with same callsign in different case + result = + lv + |> form("#registration_form", + user: %{ + "email" => unique_user_email(), + "callsign" => "w1aw", + "password" => "valid_password123" + } + ) + |> render_submit() + + assert result =~ "has already been taken" + end end describe "registration navigation" do