Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
15 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index a9f893f7b..691725702 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -1,182 +1,181 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.Impl do
@moduledoc "The module represents implementation push web notification"
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Metadata.Utils
alias Pleroma.Web.Push.Subscription
require Logger
import Ecto.Query
defdelegate mastodon_notification_type(activity), to: Activity
@types ["Create", "Follow", "Announce", "Like", "Move"]
@doc "Performs sending notifications for user subscriptions"
@spec perform(Notification.t()) :: list(any) | :error
def perform(
%{
activity: %{data: %{"type" => activity_type}} = activity,
user: %User{id: user_id}
} = notification
)
when activity_type in @types do
actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
mastodon_type = mastodon_notification_type(notification.activity)
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
avatar_url = User.avatar_url(actor)
object = Object.normalize(activity)
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, mastodon_type) do
%{
access_token: subscription.token.token,
notification_id: notification.id,
notification_type: mastodon_type,
icon: avatar_url,
preferred_locale: "en",
pleroma: %{
activity_id: notification.activity.id,
direct_conversation_id: direct_conversation_id
}
}
|> Map.merge(build_content(notification, actor, object, mastodon_type))
|> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription)
end
|> (&{:ok, &1}).()
end
def perform(_) do
Logger.warn("Unknown notification type")
{:error, :unknown_type}
end
@doc "Push message to web"
def push_message(body, sub, api_key, subscription) do
case WebPushEncryption.send_web_push(body, sub, api_key) do
{:ok, %{status_code: code}} when 400 <= code and code < 500 ->
Logger.debug("Removing subscription record")
Repo.delete!(subscription)
:ok
{:ok, %{status_code: code}} when 200 <= code and code < 300 ->
:ok
{:ok, %{status_code: code}} ->
Logger.error("Web Push Notification failed with code: #{code}")
:error
_ ->
Logger.error("Web Push Notification failed with unknown error")
:error
end
end
@doc "Gets user subscriptions"
def fetch_subscriptions(user_id) do
Subscription
|> where(user_id: ^user_id)
|> preload(:token)
|> Repo.all()
end
def build_sub(subscription) do
%{
keys: %{
p256dh: subscription.key_p256dh,
auth: subscription.key_auth
},
endpoint: subscription.endpoint
}
end
def build_content(notification, actor, object, mastodon_type \\ nil)
def build_content(
%{
- activity: %{data: %{"directMessage" => true}},
user: %{notification_settings: %{privacy_option: true}}
- },
- actor,
+ } = notification,
+ _actor,
_object,
- _mastodon_type
+ mastodon_type
) do
- %{title: "New Direct Message", body: "@#{actor.nickname}"}
+ %{body: format_title(notification, mastodon_type)}
end
def build_content(notification, actor, object, mastodon_type) do
mastodon_type = mastodon_type || mastodon_notification_type(notification.activity)
%{
title: format_title(notification, mastodon_type),
body: format_body(notification, actor, object, mastodon_type)
}
end
def format_body(activity, actor, object, mastodon_type \\ nil)
def format_body(
%{activity: %{data: %{"type" => "Create"}}},
actor,
%{data: %{"content" => content}},
_mastodon_type
) do
"@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
%{activity: %{data: %{"type" => "Announce"}}},
actor,
%{data: %{"content" => content}},
_mastodon_type
) do
"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
%{activity: %{data: %{"type" => type}}} = notification,
actor,
_object,
mastodon_type
)
when type in ["Follow", "Like"] do
mastodon_type = mastodon_type || mastodon_notification_type(notification.activity)
case mastodon_type do
"follow" -> "@#{actor.nickname} has followed you"
"follow_request" -> "@#{actor.nickname} has requested to follow you"
"favourite" -> "@#{actor.nickname} has favorited your post"
end
end
def format_title(activity, mastodon_type \\ nil)
def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do
"New Direct Message"
end
def format_title(%{activity: activity}, mastodon_type) do
mastodon_type = mastodon_type || mastodon_notification_type(activity)
case mastodon_type do
"mention" -> "New Mention"
"follow" -> "New Follower"
"follow_request" -> "New Follow Request"
"reblog" -> "New Repeat"
"favourite" -> "New Favorite"
type -> "New #{String.capitalize(type || "event")}"
end
end
end
diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs
index b2664bf28..b855d72ba 100644
--- a/test/web/push/impl_test.exs
+++ b/test/web/push/impl_test.exs
@@ -1,240 +1,295 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.ImplTest do
use Pleroma.DataCase
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Push.Impl
alias Pleroma.Web.Push.Subscription
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn
%{method: :post, url: "https://example.com/example/1234"} ->
%Tesla.Env{status: 200}
%{method: :post, url: "https://example.com/example/not_found"} ->
%Tesla.Env{status: 400}
%{method: :post, url: "https://example.com/example/bad"} ->
%Tesla.Env{status: 100}
end)
: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 fini..."
test "performs sending notifications" do
user = insert(:user)
user2 = insert(:user)
insert(:push_subscription, user: user, data: %{alerts: %{"mention" => true}})
insert(:push_subscription, user: user2, data: %{alerts: %{"mention" => true}})
insert(:push_subscription,
user: user,
data: %{alerts: %{"follow" => true, "mention" => true}}
)
insert(:push_subscription,
user: user,
data: %{alerts: %{"follow" => true, "mention" => false}}
)
{:ok, activity} = CommonAPI.post(user, %{"status" => "<Lorem ipsum dolor sit amet."})
notif =
insert(:notification,
user: user,
activity: activity
)
assert Impl.perform(notif) == {:ok, [:ok, :ok]}
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
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
end
test "delete subscription if result send message between 400..500" do
subscription = insert(:push_subscription)
assert Impl.push_message(
@message,
Map.merge(@sub, %{endpoint: "https://example.com/example/not_found"}),
@api_key,
subscription
) == :ok
refute Pleroma.Repo.get(Subscription, subscription.id)
end
test "deletes subscription when token has been deleted" do
subscription = insert(:push_subscription)
Pleroma.Repo.delete(subscription.token)
refute Pleroma.Repo.get(Subscription, subscription.id)
end
test "renders title and body for create activity" do
user = insert(:user, nickname: "Bob")
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
})
object = Object.normalize(activity)
assert Impl.format_body(
%{
activity: activity
},
user,
object
) ==
"@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
assert Impl.format_title(%{activity: activity}) ==
"New Mention"
end
test "renders title and body for follow activity" do
user = insert(:user, nickname: "Bob")
other_user = insert(:user)
{:ok, _, _, activity} = CommonAPI.follow(user, other_user)
object = Object.normalize(activity, false)
assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has followed you"
assert Impl.format_title(%{activity: activity}) ==
"New Follower"
end
test "renders title and body for announce activity" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
})
{:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user)
object = Object.normalize(activity)
assert Impl.format_body(%{activity: announce_activity}, user, object) ==
"@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
assert Impl.format_title(%{activity: announce_activity}) ==
"New Repeat"
end
test "renders title and body for like activity" do
user = insert(:user, nickname: "Bob")
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
})
{:ok, activity} = CommonAPI.favorite(user, activity.id)
object = Object.normalize(activity)
assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post"
assert Impl.format_title(%{activity: activity}) ==
"New Favorite"
end
test "renders title for create activity with direct visibility" do
user = insert(:user, nickname: "Bob")
{:ok, activity} =
CommonAPI.post(user, %{
"visibility" => "direct",
"status" => "This is just between you and me, pal"
})
assert Impl.format_title(%{activity: activity}) ==
"New Direct Message"
end
describe "build_content/3" do
- test "returns info content for direct message with enabled privacy option" do
+ test "hides details for notifications when privacy option enabled" do
user = insert(:user, nickname: "Bob")
user2 = insert(:user, nickname: "Rob", notification_settings: %{privacy_option: true})
{:ok, activity} =
CommonAPI.post(user, %{
"visibility" => "direct",
"status" => "<Lorem ipsum dolor sit amet."
})
notif = insert(:notification, user: user2, activity: activity)
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
object = Object.normalize(activity)
assert Impl.build_content(notif, actor, object) == %{
- body: "@Bob",
- title: "New Direct Message"
+ body: "New Direct Message"
+ }
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "visibility" => "public",
+ "status" => "<Lorem ipsum dolor sit amet."
+ })
+
+ notif = insert(:notification, user: user2, activity: activity)
+
+ actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
+ object = Object.normalize(activity)
+
+ assert Impl.build_content(notif, actor, object) == %{
+ body: "New Mention"
+ }
+
+ {:ok, activity} = CommonAPI.favorite(user, activity.id)
+
+ notif = insert(:notification, user: user2, activity: activity)
+
+ actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
+ object = Object.normalize(activity)
+
+ assert Impl.build_content(notif, actor, object) == %{
+ body: "New Favorite"
}
end
- test "returns regular content for direct message with disabled privacy option" do
+ test "returns regular content for notifications with privacy option disabled" do
user = insert(:user, nickname: "Bob")
user2 = insert(:user, nickname: "Rob", notification_settings: %{privacy_option: false})
{:ok, activity} =
CommonAPI.post(user, %{
"visibility" => "direct",
"status" =>
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
})
notif = insert(:notification, user: user2, activity: activity)
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
object = Object.normalize(activity)
assert Impl.build_content(notif, actor, object) == %{
body:
"@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...",
title: "New Direct Message"
}
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "visibility" => "public",
+ "status" =>
+ "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
+ })
+
+ notif = insert(:notification, user: user2, activity: activity)
+
+ actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
+ object = Object.normalize(activity)
+
+ assert Impl.build_content(notif, actor, object) == %{
+ body:
+ "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...",
+ title: "New Mention"
+ }
+
+ {:ok, activity} = CommonAPI.favorite(user, activity.id)
+
+ notif = insert(:notification, user: user2, activity: activity)
+
+ actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
+ object = Object.normalize(activity)
+
+ assert Impl.build_content(notif, actor, object) == %{
+ body: "@Bob has favorited your post",
+ title: "New Favorite"
+ }
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Thu, Oct 29, 11:59 PM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1798926
Default Alt Text
(15 KB)

Event Timeline