unify notification settings
This commit is contained in:
parent
7f413139fb
commit
16bcffd64a
@ -334,6 +334,12 @@ The message payload consist of:
|
||||
|
||||
Both user muting and thread muting can be done for only a certain time by adding an `expires_in` parameter to the API calls and giving the expiration time in seconds.
|
||||
|
||||
## Subscriptions
|
||||
|
||||
Has additional field in parameters:
|
||||
|
||||
- `pleroma:emoji_reaction`: Receive emoji reaction notifications?
|
||||
|
||||
## Not implemented
|
||||
|
||||
Pleroma is generally compatible with the Mastodon 2.7.2 API, but some newer features and non-essential features are omitted. These features usually return an HTTP 200 status code, but with an empty response. While they may be added in the future, they are considered low priority.
|
||||
|
@ -301,12 +301,20 @@ See [Admin-API](admin_api.md)
|
||||
Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.
|
||||
|
||||
## `/api/v1/pleroma/notification_settings`
|
||||
|
||||
### Updates user notification settings
|
||||
|
||||
* Method `PUT`
|
||||
* Authentication: required
|
||||
* Params:
|
||||
* `block_from_strangers`: BOOLEAN field, blocks notifications from accounts you do not follow
|
||||
* `hide_notification_contents`: BOOLEAN field. When set to true, it removes the contents of a message from the push notification.
|
||||
* `block_from_strangers`: BOOLEAN field, blocks notifications from accounts you do not follow
|
||||
* `hide_notification_contents`: BOOLEAN field. When set to true, it removes the contents of a message from the push notification.
|
||||
* `followers`: BOOLEAN field, receives notifications from followers
|
||||
* `follows`: BOOLEAN field, receives notifications from people the user follows
|
||||
* `remote`: BOOLEAN field, receives notifications from people on remote instances
|
||||
* `local`: BOOLEAN field, receives notifications from people on the local instance
|
||||
* `privacy_option`: BOOLEAN field. When set to true, it removes the contents of a message from the push notification.
|
||||
* `exclude_types`: ARRAY field. What notification types to exclude.
|
||||
* Response: JSON. Returns `{"status": "success"}` if the update was successful, otherwise returns `{"error": "error_msg"}`
|
||||
|
||||
## `/api/v1/pleroma/healthcheck`
|
||||
|
@ -74,6 +74,8 @@ defmodule Pleroma.Notification do
|
||||
reblog
|
||||
}
|
||||
|
||||
def types, do: @notification_types
|
||||
|
||||
def changeset(%Notification{} = notification, attrs) do
|
||||
notification
|
||||
|> cast(attrs, [:seen, :type])
|
||||
|
@ -12,13 +12,25 @@ defmodule Pleroma.User.NotificationSetting do
|
||||
embedded_schema do
|
||||
field(:block_from_strangers, :boolean, default: false)
|
||||
field(:hide_notification_contents, :boolean, default: false)
|
||||
field(:followers, :boolean, default: true)
|
||||
field(:follows, :boolean, default: true)
|
||||
field(:non_follows, :boolean, default: true)
|
||||
field(:non_followers, :boolean, default: true)
|
||||
field(:privacy_option, :boolean, default: false)
|
||||
field(:exclude_types, {:array, :string}, default: [])
|
||||
end
|
||||
|
||||
def changeset(schema, params) do
|
||||
schema
|
||||
|> cast(prepare_attrs(params), [
|
||||
:block_from_strangers,
|
||||
:hide_notification_contents
|
||||
:hide_notification_contents,
|
||||
:followers,
|
||||
:follows,
|
||||
:non_follows,
|
||||
:non_followers,
|
||||
:privacy_option,
|
||||
:exclude_types
|
||||
])
|
||||
end
|
||||
|
||||
|
@ -53,7 +53,24 @@ defmodule Pleroma.Web.MastoFEController do
|
||||
|
||||
@doc "PUT /api/web/settings: Backend-obscure settings blob for MastoFE, don't parse/reuse elsewhere"
|
||||
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
|
||||
with {:ok, _} <- User.mastodon_settings_update(user, settings) do
|
||||
with {:ok, user} <- User.mastodon_settings_update(user, settings) do
|
||||
if settings = get_in(user.settings, ["notifications", "shows"]) do
|
||||
notify_settings =
|
||||
Enum.map(settings, fn {k, v} ->
|
||||
if v == false do
|
||||
k
|
||||
end
|
||||
end)
|
||||
|> Enum.filter(& &1)
|
||||
|
||||
notification_settings =
|
||||
user.notification_settings
|
||||
|> Map.from_struct()
|
||||
|> Map.put(:exclude_types, notify_settings)
|
||||
|
||||
User.update_notification_settings(user, notification_settings)
|
||||
end
|
||||
|
||||
json(conn, %{})
|
||||
else
|
||||
e ->
|
||||
|
@ -52,6 +52,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|
||||
def get_notifications(user, params \\ %{}) do
|
||||
options = cast_params(params)
|
||||
|
||||
user_exclude_types = user.notification_settings.exclude_types
|
||||
|
||||
options =
|
||||
if (!options[:exclude_types] or options[:exclude_types] == []) and user_exclude_types != [] do
|
||||
Map.put(options, :exclude_types, user_exclude_types)
|
||||
else
|
||||
options
|
||||
end
|
||||
|
||||
user
|
||||
|> Notification.for_user_query(options)
|
||||
|> restrict(:include_types, options)
|
||||
|
@ -19,7 +19,7 @@ defmodule Pleroma.Web.Push.Impl do
|
||||
@types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact"]
|
||||
|
||||
@doc "Performs sending notifications for user subscriptions"
|
||||
@spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type}
|
||||
@spec perform(Notification.t()) :: {:ok, list(any)} | {:error, :unknown_type}
|
||||
def perform(
|
||||
%{
|
||||
activity: %{data: %{"type" => activity_type}} = activity,
|
||||
@ -164,13 +164,14 @@ defmodule Pleroma.Web.Push.Impl do
|
||||
_object,
|
||||
mastodon_type
|
||||
)
|
||||
when type in ["Follow", "Like"] do
|
||||
when type in ["Follow", "Like", "EmojiReact"] do
|
||||
mastodon_type = mastodon_type || notification.type
|
||||
|
||||
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"
|
||||
"pleroma:emoji_reaction" -> "@#{actor.nickname} has reacted to your post"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -29,7 +29,8 @@ defmodule Pleroma.Web.Push.Subscription do
|
||||
@supported_alert_types ~w[follow favourite mention reblog pleroma:chat_mention pleroma:emoji_reaction]a
|
||||
|
||||
defp alerts(%{data: %{alerts: alerts}}) do
|
||||
alerts = Map.take(alerts, @supported_alert_types)
|
||||
types = Enum.map(Pleroma.Notification.types(), &String.to_atom/1)
|
||||
alerts = Map.take(alerts, types)
|
||||
%{"alerts" => alerts}
|
||||
end
|
||||
|
||||
|
@ -171,8 +171,15 @@ defmodule Pleroma.Web.Streamer do
|
||||
end
|
||||
end
|
||||
|
||||
def filtered_by_user?(%User{} = user, %Notification{activity: activity}, _) do
|
||||
filtered_by_user?(user, activity, :notification)
|
||||
def filtered_by_user?(
|
||||
%User{} = user,
|
||||
%Notification{activity: activity, type: notification_type},
|
||||
_
|
||||
) do
|
||||
notification_settings = user.notification_settings
|
||||
|
||||
notification_type not in notification_settings.exclude_types and
|
||||
filtered_by_user?(user, activity, :notification)
|
||||
end
|
||||
|
||||
defp do_stream("direct", item) do
|
||||
|
@ -0,0 +1,11 @@
|
||||
defmodule Pleroma.Repo.Migrations.AddExcludeTypesIntoUserNotificationSettings do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
execute("""
|
||||
UPDATE users SET notification_settings = jsonb_set(notification_settings, '{exclude_types}', '[]') WHERE local = true;
|
||||
""")
|
||||
end
|
||||
|
||||
def down, do: :ok
|
||||
end
|
@ -408,6 +408,83 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
|
||||
assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200)
|
||||
end
|
||||
|
||||
defp update_notification_settings_and_conn(user, conn, exclude_types) do
|
||||
{:ok, user} =
|
||||
User.update_notification_settings(user, %{
|
||||
"exclude_types" => exclude_types
|
||||
})
|
||||
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> get("/api/v1/notifications")
|
||||
end
|
||||
|
||||
test "filters notifications with user settings for exclude_types" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
|
||||
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
|
||||
{:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
|
||||
{:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
|
||||
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
|
||||
|
||||
mention_notification_id = get_notification_id_by_activity(mention_activity)
|
||||
favorite_notification_id = get_notification_id_by_activity(favorite_activity)
|
||||
reblog_notification_id = get_notification_id_by_activity(reblog_activity)
|
||||
follow_notification_id = get_notification_id_by_activity(follow_activity)
|
||||
|
||||
conn_res =
|
||||
update_notification_settings_and_conn(user, conn, ["mention", "favourite", "reblog"])
|
||||
|
||||
assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
|
||||
|
||||
conn_res =
|
||||
update_notification_settings_and_conn(user, conn, ["favourite", "reblog", "follow"])
|
||||
|
||||
assert [%{"id" => ^mention_notification_id}] =
|
||||
json_response_and_validate_schema(conn_res, 200)
|
||||
|
||||
conn_res = update_notification_settings_and_conn(user, conn, ["reblog", "follow", "mention"])
|
||||
|
||||
assert [%{"id" => ^favorite_notification_id}] =
|
||||
json_response_and_validate_schema(conn_res, 200)
|
||||
|
||||
conn_res =
|
||||
update_notification_settings_and_conn(user, conn, ["follow", "mention", "favourite"])
|
||||
|
||||
assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200)
|
||||
end
|
||||
|
||||
test "exclude_types params have high priority than user settings" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||
|
||||
other_user = insert(:user)
|
||||
|
||||
{:ok, _mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
|
||||
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
|
||||
{:ok, _favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
|
||||
{:ok, _reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
|
||||
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
|
||||
|
||||
follow_notification_id = get_notification_id_by_activity(follow_activity)
|
||||
|
||||
{:ok, user} =
|
||||
User.update_notification_settings(user, %{
|
||||
"exclude_types" => ["favourite", "reblog", "follow", "mention"]
|
||||
})
|
||||
|
||||
query = params_to_query(%{exclude_types: ["mention", "favourite", "reblog"]})
|
||||
|
||||
conn_res =
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> get("/api/v1/notifications?" <> query)
|
||||
|
||||
assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200)
|
||||
end
|
||||
|
||||
test "filters notifications using include_types" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||
other_user = insert(:user)
|
||||
|
@ -11,19 +11,96 @@ defmodule Pleroma.Web.MastodonAPI.MastoFEControllerTest do
|
||||
|
||||
setup do: clear_config([:instance, :public])
|
||||
|
||||
test "put settings", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
describe "put_settings/2" do
|
||||
setup do
|
||||
%{conn: conn, user: user} = oauth_access(["write:accounts"])
|
||||
[conn: conn, user: user]
|
||||
end
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:accounts"]))
|
||||
|> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
|
||||
test "common", %{conn: conn, user: user} do
|
||||
assert conn
|
||||
|> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
|
||||
|> json_response(200)
|
||||
|
||||
assert _result = json_response(conn, 200)
|
||||
user = User.get_cached_by_ap_id(user.ap_id)
|
||||
assert user.mastofe_settings == %{"programming" => "socks"}
|
||||
end
|
||||
|
||||
user = User.get_cached_by_ap_id(user.ap_id)
|
||||
assert user.mastofe_settings == %{"programming" => "socks"}
|
||||
test "saves notification settings", %{conn: conn, user: user} do
|
||||
assert conn
|
||||
|> put("/api/web/settings", %{
|
||||
"data" => %{
|
||||
"notifications" => %{
|
||||
"alerts" => %{
|
||||
"favourite" => true,
|
||||
"follow" => true,
|
||||
"follow_request" => true,
|
||||
"mention" => true,
|
||||
"poll" => true,
|
||||
"reblog" => true
|
||||
},
|
||||
"quickFilter" => %{"active" => "all", "advanced" => true, "show" => true},
|
||||
"shows" => %{
|
||||
"favourite" => false,
|
||||
"follow" => false,
|
||||
"follow_request" => false,
|
||||
"mention" => false,
|
||||
"poll" => false,
|
||||
"reblog" => false
|
||||
},
|
||||
"sounds" => %{
|
||||
"favourite" => true,
|
||||
"follow" => true,
|
||||
"follow_request" => true,
|
||||
"mention" => true,
|
||||
"poll" => true,
|
||||
"reblog" => true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
user = User.get_cached_by_ap_id(user.ap_id)
|
||||
|
||||
assert user.settings == %{
|
||||
"notifications" => %{
|
||||
"alerts" => %{
|
||||
"favourite" => true,
|
||||
"follow" => true,
|
||||
"follow_request" => true,
|
||||
"mention" => true,
|
||||
"poll" => true,
|
||||
"reblog" => true
|
||||
},
|
||||
"quickFilter" => %{"active" => "all", "advanced" => true, "show" => true},
|
||||
"shows" => %{
|
||||
"favourite" => false,
|
||||
"follow" => false,
|
||||
"follow_request" => false,
|
||||
"mention" => false,
|
||||
"poll" => false,
|
||||
"reblog" => false
|
||||
},
|
||||
"sounds" => %{
|
||||
"favourite" => true,
|
||||
"follow" => true,
|
||||
"follow_request" => true,
|
||||
"mention" => true,
|
||||
"poll" => true,
|
||||
"reblog" => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert user.notification_settings.exclude_types == [
|
||||
"favourite",
|
||||
"follow",
|
||||
"follow_request",
|
||||
"mention",
|
||||
"poll",
|
||||
"reblog"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "index/2 redirections" do
|
||||
|
@ -125,6 +125,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
|
||||
notification_settings = %{
|
||||
block_from_strangers: false,
|
||||
hide_notification_contents: false
|
||||
followers: true,
|
||||
follows: true,
|
||||
non_followers: true,
|
||||
non_follows: true,
|
||||
privacy_option: false,
|
||||
exclude_types: []
|
||||
}
|
||||
|
||||
privacy = user.default_scope
|
||||
|
@ -69,6 +69,27 @@ defmodule Pleroma.Web.Push.ImplTest do
|
||||
assert Impl.perform(notif) == {:ok, [:ok, :ok]}
|
||||
end
|
||||
|
||||
test "notification for follow_request" do
|
||||
user = insert(:user)
|
||||
reaction_user = insert(:user)
|
||||
|
||||
insert(:push_subscription, user: user, data: %{alerts: %{"pleroma:emoji_reaction" => true}})
|
||||
insert(:push_subscription, user: user, data: %{alerts: %{"pleroma:emoji_reaction" => false}})
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "<Lorem ipsum dolor sit amet."})
|
||||
|
||||
{:ok, reaction_activity} = CommonAPI.react_with_emoji(activity.id, reaction_user, "☕")
|
||||
|
||||
notif =
|
||||
insert(:notification,
|
||||
user: user,
|
||||
activity: reaction_activity,
|
||||
type: "pleroma:emoji_reaction"
|
||||
)
|
||||
|
||||
assert Impl.perform(notif) == {:ok, [:ok]}
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "returns error if notif does not match " do
|
||||
assert Impl.perform(%{}) == {:error, :unknown_type}
|
||||
|
@ -28,6 +28,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
||||
|> put("/api/pleroma/notification_settings", %{
|
||||
"block_from_strangers" => true,
|
||||
"bar" => 1
|
||||
"followers" => false,
|
||||
"bar" => 1,
|
||||
"exclude_types" => ["follow"]
|
||||
})
|
||||
|> json_response(:ok)
|
||||
|
||||
@ -36,6 +39,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
||||
assert %Pleroma.User.NotificationSetting{
|
||||
block_from_strangers: true,
|
||||
hide_notification_contents: false
|
||||
followers: false,
|
||||
follows: true,
|
||||
non_follows: true,
|
||||
non_followers: true,
|
||||
privacy_option: false,
|
||||
exclude_types: ["follow"]
|
||||
} == user.notification_settings
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user