Persistence for IP bans.
GamendWeb.Plugs.IpBan keeps the hot-path check in ETS; this context
is the durable source of truth so bans survive restarts and can be shared
across instances (each instance loads them at boot and applies PubSub
updates).
Summary
Functions
Deletes the ban for ip (no-op if none exists).
Lists all bans that are permanent or not yet expired.
Deletes expired bans. Returns the number of rows removed.
Creates or updates a ban for ip. expires_at is nil for a permanent ban.
Functions
@spec delete_ban(String.t()) :: :ok
Deletes the ban for ip (no-op if none exists).
@spec list_active() :: [Gamend.IpBans.IpBan.t()]
Lists all bans that are permanent or not yet expired.
@spec purge_expired() :: non_neg_integer()
Deletes expired bans. Returns the number of rows removed.
@spec upsert_ban(String.t(), DateTime.t() | nil) :: {:ok, Gamend.IpBans.IpBan.t()} | {:error, Ecto.Changeset.t()}
Creates or updates a ban for ip. expires_at is nil for a permanent ban.