277 @spec/@type annotations added to 58 files covering all public APIs: contexts (propagation, radio, weather, terrain, beacons, commercial), GRIB2 decoders, terrain analysis, duct detection, rain scatter, CSV/ADIF import, weather clients, and all Ecto schemas. Dialyzer passes with 0 errors.
80 lines
2.3 KiB
Elixir
80 lines
2.3 KiB
Elixir
defmodule Microwaveprop.BeaconMonitors do
|
|
@moduledoc """
|
|
The BeaconMonitors context: manages the monitor stations a user
|
|
has registered. Each monitor has a unique random token the remote
|
|
program uses to authenticate its reports.
|
|
"""
|
|
|
|
import Ecto.Query
|
|
|
|
alias Microwaveprop.Accounts.User
|
|
alias Microwaveprop.BeaconMonitors.BeaconMonitor
|
|
alias Microwaveprop.Repo
|
|
|
|
@token_bytes 32
|
|
|
|
@doc """
|
|
Returns all monitors for the given user, newest first.
|
|
"""
|
|
@spec list_monitors_for_user(User.t()) :: [BeaconMonitor.t()]
|
|
def list_monitors_for_user(%User{id: user_id}) do
|
|
Repo.all(
|
|
from m in BeaconMonitor,
|
|
where: m.user_id == ^user_id,
|
|
order_by: [desc: m.inserted_at]
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Creates a new monitor for the given user with a freshly generated token.
|
|
"""
|
|
@spec create_monitor(User.t(), map()) :: {:ok, BeaconMonitor.t()} | {:error, Ecto.Changeset.t()}
|
|
def create_monitor(%User{} = user, attrs) do
|
|
%BeaconMonitor{user_id: user.id, token: generate_token()}
|
|
|> BeaconMonitor.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a monitor owned by the given user.
|
|
|
|
Returns `{:error, :not_found}` if the monitor does not exist or
|
|
belongs to another user.
|
|
"""
|
|
@spec delete_monitor(User.t(), Ecto.UUID.t()) ::
|
|
{:ok, BeaconMonitor.t()} | {:error, :not_found} | {:error, Ecto.Changeset.t()}
|
|
def delete_monitor(%User{id: user_id}, monitor_id) do
|
|
query =
|
|
from m in BeaconMonitor,
|
|
where: m.id == ^monitor_id and m.user_id == ^user_id
|
|
|
|
case Repo.one(query) do
|
|
nil -> {:error, :not_found}
|
|
monitor -> Repo.delete(monitor)
|
|
end
|
|
rescue
|
|
Ecto.Query.CastError -> {:error, :not_found}
|
|
end
|
|
|
|
@doc """
|
|
Looks up a monitor by its token. Returns nil if not found.
|
|
"""
|
|
@spec get_monitor_by_token(String.t()) :: BeaconMonitor.t() | nil
|
|
def get_monitor_by_token(token) when is_binary(token) do
|
|
Repo.get_by(BeaconMonitor, token: token)
|
|
end
|
|
|
|
@doc """
|
|
Returns a blank changeset for rendering the new-monitor form.
|
|
"""
|
|
@spec change_monitor(map()) :: Ecto.Changeset.t()
|
|
def change_monitor(attrs \\ %{}) do
|
|
BeaconMonitor.changeset(%BeaconMonitor{}, attrs)
|
|
end
|
|
|
|
defp generate_token do
|
|
@token_bytes
|
|
|> :crypto.strong_rand_bytes()
|
|
|> Base.url_encode64(padding: false)
|
|
end
|
|
end
|