Mastodon API: Support push subscription CRUD
authorMartin Kühl <martin.kuehl@gmail.com>
Tue, 18 Sep 2018 09:56:46 +0000 (11:56 +0200)
committerMartin Kühl <martin.kuehl@gmail.com>
Sat, 22 Sep 2018 05:04:01 +0000 (07:04 +0200)
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/views/push_subscription_view.ex [new file with mode: 0644]
lib/pleroma/web/push/subscription.ex [new file with mode: 0644]
lib/pleroma/web/router.ex
priv/repo/migrations/20180918182427_create_push_subscriptions.exs [new file with mode: 0644]

index 391a79885f70007dc858b4d764083a85c05fdabe..7f06ee607939a32b00763982ba0610b11a7091ba 100644 (file)
@@ -1138,6 +1138,33 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     json(conn, %{})
   end
 
+  def create_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do
+    Pleroma.Web.Push.Subscription.delete_if_exists(user, token)
+    {:ok, subscription} = Pleroma.Web.Push.Subscription.create(user, token, params)
+    view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
+    json(conn, view)
+  end
+
+  def get_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do
+    subscription = Pleroma.Web.Push.Subscription.get(user, token)
+    view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
+    json(conn, view)
+  end
+
+  def update_push_subscription(
+        %{assigns: %{user: user, token: token}} = conn,
+        params
+      ) do
+    {:ok, subscription} = Pleroma.Web.Push.Subscription.update(user, token, params)
+    view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
+    json(conn, view)
+  end
+
+  def delete_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do
+    {:ok, _response} = Pleroma.Web.Push.Subscription.delete(user, token)
+    json(conn, %{})
+  end
+
   def errors(conn, _) do
     conn
     |> put_status(500)
diff --git a/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex b/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex
new file mode 100644 (file)
index 0000000..a910bb4
--- /dev/null
@@ -0,0 +1,14 @@
+defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
+  use Pleroma.Web, :view
+  alias Pleroma.Web.MastodonAPI.PushSubscriptionView
+
+  def render("push_subscription.json", %{subscription: subscription}) do
+    %{
+      id: to_string(subscription.id),
+      endpoint: subscription.endpoint,
+      alerts: Map.get(subscription.data, "alerts"),
+      # TODO: generate VAPID server key
+      server_key: "N/A"
+    }
+  end
+end
diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex
new file mode 100644 (file)
index 0000000..dc8fe9f
--- /dev/null
@@ -0,0 +1,66 @@
+defmodule Pleroma.Web.Push.Subscription do
+  use Ecto.Schema
+  import Ecto.{Changeset, Query}
+  alias Pleroma.{Repo, User}
+  alias Pleroma.Web.OAuth.Token
+  alias Pleroma.Web.Push.Subscription
+
+  schema "push_subscriptions" do
+    belongs_to(:user, User)
+    belongs_to(:token, Token)
+    field(:endpoint, :string)
+    field(:key_p256dh, :string)
+    field(:key_auth, :string)
+    field(:data, :map, default: %{})
+
+    timestamps()
+  end
+
+  @supported_alert_types ~w[follow favourite mention reblog]
+
+  defp alerts(%{"data" => %{"alerts" => alerts}}) do
+    alerts = Map.take(alerts, @supported_alert_types)
+    %{"alerts" => alerts}
+  end
+
+  def create(
+        %User{} = user,
+        %Token{} = token,
+        %{
+          "subscription" => %{
+            "endpoint" => endpoint,
+            "keys" => %{"auth" => key_auth, "p256dh" => key_p256dh}
+          }
+        } = params
+      ) do
+    Repo.insert(%Subscription{
+      user_id: user.id,
+      token_id: token.id,
+      endpoint: endpoint,
+      key_auth: key_auth,
+      key_p256dh: key_p256dh,
+      data: alerts(params)
+    })
+  end
+
+  def get(%User{id: user_id}, %Token{id: token_id}) do
+    Repo.get_by(Subscription, user_id: user_id, token_id: token_id)
+  end
+
+  def update(user, token, params) do
+    get(user, token)
+    |> change(data: alerts(params))
+    |> Repo.update()
+  end
+
+  def delete(user, token) do
+    Repo.delete(get(user, token))
+  end
+
+  def delete_if_exists(user, token) do
+    case get(user, token) do
+      nil -> {:ok, nil}
+      sub -> Repo.delete(sub)
+    end
+  end
+end
index ddfaa8c423f19bb42b9ed5d5909c8a651df272c8..04dc80444cf3b66474822036b46b78acb7857a35 100644 (file)
@@ -171,6 +171,11 @@ defmodule Pleroma.Web.Router do
     put("/filters/:id", MastodonAPIController, :update_filter)
     delete("/filters/:id", MastodonAPIController, :delete_filter)
 
+    post("/push/subscription", MastodonAPIController, :create_push_subscription)
+    get("/push/subscription", MastodonAPIController, :get_push_subscription)
+    put("/push/subscription", MastodonAPIController, :update_push_subscription)
+    delete("/push/subscription", MastodonAPIController, :delete_push_subscription)
+
     get("/suggestions", MastodonAPIController, :suggestions)
 
     get("/endorsements", MastodonAPIController, :empty_array)
diff --git a/priv/repo/migrations/20180918182427_create_push_subscriptions.exs b/priv/repo/migrations/20180918182427_create_push_subscriptions.exs
new file mode 100644 (file)
index 0000000..0cc7afa
--- /dev/null
@@ -0,0 +1,18 @@
+defmodule Pleroma.Repo.Migrations.CreatePushSubscriptions do
+  use Ecto.Migration
+
+  def change do
+    create table("push_subscriptions") do
+      add :user_id, references("users", on_delete: :delete_all)
+      add :token_id, references("oauth_tokens", on_delete: :delete_all)
+      add :endpoint, :string
+      add :key_p256dh, :string
+      add :key_auth, :string
+      add :data, :map
+
+      timestamps()
+    end
+
+    create index("push_subscriptions", [:user_id, :token_id], unique: true)
+  end
+end