forked from AkkomaGang/akkoma
Merge branch 'notification-pleroma-settings' into 'develop'
Notification controls Closes #738 See merge request pleroma/pleroma!988
This commit is contained in:
commit
97395e013e
10 changed files with 217 additions and 14 deletions
|
@ -116,3 +116,13 @@ See [Admin-API](Admin-API.md)
|
|||
* Params:
|
||||
* `id`: notifications's id
|
||||
* Response: JSON. Returns `{"status": "success"}` if the reading was successful, otherwise returns `{"error": "error_msg"}`
|
||||
## `/api/pleroma/notification_settings`
|
||||
### Updates user notification settings
|
||||
* Method `PUT`
|
||||
* Authentication: required
|
||||
* Params:
|
||||
* `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
|
||||
* Response: JSON. Returns `{"status": "success"}` if the update was successful, otherwise returns `{"error": "error_msg"}`
|
||||
|
|
|
@ -122,13 +122,7 @@ def create_notifications(_), do: {:ok, []}
|
|||
|
||||
# TODO move to sql, too.
|
||||
def create_notification(%Activity{} = activity, %User{} = user) do
|
||||
unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or
|
||||
CommonAPI.thread_muted?(user, activity) or user.ap_id == activity.data["actor"] or
|
||||
(activity.data["type"] == "Follow" and
|
||||
Enum.any?(Notification.for_user(user), fn notif ->
|
||||
notif.activity.data["type"] == "Follow" and
|
||||
notif.activity.data["actor"] == activity.data["actor"]
|
||||
end)) do
|
||||
unless skip?(activity, user) do
|
||||
notification = %Notification{user_id: user.id, activity: activity}
|
||||
{:ok, notification} = Repo.insert(notification)
|
||||
Pleroma.Web.Streamer.stream("user", notification)
|
||||
|
@ -154,4 +148,59 @@ def get_notified_from_activity(
|
|||
end
|
||||
|
||||
def get_notified_from_activity(_, _local_only), do: []
|
||||
|
||||
def skip?(activity, user) do
|
||||
[:self, :blocked, :local, :muted, :followers, :follows, :recently_followed]
|
||||
|> Enum.any?(&skip?(&1, activity, user))
|
||||
end
|
||||
|
||||
def skip?(:self, activity, user) do
|
||||
activity.data["actor"] == user.ap_id
|
||||
end
|
||||
|
||||
def skip?(:blocked, activity, user) do
|
||||
actor = activity.data["actor"]
|
||||
User.blocks?(user, %{ap_id: actor})
|
||||
end
|
||||
|
||||
def skip?(:local, %{local: true}, %{info: %{notification_settings: %{"local" => false}}}),
|
||||
do: true
|
||||
|
||||
def skip?(:local, %{local: false}, %{info: %{notification_settings: %{"remote" => false}}}),
|
||||
do: true
|
||||
|
||||
def skip?(:muted, activity, user) do
|
||||
actor = activity.data["actor"]
|
||||
|
||||
User.mutes?(user, %{ap_id: actor}) or
|
||||
CommonAPI.thread_muted?(user, activity)
|
||||
end
|
||||
|
||||
def skip?(
|
||||
:followers,
|
||||
activity,
|
||||
%{info: %{notification_settings: %{"followers" => false}}} = user
|
||||
) do
|
||||
actor = activity.data["actor"]
|
||||
follower = User.get_cached_by_ap_id(actor)
|
||||
User.following?(follower, user)
|
||||
end
|
||||
|
||||
def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do
|
||||
actor = activity.data["actor"]
|
||||
followed = User.get_by_ap_id(actor)
|
||||
User.following?(user, followed)
|
||||
end
|
||||
|
||||
def skip?(:recently_followed, %{data: %{"type" => "Follow"}} = activity, user) do
|
||||
actor = activity.data["actor"]
|
||||
|
||||
Notification.for_user(user)
|
||||
|> Enum.any?(fn
|
||||
%{activity: %{data: %{"type" => "Follow", "actor" => ^actor}}} -> true
|
||||
_ -> false
|
||||
end)
|
||||
end
|
||||
|
||||
def skip?(_, _, _), do: false
|
||||
end
|
||||
|
|
|
@ -1092,6 +1092,14 @@ def deactivate(%User{} = user, status \\ true) do
|
|||
update_and_set_cache(cng)
|
||||
end
|
||||
|
||||
def update_notification_settings(%User{} = user, settings \\ %{}) do
|
||||
info_changeset = User.Info.update_notification_settings(user.info, settings)
|
||||
|
||||
change(user)
|
||||
|> put_embed(:info, info_changeset)
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
def delete(%User{} = user) do
|
||||
{:ok, user} = User.deactivate(user)
|
||||
|
||||
|
|
|
@ -40,6 +40,10 @@ defmodule Pleroma.User.Info do
|
|||
field(:pinned_activities, {:array, :string}, default: [])
|
||||
field(:flavour, :string, default: nil)
|
||||
|
||||
field(:notification_settings, :map,
|
||||
default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true}
|
||||
)
|
||||
|
||||
# Found in the wild
|
||||
# ap_id -> Where is this used?
|
||||
# bio -> Where is this used?
|
||||
|
@ -57,6 +61,19 @@ def set_activation_status(info, deactivated) do
|
|||
|> validate_required([:deactivated])
|
||||
end
|
||||
|
||||
def update_notification_settings(info, settings) do
|
||||
notification_settings =
|
||||
info.notification_settings
|
||||
|> Map.merge(settings)
|
||||
|> Map.take(["remote", "local", "followers", "follows"])
|
||||
|
||||
params = %{notification_settings: notification_settings}
|
||||
|
||||
info
|
||||
|> cast(params, [:notification_settings])
|
||||
|> validate_required([:notification_settings])
|
||||
end
|
||||
|
||||
def add_to_note_count(info, number) do
|
||||
set_note_count(info, info.note_count + number)
|
||||
end
|
||||
|
|
|
@ -117,13 +117,15 @@ defp do_render("account.json", %{user: user} = opts) do
|
|||
},
|
||||
|
||||
# Pleroma extension
|
||||
pleroma: %{
|
||||
confirmation_pending: user_info.confirmation_pending,
|
||||
tags: user.tags,
|
||||
is_moderator: user.info.is_moderator,
|
||||
is_admin: user.info.is_admin,
|
||||
relationship: relationship
|
||||
}
|
||||
pleroma:
|
||||
%{
|
||||
confirmation_pending: user_info.confirmation_pending,
|
||||
tags: user.tags,
|
||||
is_moderator: user.info.is_moderator,
|
||||
is_admin: user.info.is_admin,
|
||||
relationship: relationship
|
||||
}
|
||||
|> with_notification_settings(user, opts[:for])
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -132,4 +134,10 @@ defp username_from_nickname(string) when is_binary(string) do
|
|||
end
|
||||
|
||||
defp username_from_nickname(_), do: nil
|
||||
|
||||
defp with_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
|
||||
Map.put(data, :notification_settings, user.info.notification_settings)
|
||||
end
|
||||
|
||||
defp with_notification_settings(data, _, _), do: data
|
||||
end
|
||||
|
|
|
@ -193,6 +193,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
post("/change_password", UtilController, :change_password)
|
||||
post("/delete_account", UtilController, :delete_account)
|
||||
put("/notification_settings", UtilController, :update_notificaton_settings)
|
||||
end
|
||||
|
||||
scope [] do
|
||||
|
|
|
@ -292,6 +292,12 @@ def emoji(conn, _params) do
|
|||
json(conn, emoji)
|
||||
end
|
||||
|
||||
def update_notificaton_settings(%{assigns: %{user: user}} = conn, params) do
|
||||
with {:ok, _} <- User.update_notification_settings(user, params) do
|
||||
json(conn, %{status: "success"})
|
||||
end
|
||||
end
|
||||
|
||||
def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
|
||||
follow_import(conn, %{"list" => File.read!(listfile.path)})
|
||||
end
|
||||
|
|
|
@ -41,6 +41,75 @@ test "it doesn't create a notification for user if the user blocks the activity
|
|||
assert nil == Notification.create_notification(activity, user)
|
||||
end
|
||||
|
||||
test "it doesn't create a notificatin for the user if the user mutes the activity author" do
|
||||
muter = insert(:user)
|
||||
muted = insert(:user)
|
||||
{:ok, _} = User.mute(muter, muted)
|
||||
muter = Repo.get(User, muter.id)
|
||||
{:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
|
||||
|
||||
assert nil == Notification.create_notification(activity, muter)
|
||||
end
|
||||
|
||||
test "it doesn't create a notification for an activity from a muted thread" do
|
||||
muter = insert(:user)
|
||||
other_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(muter, %{"status" => "hey"})
|
||||
CommonAPI.add_mute(muter, activity)
|
||||
|
||||
{:ok, activity} =
|
||||
CommonAPI.post(other_user, %{
|
||||
"status" => "Hi @#{muter.nickname}",
|
||||
"in_reply_to_status_id" => activity.id
|
||||
})
|
||||
|
||||
assert nil == Notification.create_notification(activity, muter)
|
||||
end
|
||||
|
||||
test "it disables notifications from people on remote instances" do
|
||||
user = insert(:user, info: %{notification_settings: %{"remote" => false}})
|
||||
other_user = insert(:user)
|
||||
|
||||
create_activity = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Create",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"actor" => other_user.ap_id,
|
||||
"object" => %{
|
||||
"type" => "Note",
|
||||
"content" => "Hi @#{user.nickname}",
|
||||
"attributedTo" => other_user.ap_id
|
||||
}
|
||||
}
|
||||
|
||||
{:ok, %{local: false} = activity} = Transmogrifier.handle_incoming(create_activity)
|
||||
assert nil == Notification.create_notification(activity, user)
|
||||
end
|
||||
|
||||
test "it disables notifications from people on the local instance" do
|
||||
user = insert(:user, info: %{notification_settings: %{"local" => false}})
|
||||
other_user = insert(:user)
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
|
||||
assert nil == Notification.create_notification(activity, user)
|
||||
end
|
||||
|
||||
test "it disables notifications from followers" do
|
||||
follower = insert(:user)
|
||||
followed = insert(:user, info: %{notification_settings: %{"followers" => false}})
|
||||
User.follow(follower, followed)
|
||||
{:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
|
||||
assert nil == Notification.create_notification(activity, followed)
|
||||
end
|
||||
|
||||
test "it disables notifications from people the user follows" do
|
||||
follower = insert(:user, info: %{notification_settings: %{"follows" => false}})
|
||||
followed = insert(:user)
|
||||
User.follow(follower, followed)
|
||||
follower = Repo.get(User, follower.id)
|
||||
{:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
|
||||
assert nil == Notification.create_notification(activity, follower)
|
||||
end
|
||||
|
||||
test "it doesn't create a notification for user if he is the activity author" do
|
||||
activity = insert(:note_activity)
|
||||
author = User.get_by_ap_id(activity.data["actor"])
|
||||
|
|
|
@ -71,6 +71,20 @@ test "Represent a user account" do
|
|||
assert expected == AccountView.render("account.json", %{user: user})
|
||||
end
|
||||
|
||||
test "Represent the user account for the account owner" do
|
||||
user = insert(:user)
|
||||
|
||||
notification_settings = %{
|
||||
"remote" => true,
|
||||
"local" => true,
|
||||
"followers" => true,
|
||||
"follows" => true
|
||||
}
|
||||
|
||||
assert %{pleroma: %{notification_settings: ^notification_settings}} =
|
||||
AccountView.render("account.json", %{user: user, for: user})
|
||||
end
|
||||
|
||||
test "Represent a Service(bot) account" do
|
||||
user =
|
||||
insert(:user, %{
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
import Pleroma.Factory
|
||||
|
||||
|
@ -79,6 +80,26 @@ test "it marks a single notification as read", %{conn: conn} do
|
|||
end
|
||||
end
|
||||
|
||||
describe "PUT /api/pleroma/notification_settings" do
|
||||
test "it updates notification settings", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> put("/api/pleroma/notification_settings", %{
|
||||
"remote" => false,
|
||||
"followers" => false,
|
||||
"bar" => 1
|
||||
})
|
||||
|> json_response(:ok)
|
||||
|
||||
user = Repo.get(User, user.id)
|
||||
|
||||
assert %{"remote" => false, "local" => true, "followers" => false, "follows" => true} ==
|
||||
user.info.notification_settings
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/statusnet/config.json" do
|
||||
test "returns the state of safe_dm_mentions flag", %{conn: conn} do
|
||||
option = Pleroma.Config.get([:instance, :safe_dm_mentions])
|
||||
|
|
Loading…
Reference in a new issue