From fae112fb67c1cce4066872e38bd83bbe8ae02343 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Fri, 5 Apr 2024 15:04:38 -0400 Subject: [PATCH] Add registrations --- lib/tusker_push.ex | 25 +++++++++ lib/tusker_push/registration.ex | 33 +++++++++++ .../controllers/registrations_controller.ex | 55 +++++++++++++++++++ lib/tusker_push_web/router.ex | 4 +- .../20240405181919_create_registrations.exs | 16 ++++++ 5 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 lib/tusker_push/registration.ex create mode 100644 lib/tusker_push_web/controllers/registrations_controller.ex create mode 100644 priv/repo/migrations/20240405181919_create_registrations.exs diff --git a/lib/tusker_push.ex b/lib/tusker_push.ex index df769df..e5bbfde 100644 --- a/lib/tusker_push.ex +++ b/lib/tusker_push.ex @@ -6,4 +6,29 @@ defmodule TuskerPush do Contexts are also responsible for managing your data, regardless 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 unregister(String.t()) :: :ok | {:error, :no_registration | Ecto.Changeset.t()} + def unregister(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 end diff --git a/lib/tusker_push/registration.ex b/lib/tusker_push/registration.ex new file mode 100644 index 0000000..781ca1b --- /dev/null +++ b/lib/tusker_push/registration.ex @@ -0,0 +1,33 @@ +defmodule TuskerPush.Registration do + use Ecto.Schema + + import Ecto.Changeset + + @type t() :: %__MODULE__{ + id: Ecto.UUID.t(), + storekit_original_transaction_id: String.t(), + apns_environment: String.t(), + apns_device_token: String.t(), + inserted_at: NaiveDateTime.t(), + updated_at: NaiveDateTime.t() + } + + @primary_key {:id, Ecto.UUID, autogenerate: true} + + schema "registrations" do + field :storekit_original_transaction_id, :string + + field :apns_environment, Ecto.Enum, values: [:production, :development] + field :apns_device_token, :string + + timestamps() + end + + @required_fields [:storekit_original_transaction_id, :apns_environment, :apns_device_token] + + def create_changeset(registration \\ %__MODULE__{}, params) do + registration + |> cast(params, @required_fields) + |> validate_required(@required_fields) + end +end diff --git a/lib/tusker_push_web/controllers/registrations_controller.ex b/lib/tusker_push_web/controllers/registrations_controller.ex new file mode 100644 index 0000000..6cb3a36 --- /dev/null +++ b/lib/tusker_push_web/controllers/registrations_controller.ex @@ -0,0 +1,55 @@ +defmodule TuskerPushWeb.RegistrationsController do + alias TuskerPush.Registration + alias Ecto.Changeset + use TuskerPushWeb, :controller + + require Logger + + def create(conn, %{ + "transaction_id" => transaction_id, + "environment" => env, + "device_token" => token + }) do + with {:ok, %Registration{id: id}} <- + TuskerPush.register(%{ + storekit_original_transaction_id: transaction_id, + apns_environment: env, + apns_device_token: token + }) do + json(conn, %{id: id}) + else + {:env, nil} -> + conn + |> put_status(400) + |> json(%{error: "invalid apns environment"}) + + {:error, %Changeset{valid?: false} = changeset} -> + errors = + changeset.errors + |> Enum.map(fn {k, {reason, _}} -> %{key: k, reason: reason} end) + + conn + |> put_status(400) + |> json(%{errors: errors}) + + {:error, reason} -> + Logger.error("Failed creating registration: #{inspect(reason)}") + + conn + |> put_status(500) + |> json(%{error: "unknown error"}) + end + end + + def create(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 diff --git a/lib/tusker_push_web/router.ex b/lib/tusker_push_web/router.ex index f75a971..9a0b0a6 100644 --- a/lib/tusker_push_web/router.ex +++ b/lib/tusker_push_web/router.ex @@ -5,7 +5,9 @@ defmodule TuskerPushWeb.Router do plug :accepts, ["json"] end - scope "/api", TuskerPushWeb do + scope "/app", TuskerPushWeb do pipe_through :api + + resources "/registrations", RegistrationsController, only: [:create, :delete] end end diff --git a/priv/repo/migrations/20240405181919_create_registrations.exs b/priv/repo/migrations/20240405181919_create_registrations.exs new file mode 100644 index 0000000..c039cc9 --- /dev/null +++ b/priv/repo/migrations/20240405181919_create_registrations.exs @@ -0,0 +1,16 @@ +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 + + timestamps() + end + end +end