Merge branch 'docs/admin-api' into 'develop'
[akkoma] / lib / pleroma / web / push / push.ex
index d27750ab67b18dc5542da322550e5107dbe48b02..ffd2aac91ad1097de63be3c229eb94a72f1e3028 100644 (file)
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
 defmodule Pleroma.Web.Push do
   use GenServer
 
@@ -9,28 +13,42 @@ defmodule Pleroma.Web.Push do
 
   @types ["Create", "Follow", "Announce", "Like"]
 
-  @gcm_api_key nil
-
   def start_link() do
     GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
   end
 
-  def init(:ok) do
-    case Application.get_env(:web_push_encryption, :vapid_details) do
-      nil ->
-        Logger.error(
-          "VAPID key pair is not found. Please, add VAPID configuration to config. Run `mix web_push.gen.keypair` mix task to create a key pair"
-        )
-
-        {:error, %{}}
+  def vapid_config() do
+    Application.get_env(:web_push_encryption, :vapid_details, [])
+  end
 
-      _ ->
-        {:ok, %{}}
+  def enabled() do
+    case vapid_config() do
+      [] -> false
+      list when is_list(list) -> true
+      _ -> false
     end
   end
 
   def send(notification) do
-    GenServer.cast(Pleroma.Web.Push, {:send, notification})
+    if enabled() do
+      GenServer.cast(Pleroma.Web.Push, {:send, notification})
+    end
+  end
+
+  def init(:ok) do
+    if !enabled() do
+      Logger.warn("""
+      VAPID key pair is not found. If you wish to enabled web push, please run
+
+          mix web_push.gen.keypair
+
+      and add the resulting output to your configuration file.
+      """)
+
+      :ignore
+    else
+      {:ok, nil}
+    end
   end
 
   def handle_cast(
@@ -39,36 +57,55 @@ defmodule Pleroma.Web.Push do
       )
       when type in @types do
     actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
-    body = notification |> format(actor) |> Jason.encode!()
+
+    type = Pleroma.Activity.mastodon_notification_type(notification.activity)
 
     Subscription
     |> where(user_id: ^user_id)
+    |> preload(:token)
     |> Repo.all()
-    |> Enum.each(fn record ->
-      subscription = %{
+    |> Enum.filter(fn subscription ->
+      get_in(subscription.data, ["alerts", type]) || false
+    end)
+    |> Enum.each(fn subscription ->
+      sub = %{
         keys: %{
-          p256dh: record.key_p256dh,
-          auth: record.key_auth
+          p256dh: subscription.key_p256dh,
+          auth: subscription.key_auth
         },
-        endpoint: record.endpoint
+        endpoint: subscription.endpoint
       }
 
-      case WebPushEncryption.send_web_push(body, subscription, @gcm_api_key) do
+      body =
+        Jason.encode!(%{
+          title: format_title(notification),
+          access_token: subscription.token.token,
+          body: format_body(notification, actor),
+          notification_id: notification.id,
+          notification_type: type,
+          icon: User.avatar_url(actor),
+          preferred_locale: "en"
+        })
+
+      case WebPushEncryption.send_web_push(
+             body,
+             sub,
+             Application.get_env(:web_push_encryption, :gcm_api_key)
+           ) do
         {:ok, %{status_code: code}} when 400 <= code and code < 500 ->
           Logger.debug("Removing subscription record")
-          Repo.delete!(record)
+          Repo.delete!(subscription)
           :ok
 
         {:ok, %{status_code: code}} when 200 <= code and code < 300 ->
           :ok
 
         {:ok, %{status_code: code}} ->
-          Logger.error("Web Push Nonification failed with code: #{code}")
+          Logger.error("Web Push Notification failed with code: #{code}")
           :error
 
-        data ->
-          Logger.error("Web Push Nonification failed with unknown error")
-          IO.inspect(data)
+        _ ->
+          Logger.error("Web Push Notification failed with unknown error")
           :error
       end
     end)
@@ -81,46 +118,21 @@ defmodule Pleroma.Web.Push do
     {:noreply, state}
   end
 
-  def format(%{activity: %{data: %{"type" => "Create"}}}, actor) do
-    %{
-      title: "New Mention",
-      body: "@#{actor.nickname} has mentiond you",
-      icon: get_avatar_url(actor)
-    }
-  end
-
-  def format(%{activity: %{data: %{"type" => "Follow"}}}, actor) do
-    %{
-      title: "New Follower",
-      body: "@#{actor.nickname} has followed you",
-      icon: get_avatar_url(actor)
-    }
-  end
-
-  def format(%{activity: %{data: %{"type" => "Announce"}}}, actor) do
-    %{
-      title: "New Announce",
-      body: "@#{actor.nickname} has announced your post",
-      icon: get_avatar_url(actor)
-    }
-  end
-
-  def format(%{activity: %{data: %{"type" => "Like"}}}, actor) do
-    %{
-      title: "New Like",
-      body: "@#{actor.nickname} has liked your post",
-      icon: get_avatar_url(actor)
-    }
-  end
-
-  def get_avatar_url(%{avatar: %{"type" => "Image", "url" => urls}}) do
-    case List.first(urls) do
-      %{"href" => url} -> url
-      _ -> get_avatar_url(nil)
+  defp format_title(%{activity: %{data: %{"type" => type}}}) do
+    case type do
+      "Create" -> "New Mention"
+      "Follow" -> "New Follower"
+      "Announce" -> "New Repeat"
+      "Like" -> "New Favorite"
     end
   end
 
-  def get_avatar_url(_) do
-    Pleroma.Web.Endpoint.static_url() <> "/images/avi.png"
+  defp format_body(%{activity: %{data: %{"type" => type}}}, actor) do
+    case type do
+      "Create" -> "@#{actor.nickname} has mentioned you"
+      "Follow" -> "@#{actor.nickname} has followed you"
+      "Announce" -> "@#{actor.nickname} has repeated your post"
+      "Like" -> "@#{actor.nickname} has favorited your post"
+    end
   end
 end