Harden /submit route for production
- Defensive grid-to-coordinate resolution in create_qso (case instead of crash on match failure) - Log warning when Oban weather enqueue fails instead of silently dropping - Add 30s per-session submission cooldown to prevent rapid-fire submissions
This commit is contained in:
parent
4468fb3b61
commit
fe3c8812a0
2 changed files with 48 additions and 19 deletions
|
|
@ -137,17 +137,21 @@ defmodule Microwaveprop.Radio do
|
|||
grid1 = Ecto.Changeset.get_change(changeset, :grid1)
|
||||
grid2 = Ecto.Changeset.get_change(changeset, :grid2)
|
||||
|
||||
{:ok, {lat1, lon1}} = Maidenhead.to_latlon(grid1)
|
||||
{:ok, {lat2, lon2}} = Maidenhead.to_latlon(grid2)
|
||||
case {Maidenhead.to_latlon(grid1), Maidenhead.to_latlon(grid2)} do
|
||||
{{:ok, {lat1, lon1}}, {:ok, {lat2, lon2}}} ->
|
||||
distance = lat1 |> haversine_km(lon1, lat2, lon2) |> round() |> Decimal.new()
|
||||
|
||||
distance = lat1 |> haversine_km(lon1, lat2, lon2) |> round() |> Decimal.new()
|
||||
changeset
|
||||
|> Ecto.Changeset.put_change(:pos1, %{"lat" => lat1, "lon" => lon1})
|
||||
|> Ecto.Changeset.put_change(:pos2, %{"lat" => lat2, "lon" => lon2})
|
||||
|> Ecto.Changeset.put_change(:distance_km, distance)
|
||||
|> Ecto.Changeset.put_change(:user_submitted, true)
|
||||
|> Repo.insert()
|
||||
|
||||
changeset
|
||||
|> Ecto.Changeset.put_change(:pos1, %{"lat" => lat1, "lon" => lon1})
|
||||
|> Ecto.Changeset.put_change(:pos2, %{"lat" => lat2, "lon" => lon2})
|
||||
|> Ecto.Changeset.put_change(:distance_km, distance)
|
||||
|> Ecto.Changeset.put_change(:user_submitted, true)
|
||||
|> Repo.insert()
|
||||
_ ->
|
||||
changeset = Ecto.Changeset.add_error(changeset, :grid1, "could not resolve grid to coordinates")
|
||||
{:error, %{changeset | action: :insert}}
|
||||
end
|
||||
else
|
||||
{:error, %{changeset | action: :insert}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
alias Microwaveprop.Radio.Qso
|
||||
alias Microwaveprop.Workers.QsoWeatherEnqueueWorker
|
||||
|
||||
require Logger
|
||||
|
||||
@band_options [
|
||||
{"1296 MHz", "1296"},
|
||||
{"2304 MHz", "2304"},
|
||||
|
|
@ -28,7 +30,8 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
page_title: "Submit QSO",
|
||||
form: to_form(changeset),
|
||||
band_options: @band_options,
|
||||
mode_options: @mode_options
|
||||
mode_options: @mode_options,
|
||||
submitted_at: nil
|
||||
)}
|
||||
end
|
||||
|
||||
|
|
@ -42,18 +45,40 @@ defmodule MicrowavepropWeb.SubmitLive do
|
|||
{:noreply, assign(socket, form: to_form(changeset))}
|
||||
end
|
||||
|
||||
# Minimum milliseconds between submissions per LiveView session.
|
||||
# For broader IP-based rate limiting, use a reverse proxy (nginx limit_req, Cloudflare).
|
||||
@submission_cooldown_ms 30_000
|
||||
|
||||
def handle_event("save", %{"qso" => qso_params}, socket) do
|
||||
case Radio.create_qso(qso_params) do
|
||||
{:ok, qso} ->
|
||||
Oban.insert(QsoWeatherEnqueueWorker.new(%{}))
|
||||
if recently_submitted?(socket) do
|
||||
{:noreply, put_flash(socket, :error, "Please wait before submitting another QSO.")}
|
||||
else
|
||||
case Radio.create_qso(qso_params) do
|
||||
{:ok, qso} ->
|
||||
case Oban.insert(QsoWeatherEnqueueWorker.new(%{})) do
|
||||
{:ok, _job} ->
|
||||
:ok
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "QSO submitted successfully!")
|
||||
|> push_navigate(to: ~p"/qsos/#{qso.id}")}
|
||||
{:error, reason} ->
|
||||
Logger.warning("Failed to enqueue weather processing: #{inspect(reason)}")
|
||||
end
|
||||
|
||||
{:error, changeset} ->
|
||||
{:noreply, assign(socket, form: to_form(changeset))}
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(submitted_at: System.monotonic_time(:millisecond))
|
||||
|> put_flash(:info, "QSO submitted successfully!")
|
||||
|> push_navigate(to: ~p"/qsos/#{qso.id}")}
|
||||
|
||||
{:error, changeset} ->
|
||||
{:noreply, assign(socket, form: to_form(changeset))}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp recently_submitted?(socket) do
|
||||
case socket.assigns.submitted_at do
|
||||
nil -> false
|
||||
ts -> System.monotonic_time(:millisecond) - ts < @submission_cooldown_ms
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue