Remove database

This commit is contained in:
Shadowfacts 2024-04-12 16:16:46 -04:00
parent 8024e27ebe
commit 97a06e7691
23 changed files with 45 additions and 416 deletions

View File

@ -1,5 +1,5 @@
[ [
import_deps: [:ecto, :ecto_sql, :phoenix], import_deps: [:phoenix],
subdirectories: ["priv/*/migrations"], subdirectories: [],
inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}", "priv/*/seeds.exs"] inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"]
] ]

View File

@ -8,7 +8,6 @@
import Config import Config
config :tusker_push, config :tusker_push,
ecto_repos: [TuskerPush.Repo],
generators: [timestamp_type: :utc_datetime] generators: [timestamp_type: :utc_datetime]
# Configures the endpoint # Configures the endpoint

View File

@ -1,15 +1,5 @@
import Config import Config
# Configure your database
config :tusker_push, TuskerPush.Repo,
username: "postgres",
password: "postgres",
hostname: "localhost",
database: "tusker_push_dev",
stacktrace: true,
show_sensitive_data_on_connection_error: true,
pool_size: 10
# For development, we disable any cache and enable # For development, we disable any cache and enable
# debugging and code reloading. # debugging and code reloading.
# #

View File

@ -21,21 +21,6 @@ if System.get_env("PHX_SERVER") do
end end
if config_env() == :prod do if config_env() == :prod do
database_url =
System.get_env("DATABASE_URL") ||
raise """
environment variable DATABASE_URL is missing.
For example: ecto://USER:PASS@HOST/DATABASE
"""
maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []
config :tusker_push, TuskerPush.Repo,
# ssl: true,
url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
socket_options: maybe_ipv6
# The secret key base is used to sign/encrypt cookies and other secrets. # The secret key base is used to sign/encrypt cookies and other secrets.
# A default value is used in config/dev.exs and config/test.exs but you # A default value is used in config/dev.exs and config/test.exs but you
# want to use a different value for prod and you most likely don't want # want to use a different value for prod and you most likely don't want

View File

@ -1,18 +1,5 @@
import Config import Config
# Configure your database
#
# The MIX_TEST_PARTITION environment variable can be used
# to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information.
config :tusker_push, TuskerPush.Repo,
username: "postgres",
password: "postgres",
hostname: "localhost",
database: "tusker_push_test#{System.get_env("MIX_TEST_PARTITION")}",
pool: Ecto.Adapters.SQL.Sandbox,
pool_size: System.schedulers_online() * 2
# We don't run a server during test. If one is required, # We don't run a server during test. If one is required,
# you can enable the server option below. # you can enable the server option below.
config :tusker_push, TuskerPushWeb.Endpoint, config :tusker_push, TuskerPushWeb.Endpoint,

View File

@ -6,56 +6,4 @@ defmodule TuskerPush do
Contexts are also responsible for managing your data, regardless Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others. if it comes from the database, an external API or others.
""" """
alias TuskerPush.Registration
alias TuskerPush.Repo
@spec register(Map.t()) ::
{:ok, Registration.t()} | {:error, Ecto.Changeset.t()}
def register(params) do
params
|> Registration.create_changeset()
|> Repo.insert()
end
@spec update_registration(Registration.t(), Map.t()) ::
{:ok, Registration.t()} | {:error, Ecto.Changeset.t()}
def update_registration(registration, params) do
registration
|> Registration.update_changeset(params)
|> Repo.update()
end
@spec unregister(String.t()) :: :ok | {:error, :no_registration | Ecto.Changeset.t()}
def unregister(id) when is_binary(id) do
with registration when not is_nil(registration) <- Repo.get(Registration, id),
{:ok, _} <- Repo.delete(registration) do
:ok
else
nil ->
{:error, :no_registration}
{:error, reason} ->
{:error, reason}
end
end
@spec unregister(Registration.t()) :: :ok | {:error, Ecto.Changeset.t()}
def unregister(%Registration{} = registration) do
case Repo.delete(registration) do
{:ok, _} -> :ok
{:error, reason} -> {:error, reason}
end
end
@spec get_registration(String.t()) :: Registration.t() | nil
def get_registration(id) do
Repo.get(Registration, id)
end
@spec check_registration_expired(Registration.t()) :: :ok | {:expired, Registration.t()}
def check_registration_expired(_registration) do
# TODO: expiration & grace period
:ok
end
end end

View File

@ -1,37 +1,37 @@
defmodule TuskerPush.Apns do defmodule TuskerPush.Apns do
alias TuskerPush.Registration
require Logger require Logger
@spec send(Registration.t(), Map.t()) :: :ok | {:error, term()} @type environment() :: :development | :production
def send(registration, payload) do
@spec send(environment(), String.t(), Map.t()) :: :ok | {:error, term()}
def send(apns_env, apns_device_token, payload) do
with {:ok, body} <- Jason.encode(payload, pretty_print: false), with {:ok, body} <- Jason.encode(payload, pretty_print: false),
req <- make_request(registration, body), req <- make_request(apns_env, apns_device_token, body),
{:ok, resp} <- Finch.request(req, TuskerPush.Finch) do {:ok, resp} <- Finch.request(req, TuskerPush.Finch) do
handle_response(resp, registration, payload) handle_response(resp, apns_env, apns_device_token, payload)
else else
{:error, %Finch.Error{reason: :connection_closed}} -> {:error, %Finch.Error{reason: :connection_closed}} ->
Logger.warning("Apns Finch connection_closed, retrying in 1s") Logger.warning("Apns Finch connection_closed, retrying in 1s")
Process.sleep(1000) Process.sleep(1000)
__MODULE__.send(registration, payload) __MODULE__.send(apns_env, apns_device_token, payload)
{:error, %Finch.Error{reason: :disconnected}} -> {:error, %Finch.Error{reason: :disconnected}} ->
Logger.warning("Apns Finch disconnected, retrying in 1s") Logger.warning("Apns Finch disconnected, retrying in 1s")
Process.sleep(1000) Process.sleep(1000)
__MODULE__.send(registration, payload) __MODULE__.send(apns_env, apns_device_token, payload)
{:error, %Mint.TransportError{reason: :closed}} -> {:error, %Mint.TransportError{reason: :closed}} ->
Logger.warning("Apns Mint transport closed, retrying in 1s") Logger.warning("Apns Mint transport closed, retrying in 1s")
Process.sleep(1000) Process.sleep(1000)
__MODULE__.send(registration, payload) __MODULE__.send(apns_env, apns_device_token, payload)
{:error, reason} -> {:error, reason} ->
{:error, reason} {:error, reason}
end end
end end
@spec make_request(Registration.t(), binary()) :: Finch.Request.t() @spec make_request(environment(), String.t(), binary()) :: Finch.Request.t()
defp make_request(registration, body) do defp make_request(apns_env, apns_device_token, body) do
bundle_id = Application.fetch_env!(:tusker_push, :apns)[:bundle_id] bundle_id = Application.fetch_env!(:tusker_push, :apns)[:bundle_id]
headers = [ headers = [
@ -45,16 +45,17 @@ defmodule TuskerPush.Apns do
Finch.build( Finch.build(
:post, :post,
"https://#{host(registration.apns_environment)}/3/device/#{registration.apns_device_token}", "https://#{host(apns_env)}/3/device/#{apns_device_token}",
headers, headers,
body body
) )
end end
@spec handle_response(Finch.Response.t(), Registration.t(), Map.t()) :: :ok | {:error, term()} @spec handle_response(Finch.Response.t(), environment(), String.t(), Map.t()) ::
:ok | {:error, term()}
defp handle_response(resp, registration, payload) do defp handle_response(resp, apns_env, apns_device_token, payload) do
maybe_log_unique_id(resp, registration.apns_environment) maybe_log_unique_id(resp, apns_env)
if resp.status in 200..299 do if resp.status in 200..299 do
:ok :ok
@ -71,7 +72,7 @@ defmodule TuskerPush.Apns do
case {resp.status, info} do case {resp.status, info} do
{403, %{reason: "ExpiredProviderToken"}} -> {403, %{reason: "ExpiredProviderToken"}} ->
Logger.warning("Expired provider token, retrying") Logger.warning("Expired provider token, retrying")
__MODULE__.send(registration, payload) __MODULE__.send(apns_env, apns_device_token, payload)
{410, %{reason: "Unregistered"}} -> {410, %{reason: "Unregistered"}} ->
Logger.warning("Device token unregistered") Logger.warning("Device token unregistered")
@ -106,7 +107,7 @@ defmodule TuskerPush.Apns do
defp maybe_log_unique_id(_resp, :production), do: :ok defp maybe_log_unique_id(_resp, :production), do: :ok
@spec host(:development | :production) :: String.t() @spec host(environment()) :: String.t()
def host(:development) do def host(:development) do
"api.sandbox.push.apple.com" "api.sandbox.push.apple.com"

View File

@ -9,7 +9,6 @@ defmodule TuskerPush.Application do
def start(_type, _args) do def start(_type, _args) do
children = [ children = [
TuskerPushWeb.Telemetry, TuskerPushWeb.Telemetry,
TuskerPush.Repo,
{DNSCluster, query: Application.get_env(:tusker_push, :dns_cluster_query) || :ignore}, {DNSCluster, query: Application.get_env(:tusker_push, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: TuskerPush.PubSub}, {Phoenix.PubSub, name: TuskerPush.PubSub},
# Start a worker by calling: TuskerPush.Worker.start_link(arg) # Start a worker by calling: TuskerPush.Worker.start_link(arg)

View File

@ -1,12 +1,18 @@
defmodule TuskerPush.Forwarder do defmodule TuskerPush.Forwarder do
alias TuskerPush.Apns alias TuskerPush.Apns
alias TuskerPush.Registration
require Logger require Logger
@spec forward(Registration.t(), binary(), String.t(), String.t(), String.t() | nil) :: @spec forward(
Apns.environment(),
String.t(),
binary(),
String.t(),
String.t(),
String.t() | nil
) ::
:ok | {:error, term()} :ok | {:error, term()}
def forward(%Registration{push_version: 1} = registration, body, salt, key, context) do def forward(apns_env, apns_device_token, body, salt, key, context) do
payload = %{ payload = %{
"aps" => %{ "aps" => %{
"alert" => %{ "alert" => %{
@ -29,6 +35,6 @@ defmodule TuskerPush.Forwarder do
Logger.debug("Sending #{inspect(payload)}") Logger.debug("Sending #{inspect(payload)}")
Apns.send(registration, payload) Apns.send(apns_env, apns_device_token, payload)
end end
end end

View File

@ -1,50 +0,0 @@
defmodule TuskerPush.Registration do
use Ecto.Schema
import Ecto.Changeset
@type t() :: %__MODULE__{
id: Ecto.UUID.t(),
apns_environment: String.t(),
apns_device_token: String.t(),
push_version: integer(),
inserted_at: NaiveDateTime.t(),
updated_at: NaiveDateTime.t()
}
@primary_key {:id, Ecto.UUID, autogenerate: true}
schema "registrations" do
field :apns_environment, Ecto.Enum, values: [:production, :development]
# hex-encoded
field :apns_device_token, :string
field :push_version, :integer
timestamps()
end
@create_fields [
:apns_environment,
:apns_device_token,
:push_version
]
def create_changeset(registration \\ %__MODULE__{}, params) do
registration
|> cast(params, @create_fields)
|> validate_required(@create_fields)
end
@update_fields [
:apns_environment,
:apns_device_token,
:push_version
]
def update_changeset(registration, params) do
registration
|> cast(params, @update_fields)
|> validate_required(@update_fields)
end
end

View File

@ -1,5 +0,0 @@
defmodule TuskerPush.Repo do
use Ecto.Repo,
otp_app: :tusker_push,
adapter: Ecto.Adapters.Postgres
end

View File

@ -1,106 +0,0 @@
defmodule TuskerPushWeb.AppRegistrationsController do
alias TuskerPush.Registration
alias Ecto.Changeset
use TuskerPushWeb, :controller
require Logger
def create(conn, %{
"environment" => env,
"device_token" => token,
"push_version" => version
}) do
with {:ok, %Registration{id: id}} <-
TuskerPush.register(%{
apns_environment: env,
apns_device_token: token,
push_version: version
}) do
conn
|> json(%{
id: id,
endpoint: url(~p"/mastodon/v1/push/#{id}"),
device_token: token
})
else
{:error, %Changeset{valid?: false} = changeset} ->
errors =
changeset.errors
|> Enum.map(fn {k, {reason, _}} -> %{key: k, reason: reason} end)
conn
|> put_status(400)
|> json(%{error: "validation failed", fields: errors})
{:error, reason} ->
Logger.error("Failed creating registration: #{inspect(reason)}")
conn
|> put_status(500)
|> json(%{error: "unknown error", fields: []})
end
end
def create(conn, _) do
conn
|> put_status(400)
|> json(%{error: "missing required parameters"})
end
def update(conn, %{
"id" => id,
"environment" => env,
"device_token" => token,
"push_version" => version
}) do
params = %{
apns_environment: env,
apns_device_token: token,
push_version: version
}
with {:registration, registration} when not is_nil(registration) <-
{:registration, TuskerPush.get_registration(id)},
{:ok, _} <- TuskerPush.update_registration(registration, params) do
conn
|> json(%{
id: id,
endpoint: url(~p"/mastodon/v1/push/#{id}"),
device_token: token
})
else
{:registration, nil} ->
conn
|> put_status(404)
|> json(%{error: "not found", fields: []})
{:error, %Changeset{valid?: false} = changeset} ->
errors =
changeset.errors
|> Enum.map(fn {k, {reason, _}} -> %{key: k, reason: reason} end)
conn
|> put_status(400)
|> json(%{error: "validation failed", fields: errors})
{:error, reason} ->
Logger.error("Failed updating registration: #{inspect(reason)}")
conn
|> put_status(500)
|> json(%{error: "unknown error", fields: []})
end
end
def update(conn, _) do
conn
|> put_status(400)
|> json(%{error: "missing required parameters"})
end
def delete(conn, %{"id" => id}) do
TuskerPush.unregister(id)
json(conn, %{status: "ok"})
end
end

View File

@ -4,24 +4,19 @@ defmodule TuskerPushWeb.PushController do
require Logger require Logger
def push(conn, %{"id" => id} = params) do def push(conn, %{"env" => env, "apns_device_token" => apns_device_token, "ctx" => context}) do
with {:registration, registration} when not is_nil(registration) <- with {:apns_env, apns_env} <- {:apns_env, get_apns_env(env)},
{:registration, TuskerPush.get_registration(id)},
:ok <- TuskerPush.check_registration_expired(registration),
{:encoding, ["aesgcm"]} <- {:encoding, get_req_header(conn, "content-encoding")}, {:encoding, ["aesgcm"]} <- {:encoding, get_req_header(conn, "content-encoding")},
{:body, {:ok, body, conn}} <- {:body, read_body(conn)}, {:body, {:ok, body, conn}} <- {:body, read_body(conn)},
{:salt, salt} when not is_nil(salt) <- get_salt(conn), {:salt, salt} when not is_nil(salt) <- get_salt(conn),
{:key, key} when not is_nil(key) <- get_key(conn), {:key, key} when not is_nil(key) <- get_key(conn),
context <- Map.get(params, "ctx"), {:forward, :ok} <-
{:forward, :ok} <- {:forward, Forwarder.forward(registration, body, salt, key, context)} do {:forward, Forwarder.forward(apns_env, apns_device_token, body, salt, key, context)} do
send_resp(conn, 200, "ok") send_resp(conn, 200, "ok")
else else
{:registration, nil} -> {:apns_env, nil} ->
send_resp(conn, 400, "unregistered") Logger.error("Bad environment: #{env}")
send_resp(conn, 400, "bad env")
{:expired, registration} ->
TuskerPush.unregister(registration)
send_resp(conn, 400, "expired")
{:encoding, encoding} -> {:encoding, encoding} ->
Logger.warning("Unexpected encoding: #{inspect(encoding)}") Logger.warning("Unexpected encoding: #{inspect(encoding)}")
@ -45,7 +40,6 @@ defmodule TuskerPushWeb.PushController do
{:forward, {:error, :device_token_unregistered}} -> {:forward, {:error, :device_token_unregistered}} ->
Logger.debug("APNS device token unregistered, removing registration") Logger.debug("APNS device token unregistered, removing registration")
TuskerPush.unregister(id)
send_resp(conn, 400, "apns unregistered") send_resp(conn, 400, "apns unregistered")
{:forward, {:error, reason}} -> {:forward, {:error, reason}} ->
@ -54,6 +48,10 @@ defmodule TuskerPushWeb.PushController do
end end
end end
defp get_apns_env("development"), do: :development
defp get_apns_env("production"), do: :production
defp get_apns_env(_), do: nil
defp get_salt(conn) do defp get_salt(conn) do
conn conn
|> get_req_header("encryption") |> get_req_header("encryption")

View File

@ -29,7 +29,6 @@ defmodule TuskerPushWeb.Endpoint do
# :code_reloader configuration of your endpoint. # :code_reloader configuration of your endpoint.
if code_reloading? do if code_reloading? do
plug Phoenix.CodeReloader plug Phoenix.CodeReloader
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :tusker_push
end end
plug Plug.RequestId plug Plug.RequestId

View File

@ -5,19 +5,11 @@ defmodule TuskerPushWeb.Router do
plug :accepts, ["json"] plug :accepts, ["json"]
end end
scope "/app", TuskerPushWeb do scope "/push", TuskerPushWeb do
pipe_through :api pipe_through :api
scope "/v1" do scope "/v1" do
resources "/registrations", AppRegistrationsController, only: [:create, :update, :delete] post "/:env/:apns_device_token/:ctx", PushController, :push
end
end
scope "/mastodon", TuskerPushWeb do
pipe_through :api
scope "/v1" do
post "/push/:id", PushController, :push
end end
end end
end end

View File

@ -33,9 +33,6 @@ defmodule TuskerPush.MixProject do
defp deps do defp deps do
[ [
{:phoenix, "~> 1.7.11"}, {:phoenix, "~> 1.7.11"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.10"},
{:postgrex, ">= 0.0.0"},
{:telemetry_metrics, "~> 0.6"}, {:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"}, {:telemetry_poller, "~> 1.0"},
{:jason, "~> 1.2"}, {:jason, "~> 1.2"},
@ -55,10 +52,7 @@ defmodule TuskerPush.MixProject do
# See the documentation for `Mix` for more info on aliases. # See the documentation for `Mix` for more info on aliases.
defp aliases do defp aliases do
[ [
setup: ["deps.get", "ecto.setup"], setup: ["deps.get"]
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"]
] ]
end end
end end

View File

@ -1,29 +1,22 @@
%{ %{
"bandit": {:hex, :bandit, "1.4.2", "a1475c8dcbffd1f43002797f99487a64c8444753ff2b282b52409e279488e1f5", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "3db8bacea631bd926cc62ccad58edfee4252d1b4c5cccbbad9825df2722b884f"}, "bandit": {:hex, :bandit, "1.4.2", "a1475c8dcbffd1f43002797f99487a64c8444753ff2b282b52409e279488e1f5", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "3db8bacea631bd926cc62ccad58edfee4252d1b4c5cccbbad9825df2722b884f"},
"castore": {:hex, :castore, "1.0.6", "ffc42f110ebfdafab0ea159cd43d31365fa0af0ce4a02ecebf1707ae619ee727", [:mix], [], "hexpm", "374c6e7ca752296be3d6780a6d5b922854ffcc74123da90f2f328996b962d33a"}, "castore": {:hex, :castore, "1.0.6", "ffc42f110ebfdafab0ea159cd43d31365fa0af0ce4a02ecebf1707ae619ee727", [:mix], [], "hexpm", "374c6e7ca752296be3d6780a6d5b922854ffcc74123da90f2f328996b962d33a"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"joken": {:hex, :joken, "2.6.0", "b9dd9b6d52e3e6fcb6c65e151ad38bf4bc286382b5b6f97079c47ade6b1bcc6a", [:mix], [{:jose, "~> 1.11.5", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5a95b05a71cd0b54abd35378aeb1d487a23a52c324fa7efdffc512b655b5aaa7"},
"jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"}, "jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"}, "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
"nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"phoenix": {:hex, :phoenix, "1.7.11", "1d88fc6b05ab0c735b250932c4e6e33bfa1c186f76dcf623d8dd52f07d6379c7", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "b1ec57f2e40316b306708fe59b92a16b9f6f4bf50ccfa41aa8c7feb79e0ec02a"}, "phoenix": {:hex, :phoenix, "1.7.11", "1d88fc6b05ab0c735b250932c4e6e33bfa1c186f76dcf623d8dd52f07d6379c7", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "b1ec57f2e40316b306708fe59b92a16b9f6f4bf50ccfa41aa8c7feb79e0ec02a"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.5.1", "6fdbc334ea53620e71655664df6f33f670747b3a7a6c4041cdda3e2c32df6257", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ebe43aa580db129e54408e719fb9659b7f9e0d52b965c5be26cdca416ecead28"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},

View File

@ -1,4 +0,0 @@
[
import_deps: [:ecto_sql],
inputs: ["*.exs"]
]

View File

@ -1,18 +0,0 @@
defmodule TuskerPush.Repo.Migrations.CreateRegistrations do
use Ecto.Migration
def change do
create table(:registrations, primary_key: false) do
add :id, :uuid, primary_key: true, null: false
add :storekit_original_transaction_id, :string, null: false
add :apns_environment, :string, null: false
add :apns_device_token, :string, null: false
add :push_version, :integer, null: false
timestamps()
end
end
end

View File

@ -1,9 +0,0 @@
defmodule TuskerPush.Repo.Migrations.RegistrationsRemoveTransactionId do
use Ecto.Migration
def change do
alter table(:registrations) do
remove :storekit_original_transaction_id
end
end
end

View File

@ -1,11 +0,0 @@
# Script for populating the database. You can run it as:
#
# mix run priv/repo/seeds.exs
#
# Inside the script, you can read and write to any of your
# repositories directly:
#
# TuskerPush.Repo.insert!(%TuskerPush.SomeSchema{})
#
# We recommend using the bang functions (`insert!`, `update!`
# and so on) as they will fail if something goes wrong.

View File

@ -1,58 +0,0 @@
defmodule TuskerPush.DataCase do
@moduledoc """
This module defines the setup for tests requiring
access to the application's data layer.
You may define functions here to be used as helpers in
your tests.
Finally, if the test case interacts with the database,
we enable the SQL sandbox, so changes done to the database
are reverted at the end of every test. If you are using
PostgreSQL, you can even run database tests asynchronously
by setting `use TuskerPush.DataCase, async: true`, although
this option is not recommended for other databases.
"""
use ExUnit.CaseTemplate
using do
quote do
alias TuskerPush.Repo
import Ecto
import Ecto.Changeset
import Ecto.Query
import TuskerPush.DataCase
end
end
setup tags do
TuskerPush.DataCase.setup_sandbox(tags)
:ok
end
@doc """
Sets up the sandbox based on the test tags.
"""
def setup_sandbox(tags) do
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(TuskerPush.Repo, shared: not tags[:async])
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
end
@doc """
A helper that transforms changeset errors into a map of messages.
assert {:error, changeset} = Accounts.create_user(%{password: "short"})
assert "password is too short" in errors_on(changeset).password
assert %{password: ["password is too short"]} = errors_on(changeset)
"""
def errors_on(changeset) do
Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
Regex.replace(~r"%{(\w+)}", message, fn _, key ->
opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string()
end)
end)
end
end

View File

@ -1,2 +1 @@
ExUnit.start() ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(TuskerPush.Repo, :manual)