who_need_help/lib/who_need_help/notifications/push_device.ex

92 lines
2.6 KiB
Elixir

defmodule WhoNeedHelp.Notifications.PushDevice do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@type t :: %__MODULE__{}
schema "push_devices" do
field :platform, Ecto.Enum, values: [:web, :android]
field :provider, Ecto.Enum, values: [:web_push, :fcm]
field :token, :string, redact: true
field :token_digest, :binary
field :installation_id, :string, redact: true
field :p256dh, :string, redact: true
field :auth_secret, :string, redact: true
field :device_label, :string
field :user_agent, :string
field :last_seen_at, :utc_datetime
field :disabled_at, :utc_datetime
belongs_to :user, WhoNeedHelp.Accounts.User
timestamps(type: :utc_datetime)
end
def changeset(device, attrs) do
device
|> cast(attrs, [
:user_id,
:platform,
:provider,
:token,
:installation_id,
:p256dh,
:auth_secret,
:device_label,
:user_agent,
:last_seen_at,
:disabled_at
])
|> validate_required([
:user_id,
:platform,
:provider,
:token,
:installation_id,
:last_seen_at
])
|> validate_length(:token, min: 16, max: 4_096)
|> validate_length(:installation_id, min: 16, max: 120)
|> validate_length(:p256dh, max: 512)
|> validate_length(:auth_secret, max: 512)
|> validate_length(:device_label, max: 120)
|> validate_length(:user_agent, max: 500)
|> validate_provider_fields()
|> validate_platform_provider_pair()
|> put_token_digest()
|> unique_constraint(:token_digest)
|> unique_constraint([:platform, :installation_id],
name: :push_devices_platform_installation_id_index
)
end
defp validate_provider_fields(changeset) do
case get_field(changeset, :provider) do
:web_push -> validate_required(changeset, [:p256dh, :auth_secret])
:fcm -> changeset
_unknown -> changeset
end
end
defp validate_platform_provider_pair(changeset) do
case {get_field(changeset, :platform), get_field(changeset, :provider)} do
{:web, :web_push} -> changeset
{:android, :fcm} -> changeset
{nil, _provider} -> changeset
{_platform, nil} -> changeset
_invalid -> add_error(changeset, :provider, "does not match the device platform")
end
end
defp put_token_digest(changeset) do
case get_field(changeset, :token) do
token when is_binary(token) and token != "" ->
put_change(changeset, :token_digest, :crypto.hash(:sha256, token))
_missing ->
changeset
end
end
end