prop/lib/microwaveprop/radio/edit_notifier.ex
Graham McIntire a66d3094ca Add contact edit approval system with admin review queue
Registered users can suggest edits to any contact's core fields
(callsigns, grids, band, mode, timestamp). Edits enter an admin
approval queue with field-by-field diff view. On approve, changes
are applied and enrichment re-enqueued if grids/band changed.
Users receive email notification on approve or reject.

Also updates dependabot.yml for mix ecosystem.
2026-04-11 16:15:49 -05:00

98 lines
2.5 KiB
Elixir

defmodule Microwaveprop.Radio.EditNotifier do
@moduledoc false
import Swoosh.Email
alias Microwaveprop.Mailer
@default_from {"NTMS Propagation", "noreply@mcintire.me"}
def deliver_edit_approved(edit) do
edit = Microwaveprop.Repo.preload(edit, [:user, :contact])
contact = edit.contact
body = """
==============================
Hi #{edit.user.callsign},
Your suggested edit to the contact #{contact.station1} <-> #{contact.station2}
(#{format_band(contact.band)}, #{format_ts(contact.qso_timestamp)}) has been APPROVED
and applied.
Changes applied:
#{format_changes(edit.proposed_changes)}
#{format_note(edit.admin_note)}
View the contact: #{url()}/contacts/#{contact.id}
==============================
"""
deliver(edit.user.email, "Your contact edit was approved", body)
end
def deliver_edit_rejected(edit) do
edit = Microwaveprop.Repo.preload(edit, [:user, :contact])
contact = edit.contact
body = """
==============================
Hi #{edit.user.callsign},
Your suggested edit to the contact #{contact.station1} <-> #{contact.station2}
(#{format_band(contact.band)}, #{format_ts(contact.qso_timestamp)}) has been REJECTED.
Proposed changes:
#{format_changes(edit.proposed_changes)}
#{format_note(edit.admin_note)}
View the contact: #{url()}/contacts/#{contact.id}
==============================
"""
deliver(edit.user.email, "Your contact edit was rejected", body)
end
defp deliver(recipient, subject, body) do
email =
new()
|> to(recipient)
|> from(from_address())
|> subject(subject)
|> text_body(body)
with {:ok, _metadata} <- Mailer.deliver(email) do
{:ok, email}
end
end
defp from_address do
case System.get_env("EMAIL_FROM") do
nil -> @default_from
"" -> @default_from
addr -> {"NTMS Propagation", addr}
end
end
defp url do
MicrowavepropWeb.Endpoint.url()
end
defp format_band(nil), do: "?"
defp format_band(band) do
mhz = Decimal.to_integer(band)
if mhz >= 1000, do: "#{div(mhz, 1000)} GHz", else: "#{mhz} MHz"
end
defp format_ts(nil), do: "?"
defp format_ts(ts), do: Calendar.strftime(ts, "%Y-%m-%d %H:%M UTC")
defp format_changes(changes) do
Enum.map_join(changes, "\n", fn {field, value} -> " - #{field}: #{value}" end)
end
defp format_note(nil), do: ""
defp format_note(""), do: ""
defp format_note(note), do: "\nAdmin note: #{note}\n"
end