Beacon power in mW, settings tweaks
- Rename beacons.power_watts to power_mw (migration multiplies existing values by 1000); form/list/show all relabeled to "Power (mW)" - Fix Add-monitor button alignment on /users/settings by rendering the label above and putting the input and button in a plain flex row so the input wrapper margin no longer offsets the button - Extend the settings page re-auth window from 10 minutes to 24 hours
This commit is contained in:
parent
f236ec147f
commit
b656e015bf
12 changed files with 41 additions and 26 deletions
|
|
@ -2,7 +2,7 @@ defmodule Microwaveprop.Beacons.Beacon do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
A beacon transmitter. Frequency in MHz, coordinates as lat/lon,
|
A beacon transmitter. Frequency in MHz, coordinates as lat/lon,
|
||||||
grid as Maidenhead (auto-computed from lat/lon when not supplied),
|
grid as Maidenhead (auto-computed from lat/lon when not supplied),
|
||||||
power in watts, height above ground in meters.
|
power in milliwatts, height above ground in meters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
@ -19,22 +19,22 @@ defmodule Microwaveprop.Beacons.Beacon do
|
||||||
field :grid, :string
|
field :grid, :string
|
||||||
field :lat, :float
|
field :lat, :float
|
||||||
field :lon, :float
|
field :lon, :float
|
||||||
field :power_watts, :float
|
field :power_mw, :float
|
||||||
field :height_m, :float
|
field :height_m, :float
|
||||||
field :user_id, :binary_id
|
field :user_id, :binary_id
|
||||||
|
|
||||||
timestamps(type: :utc_datetime)
|
timestamps(type: :utc_datetime)
|
||||||
end
|
end
|
||||||
|
|
||||||
@required_fields [:frequency_mhz, :callsign, :lat, :lon, :power_watts, :height_m]
|
@required_fields [:frequency_mhz, :callsign, :lat, :lon, :power_mw, :height_m]
|
||||||
|
|
||||||
def changeset(beacon, attrs) do
|
def changeset(beacon, attrs) do
|
||||||
beacon
|
beacon
|
||||||
|> cast(attrs, [:frequency_mhz, :callsign, :grid, :lat, :lon, :power_watts, :height_m])
|
|> cast(attrs, [:frequency_mhz, :callsign, :grid, :lat, :lon, :power_mw, :height_m])
|
||||||
|> update_change(:callsign, fn cs -> cs && String.upcase(String.trim(cs)) end)
|
|> update_change(:callsign, fn cs -> cs && String.upcase(String.trim(cs)) end)
|
||||||
|> validate_required(@required_fields)
|
|> validate_required(@required_fields)
|
||||||
|> validate_number(:frequency_mhz, greater_than: 0)
|
|> validate_number(:frequency_mhz, greater_than: 0)
|
||||||
|> validate_number(:power_watts, greater_than_or_equal_to: 0)
|
|> validate_number(:power_mw, greater_than_or_equal_to: 0)
|
||||||
|> validate_number(:height_m, greater_than_or_equal_to: 0)
|
|> validate_number(:height_m, greater_than_or_equal_to: 0)
|
||||||
|> validate_number(:lat, greater_than_or_equal_to: -90, less_than_or_equal_to: 90)
|
|> validate_number(:lat, greater_than_or_equal_to: -90, less_than_or_equal_to: 90)
|
||||||
|> validate_number(:lon, greater_than_or_equal_to: -180, less_than_or_equal_to: 180)
|
|> validate_number(:lon, greater_than_or_equal_to: -180, less_than_or_equal_to: 180)
|
||||||
|
|
|
||||||
|
|
@ -64,18 +64,20 @@
|
||||||
as={:beacon_monitor}
|
as={:beacon_monitor}
|
||||||
action={~p"/users/beacon-monitors"}
|
action={~p"/users/beacon-monitors"}
|
||||||
id="create_beacon_monitor"
|
id="create_beacon_monitor"
|
||||||
class="flex items-end gap-2"
|
|
||||||
>
|
>
|
||||||
<div class="flex-1">
|
<label for={f[:name].id} class="label mb-1">Monitor name</label>
|
||||||
<.input
|
<div class="flex items-center gap-2">
|
||||||
field={f[:name]}
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
label="Monitor name"
|
name={f[:name].name}
|
||||||
|
id={f[:name].id}
|
||||||
|
value={Phoenix.HTML.Form.normalize_value("text", f[:name].value)}
|
||||||
placeholder="e.g. Shack Pi"
|
placeholder="e.g. Shack Pi"
|
||||||
|
class="input flex-1"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<.button variant="primary" phx-disable-with="Adding...">Add monitor</.button>
|
||||||
</div>
|
</div>
|
||||||
<.button variant="primary" phx-disable-with="Adding...">Add monitor</.button>
|
|
||||||
</.form>
|
</.form>
|
||||||
|
|
||||||
<%= if @beacon_monitors == [] do %>
|
<%= if @beacon_monitors == [] do %>
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ defmodule MicrowavepropWeb.BeaconLive.Form do
|
||||||
<.input field={@form[:lat]} type="number" label="Latitude" step="any" required />
|
<.input field={@form[:lat]} type="number" label="Latitude" step="any" required />
|
||||||
<.input field={@form[:lon]} type="number" label="Longitude" step="any" required />
|
<.input field={@form[:lon]} type="number" label="Longitude" step="any" required />
|
||||||
<.input
|
<.input
|
||||||
field={@form[:power_watts]}
|
field={@form[:power_mw]}
|
||||||
type="number"
|
type="number"
|
||||||
label="Power (W)"
|
label="Power (mW)"
|
||||||
step="any"
|
step="any"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ defmodule MicrowavepropWeb.BeaconLive.Index do
|
||||||
<:col :let={{_id, beacon}} label="Grid">{beacon.grid}</:col>
|
<:col :let={{_id, beacon}} label="Grid">{beacon.grid}</:col>
|
||||||
<:col :let={{_id, beacon}} label="Lat">{beacon.lat}</:col>
|
<:col :let={{_id, beacon}} label="Lat">{beacon.lat}</:col>
|
||||||
<:col :let={{_id, beacon}} label="Lon">{beacon.lon}</:col>
|
<:col :let={{_id, beacon}} label="Lon">{beacon.lon}</:col>
|
||||||
<:col :let={{_id, beacon}} label="Power (W)">{beacon.power_watts}</:col>
|
<:col :let={{_id, beacon}} label="Power (mW)">{beacon.power_mw}</:col>
|
||||||
<:col :let={{_id, beacon}} label="Height AGL (m)">{beacon.height_m}</:col>
|
<:col :let={{_id, beacon}} label="Height AGL (m)">{beacon.height_m}</:col>
|
||||||
<:action :let={{_id, beacon}}>
|
<:action :let={{_id, beacon}}>
|
||||||
<div class="sr-only">
|
<div class="sr-only">
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ defmodule MicrowavepropWeb.BeaconLive.Show do
|
||||||
<:item title="Grid">{@beacon.grid}</:item>
|
<:item title="Grid">{@beacon.grid}</:item>
|
||||||
<:item title="Latitude">{@beacon.lat}</:item>
|
<:item title="Latitude">{@beacon.lat}</:item>
|
||||||
<:item title="Longitude">{@beacon.lon}</:item>
|
<:item title="Longitude">{@beacon.lon}</:item>
|
||||||
<:item title="Power (W)">{@beacon.power_watts}</:item>
|
<:item title="Power (mW)">{@beacon.power_mw}</:item>
|
||||||
<:item title="Height above ground (m)">{@beacon.height_m}</:item>
|
<:item title="Height above ground (m)">{@beacon.height_m}</:item>
|
||||||
</.list>
|
</.list>
|
||||||
</Layouts.app>
|
</Layouts.app>
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ defmodule MicrowavepropWeb.UserAuth do
|
||||||
Plug for routes that require sudo mode.
|
Plug for routes that require sudo mode.
|
||||||
"""
|
"""
|
||||||
def require_sudo_mode(conn, _opts) do
|
def require_sudo_mode(conn, _opts) do
|
||||||
if Accounts.sudo_mode?(conn.assigns.current_scope.user, -10) do
|
if Accounts.sudo_mode?(conn.assigns.current_scope.user, -60 * 24) do
|
||||||
conn
|
conn
|
||||||
else
|
else
|
||||||
conn
|
conn
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule Microwaveprop.Repo.Migrations.RenameBeaconPowerToMw do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
rename table(:beacons), :power_watts, to: :power_mw
|
||||||
|
execute "UPDATE beacons SET power_mw = power_mw * 1000"
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
execute "UPDATE beacons SET power_mw = power_mw / 1000"
|
||||||
|
rename table(:beacons), :power_mw, to: :power_watts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -13,7 +13,7 @@ defmodule Microwaveprop.BeaconsTest do
|
||||||
grid: nil,
|
grid: nil,
|
||||||
lat: nil,
|
lat: nil,
|
||||||
lon: nil,
|
lon: nil,
|
||||||
power_watts: nil,
|
power_mw: nil,
|
||||||
height_m: nil
|
height_m: nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ defmodule Microwaveprop.BeaconsTest do
|
||||||
assert beacon.callsign == "W5HN"
|
assert beacon.callsign == "W5HN"
|
||||||
assert beacon.lat == attrs.lat
|
assert beacon.lat == attrs.lat
|
||||||
assert beacon.lon == attrs.lon
|
assert beacon.lon == attrs.lon
|
||||||
assert beacon.power_watts == attrs.power_watts
|
assert beacon.power_mw == attrs.power_mw
|
||||||
assert beacon.height_m == attrs.height_m
|
assert beacon.height_m == attrs.height_m
|
||||||
assert beacon.user_id == user.id
|
assert beacon.user_id == user.id
|
||||||
end
|
end
|
||||||
|
|
@ -98,11 +98,11 @@ defmodule Microwaveprop.BeaconsTest do
|
||||||
user = user_fixture()
|
user = user_fixture()
|
||||||
beacon = beacon_fixture(user)
|
beacon = beacon_fixture(user)
|
||||||
|
|
||||||
update_attrs = %{frequency_mhz: 24_192.1, power_watts: 5.0}
|
update_attrs = %{frequency_mhz: 24_192.1, power_mw: 5.0}
|
||||||
|
|
||||||
assert {:ok, %Beacon{} = beacon} = Beacons.update_beacon(beacon, update_attrs)
|
assert {:ok, %Beacon{} = beacon} = Beacons.update_beacon(beacon, update_attrs)
|
||||||
assert beacon.frequency_mhz == 24_192.1
|
assert beacon.frequency_mhz == 24_192.1
|
||||||
assert beacon.power_watts == 5.0
|
assert beacon.power_mw == 5.0
|
||||||
end
|
end
|
||||||
|
|
||||||
test "with invalid data returns error changeset" do
|
test "with invalid data returns error changeset" do
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ defmodule MicrowavepropWeb.UserSettingsControllerTest do
|
||||||
assert redirected_to(conn) == ~p"/users/log-in"
|
assert redirected_to(conn) == ~p"/users/log-in"
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag token_authenticated_at: DateTime.add(DateTime.utc_now(:second), -11, :minute)
|
@tag token_authenticated_at: DateTime.add(DateTime.utc_now(:second), -25, :hour)
|
||||||
test "redirects if user is not in sudo mode", %{conn: conn} do
|
test "redirects if user is not in sudo mode", %{conn: conn} do
|
||||||
conn = get(conn, ~p"/users/settings")
|
conn = get(conn, ~p"/users/settings")
|
||||||
assert redirected_to(conn) == ~p"/users/log-in"
|
assert redirected_to(conn) == ~p"/users/log-in"
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ defmodule MicrowavepropWeb.BeaconLiveTest do
|
||||||
|
|
||||||
assert {:ok, _view, html} =
|
assert {:ok, _view, html} =
|
||||||
form_live
|
form_live
|
||||||
|> form("#beacon-form", beacon: %{power_watts: 25.0})
|
|> form("#beacon-form", beacon: %{power_mw: 25_000.0})
|
||||||
|> render_submit()
|
|> render_submit()
|
||||||
|> follow_redirect(conn, ~p"/beacons")
|
|> follow_redirect(conn, ~p"/beacons")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ defmodule MicrowavepropWeb.UserAuthTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "require_sudo_mode/2" do
|
describe "require_sudo_mode/2" do
|
||||||
test "allows users that have authenticated in the last 10 minutes", %{conn: conn, user: user} do
|
test "allows users that have authenticated in the last 24 hours", %{conn: conn, user: user} do
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> fetch_flash()
|
|> fetch_flash()
|
||||||
|
|
@ -198,8 +198,8 @@ defmodule MicrowavepropWeb.UserAuthTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects when authentication is too old", %{conn: conn, user: user} do
|
test "redirects when authentication is too old", %{conn: conn, user: user} do
|
||||||
eleven_minutes_ago = :second |> DateTime.utc_now() |> DateTime.add(-11, :minute)
|
too_long_ago = :second |> DateTime.utc_now() |> DateTime.add(-25, :hour)
|
||||||
user = %{user | authenticated_at: eleven_minutes_ago}
|
user = %{user | authenticated_at: too_long_ago}
|
||||||
user_token = Accounts.generate_user_session_token(user)
|
user_token = Accounts.generate_user_session_token(user)
|
||||||
{user, token_inserted_at} = Accounts.get_user_by_session_token(user_token)
|
{user, token_inserted_at} = Accounts.get_user_by_session_token(user_token)
|
||||||
assert DateTime.after?(token_inserted_at, user.authenticated_at)
|
assert DateTime.after?(token_inserted_at, user.authenticated_at)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ defmodule Microwaveprop.BeaconsFixtures do
|
||||||
callsign: "W5HN",
|
callsign: "W5HN",
|
||||||
lat: 32.897,
|
lat: 32.897,
|
||||||
lon: -97.038,
|
lon: -97.038,
|
||||||
power_watts: 10.0,
|
power_mw: 10_000.0,
|
||||||
height_m: 30.0
|
height_m: 30.0
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue