WebPush refactoring: separate build and deliver steps
This commit is contained in:
parent
f47a124698
commit
568819c08a
@ -19,25 +19,30 @@ defmodule Pleroma.Web.Push.Impl do
|
||||
@body_chars 140
|
||||
@types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"]
|
||||
|
||||
@doc "Performs sending notifications for user subscriptions"
|
||||
@spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type}
|
||||
def perform(
|
||||
@doc "Builds webpush notification payloads for the subscriptions enabled by the receiving user"
|
||||
@spec build(Notification.t()) ::
|
||||
list(%{content: map(), subscription: Subscription.t()})
|
||||
| :error
|
||||
| {:error, :unknown_type}
|
||||
def build(
|
||||
%{
|
||||
activity: %{data: %{"type" => activity_type}} = activity,
|
||||
user: %User{id: user_id}
|
||||
user: user
|
||||
} = notification
|
||||
)
|
||||
when activity_type in @types do
|
||||
user = User.get_cached_by_ap_id(notification.activity.data["actor"])
|
||||
notification_actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
|
||||
avatar_url = User.avatar_url(notification_actor)
|
||||
|
||||
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
|
||||
avatar_url = User.avatar_url(user)
|
||||
object = Object.normalize(activity, fetch: false)
|
||||
user = User.get_cached_by_id(user_id)
|
||||
direct_conversation_id = Activity.direct_conversation_id(activity, user)
|
||||
|
||||
for subscription <- fetch_subscriptions(user_id),
|
||||
Subscription.enabled?(subscription, notification.type) do
|
||||
subscriptions = fetch_subscriptions(user.id)
|
||||
|
||||
subscriptions
|
||||
|> Enum.filter(&Subscription.enabled?(&1, notification.type))
|
||||
|> Enum.map(fn subscription ->
|
||||
payload =
|
||||
%{
|
||||
access_token: subscription.token.token,
|
||||
notification_id: notification.id,
|
||||
@ -49,39 +54,37 @@ defmodule Pleroma.Web.Push.Impl do
|
||||
direct_conversation_id: direct_conversation_id
|
||||
}
|
||||
}
|
||||
|> Map.merge(build_content(notification, user, object))
|
||||
|> Map.merge(build_content(notification, notification_actor, object))
|
||||
|> Jason.encode!()
|
||||
|> push_message(build_sub(subscription), gcm_api_key, subscription)
|
||||
end
|
||||
|> (&{:ok, &1}).()
|
||||
|
||||
%{payload: payload, subscription: subscription}
|
||||
end)
|
||||
end
|
||||
|
||||
def perform(_) do
|
||||
def build(_) do
|
||||
Logger.warning("Unknown notification type")
|
||||
{:error, :unknown_type}
|
||||
end
|
||||
|
||||
@doc "Push message to web"
|
||||
def push_message(body, sub, api_key, subscription) do
|
||||
try do
|
||||
case WebPushEncryption.send_web_push(body, sub, api_key) do
|
||||
@doc "Deliver push notification to the provided webpush subscription"
|
||||
@spec deliver(%{payload: String.t(), subscription: Subscription.t()}) :: :ok | :error
|
||||
def deliver(%{payload: payload, subscription: subscription}) do
|
||||
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
|
||||
formatted_subscription = build_sub(subscription)
|
||||
|
||||
case WebPushEncryption.send_web_push(payload, formatted_subscription, gcm_api_key) do
|
||||
{:ok, %{status: code}} when code in 200..299 ->
|
||||
:ok
|
||||
|
||||
{:ok, %{status: code}} when code in 400..499 ->
|
||||
Logger.debug("Removing subscription record")
|
||||
Repo.delete!(subscription)
|
||||
:ok
|
||||
|
||||
{:ok, %{status: code}} when code in 200..299 ->
|
||||
:ok
|
||||
|
||||
{:ok, %{status: code}} ->
|
||||
Logger.error("Web Push Notification failed with code: #{code}")
|
||||
:error
|
||||
|
||||
error ->
|
||||
Logger.error("Web Push Notification failed with #{inspect(error)}")
|
||||
:error
|
||||
end
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Web Push Notification failed with #{inspect(error)}")
|
||||
:error
|
||||
@ -140,9 +143,7 @@ defmodule Pleroma.Web.Push.Impl do
|
||||
|
||||
content_text = content <> "\n"
|
||||
|
||||
options_text =
|
||||
Enum.map(options, fn x -> "○ #{x["name"]}" end)
|
||||
|> Enum.join("\n")
|
||||
options_text = Enum.map_join(options, "\n", fn x -> "○ #{x["name"]}" end)
|
||||
|
||||
[content_text, options_text]
|
||||
|> Enum.join("\n")
|
||||
|
@ -5,6 +5,7 @@
|
||||
defmodule Pleroma.Workers.WebPusherWorker do
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.Web.Push.Impl
|
||||
|
||||
use Pleroma.Workers.WorkerHelper, queue: "web_push"
|
||||
|
||||
@ -15,7 +16,8 @@ defmodule Pleroma.Workers.WebPusherWorker do
|
||||
|> Repo.get(notification_id)
|
||||
|> Repo.preload([:activity, :user])
|
||||
|
||||
Pleroma.Web.Push.Impl.perform(notification)
|
||||
Impl.build(notification)
|
||||
|> Enum.each(&Impl.deliver(&1))
|
||||
end
|
||||
|
||||
@impl Oban.Worker
|
||||
|
@ -32,17 +32,6 @@ defmodule Pleroma.Web.Push.ImplTest do
|
||||
:ok
|
||||
end
|
||||
|
||||
@sub %{
|
||||
endpoint: "https://example.com/example/1234",
|
||||
keys: %{
|
||||
auth: "8eDyX_uCN0XRhSbY5hs7Hg==",
|
||||
p256dh:
|
||||
"BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA="
|
||||
}
|
||||
}
|
||||
@api_key "BASgACIHpN1GYgzSRp"
|
||||
@message "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis."
|
||||
|
||||
test "performs sending notifications" do
|
||||
user = insert(:user)
|
||||
user2 = insert(:user)
|
||||
@ -68,39 +57,65 @@ defmodule Pleroma.Web.Push.ImplTest do
|
||||
type: "mention"
|
||||
)
|
||||
|
||||
assert Impl.perform(notif) == {:ok, [:ok, :ok]}
|
||||
Impl.build(notif)
|
||||
|> Enum.each(fn push -> assert match?(:ok, Impl.deliver(push)) end)
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "returns error if notif does not match " do
|
||||
assert Impl.perform(%{}) == {:error, :unknown_type}
|
||||
end
|
||||
|
||||
test "successful message sending" do
|
||||
assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok
|
||||
assert Impl.build(%{}) == {:error, :unknown_type}
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "fail message sending" do
|
||||
assert Impl.push_message(
|
||||
@message,
|
||||
Map.merge(@sub, %{endpoint: "https://example.com/example/bad"}),
|
||||
@api_key,
|
||||
%Subscription{}
|
||||
) == :error
|
||||
user = insert(:user)
|
||||
|
||||
insert(:push_subscription,
|
||||
user: user,
|
||||
endpoint: "https://example.com/example/bad",
|
||||
data: %{alerts: %{"follow" => true}}
|
||||
)
|
||||
|
||||
other_user = insert(:user)
|
||||
{:ok, _, _, activity} = CommonAPI.follow(user, other_user)
|
||||
|
||||
notif =
|
||||
insert(:notification,
|
||||
user: user,
|
||||
activity: activity,
|
||||
type: "follow"
|
||||
)
|
||||
|
||||
[push] = Impl.build(notif)
|
||||
|
||||
assert Impl.deliver(push) == :error
|
||||
end
|
||||
|
||||
test "delete subscription if result send message between 400..500" do
|
||||
subscription = insert(:push_subscription)
|
||||
user = insert(:user)
|
||||
|
||||
assert Impl.push_message(
|
||||
@message,
|
||||
Map.merge(@sub, %{endpoint: "https://example.com/example/not_found"}),
|
||||
@api_key,
|
||||
subscription
|
||||
) == :ok
|
||||
bad_subscription =
|
||||
insert(:push_subscription,
|
||||
user: user,
|
||||
endpoint: "https://example.com/example/not_found",
|
||||
data: %{alerts: %{"follow" => true}}
|
||||
)
|
||||
|
||||
refute Pleroma.Repo.get(Subscription, subscription.id)
|
||||
other_user = insert(:user)
|
||||
{:ok, _, _, activity} = CommonAPI.follow(user, other_user)
|
||||
|
||||
notif =
|
||||
insert(:notification,
|
||||
user: user,
|
||||
activity: activity,
|
||||
type: "follow"
|
||||
)
|
||||
|
||||
[push] = Impl.build(notif)
|
||||
|
||||
assert Impl.deliver(push) == :ok
|
||||
|
||||
refute Pleroma.Repo.get(Subscription, bad_subscription.id)
|
||||
end
|
||||
|
||||
test "deletes subscription when token has been deleted" do
|
||||
|
Loading…
Reference in New Issue
Block a user