add forgiving API key validation with inline errors

Add KeyValidation module for format-checking API keys before
attempting connections. Auto-strips whitespace, detects common
mistakes (e.g. pasting a Stripe publishable key), and returns
helpful error messages.

Inline field errors across all three entry points:
- Setup wizard: provider + Stripe keys
- Admin provider form: simplified to single Connect button
- Email settings: per-field errors instead of flash toasts

Also: plain text inputs for all API keys (not password fields),
accessible error states (aria-invalid, role=alert, thick border,
bold text), inner_block slot declaration on error component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-04 12:17:56 +00:00
parent e139a75b69
commit 76cff0494e
10 changed files with 557 additions and 216 deletions

View File

@@ -167,14 +167,6 @@ defmodule BerrypodWeb.Admin.ProvidersTest do
assert html =~ "Connect to Printify"
end
test "test connection shows error when no api key", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/providers/new")
html = render_click(view, "test_connection")
assert html =~ "Please enter your API key"
end
test "saves new connection", %{conn: conn} do
expect(MockProvider, :test_connection, fn _conn ->
{:ok, %{shop_name: "My Printify Shop", shop_id: 12345}}
@@ -196,55 +188,6 @@ defmodule BerrypodWeb.Admin.ProvidersTest do
end
end
describe "form - test connection" do
setup %{conn: conn, user: user} do
Application.put_env(:berrypod, :provider_modules, %{
"printify" => MockProvider
})
on_exit(fn -> Application.delete_env(:berrypod, :provider_modules) end)
%{conn: log_in_user(conn, user)}
end
test "shows success when connection is valid", %{conn: conn} do
expect(MockProvider, :test_connection, fn _conn ->
{:ok, %{shop_name: "My Printify Shop", shop_id: 12345}}
end)
{:ok, view, _html} = live(conn, ~p"/admin/providers/new")
# Validate first to set pending_api_key
view
|> form("#provider-form", %{
"provider_connection" => %{"api_key" => "valid_key_123"}
})
|> render_change()
html = render_click(view, "test_connection")
assert html =~ "Connected to My Printify Shop"
end
test "shows error when connection fails", %{conn: conn} do
expect(MockProvider, :test_connection, fn _conn ->
{:error, :unauthorized}
end)
{:ok, view, _html} = live(conn, ~p"/admin/providers/new")
view
|> form("#provider-form", %{
"provider_connection" => %{"api_key" => "bad_key"}
})
|> render_change()
html = render_click(view, "test_connection")
assert html =~ "doesn&#39;t seem to be valid"
end
end
describe "form - edit" do
setup %{conn: conn, user: user} do
connection =