Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into pleroma-moderation-log-stuff
This commit is contained in:
commit
bea69853a2
10 changed files with 190 additions and 114 deletions
|
@ -134,6 +134,10 @@
|
||||||
|
|
||||||
config :pleroma, :cachex, provider: Pleroma.CachexMock
|
config :pleroma, :cachex, provider: Pleroma.CachexMock
|
||||||
|
|
||||||
|
config :pleroma, :side_effects,
|
||||||
|
ap_streamer: Pleroma.Web.ActivityPub.ActivityPubMock,
|
||||||
|
logger: Pleroma.LoggerMock
|
||||||
|
|
||||||
if File.exists?("./config/test.secret.exs") do
|
if File.exists?("./config/test.secret.exs") do
|
||||||
import_config "test.secret.exs"
|
import_config "test.secret.exs"
|
||||||
else
|
else
|
||||||
|
|
7
lib/pleroma/logging.ex
Normal file
7
lib/pleroma/logging.ex
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Logging do
|
||||||
|
@callback error(String.t()) :: any()
|
||||||
|
end
|
|
@ -33,6 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.ActivityPub.Persisting
|
@behaviour Pleroma.Web.ActivityPub.ActivityPub.Persisting
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.ActivityPub.Streaming
|
||||||
|
|
||||||
defp get_recipients(%{"type" => "Create"} = data) do
|
defp get_recipients(%{"type" => "Create"} = data) do
|
||||||
to = Map.get(data, "to", [])
|
to = Map.get(data, "to", [])
|
||||||
|
@ -224,6 +225,7 @@ def stream_out_participations(participations) do
|
||||||
Streamer.stream("participation", participations)
|
Streamer.stream("participation", participations)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def stream_out_participations(%Object{data: %{"context" => context}}, user) do
|
def stream_out_participations(%Object{data: %{"context" => context}}, user) do
|
||||||
with %Conversation{} = conversation <- Conversation.get_for_ap_id(context) do
|
with %Conversation{} = conversation <- Conversation.get_for_ap_id(context) do
|
||||||
conversation = Repo.preload(conversation, :participations)
|
conversation = Repo.preload(conversation, :participations)
|
||||||
|
@ -240,8 +242,10 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def stream_out_participations(_, _), do: :noop
|
def stream_out_participations(_, _), do: :noop
|
||||||
|
|
||||||
|
@impl true
|
||||||
def stream_out(%Activity{data: %{"type" => data_type}} = activity)
|
def stream_out(%Activity{data: %{"type" => data_type}} = activity)
|
||||||
when data_type in ["Create", "Announce", "Delete"] do
|
when data_type in ["Create", "Announce", "Delete"] do
|
||||||
activity
|
activity
|
||||||
|
@ -249,6 +253,7 @@ def stream_out(%Activity{data: %{"type" => data_type}} = activity)
|
||||||
|> Streamer.stream(activity)
|
|> Streamer.stream(activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def stream_out(_activity) do
|
def stream_out(_activity) do
|
||||||
:noop
|
:noop
|
||||||
end
|
end
|
||||||
|
|
12
lib/pleroma/web/activity_pub/activity_pub/streaming.ex
Normal file
12
lib/pleroma/web/activity_pub/activity_pub/streaming.ex
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.ActivityPub.Streaming do
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@callback stream_out(Activity.t()) :: any()
|
||||||
|
@callback stream_out_participations(Object.t(), User.t()) :: any()
|
||||||
|
end
|
|
@ -28,6 +28,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||||
|
@ap_streamer Pleroma.Config.get([:side_effects, :ap_streamer], ActivityPub)
|
||||||
|
@logger Pleroma.Config.get([:side_effects, :logger], Logger)
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.SideEffects.Handling
|
@behaviour Pleroma.Web.ActivityPub.SideEffects.Handling
|
||||||
|
|
||||||
|
@ -287,12 +289,12 @@ def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object,
|
||||||
|
|
||||||
MessageReference.delete_for_object(deleted_object)
|
MessageReference.delete_for_object(deleted_object)
|
||||||
|
|
||||||
ActivityPub.stream_out(object)
|
@ap_streamer.stream_out(object)
|
||||||
ActivityPub.stream_out_participations(deleted_object, user)
|
@ap_streamer.stream_out_participations(deleted_object, user)
|
||||||
:ok
|
:ok
|
||||||
else
|
else
|
||||||
{:actor, _} ->
|
{:actor, _} ->
|
||||||
Logger.error("The object doesn't have an actor: #{inspect(deleted_object)}")
|
@logger.error("The object doesn't have an actor: #{inspect(deleted_object)}")
|
||||||
:no_object_actor
|
:no_object_actor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
147
test/pleroma/web/activity_pub/side_effects/delete_test.exs
Normal file
147
test/pleroma/web/activity_pub/side_effects/delete_test.exs
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.SideEffects.DeleteTest do
|
||||||
|
use Oban.Testing, repo: Pleroma.Repo
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Tests.ObanHelpers
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
|
alias Pleroma.Web.ActivityPub.SideEffects
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
alias Pleroma.LoggerMock
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPubMock
|
||||||
|
|
||||||
|
import Mox
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
describe "user deletion" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
|
||||||
|
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
|
||||||
|
|
||||||
|
%{
|
||||||
|
user: user,
|
||||||
|
delete_user: delete_user
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it handles user deletions", %{delete_user: delete, user: user} do
|
||||||
|
{:ok, _delete, _} = SideEffects.handle(delete)
|
||||||
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
|
assert User.get_cached_by_ap_id(user.ap_id).deactivated
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "object deletion" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
|
||||||
|
{:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
|
||||||
|
{:ok, favorite} = CommonAPI.favorite(user, post.id)
|
||||||
|
object = Object.normalize(post)
|
||||||
|
{:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
|
||||||
|
{:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
|
||||||
|
|
||||||
|
%{
|
||||||
|
user: user,
|
||||||
|
delete: delete,
|
||||||
|
post: post,
|
||||||
|
object: object,
|
||||||
|
op: op,
|
||||||
|
favorite: favorite
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it handles object deletions", %{
|
||||||
|
delete: delete,
|
||||||
|
post: post,
|
||||||
|
object: object,
|
||||||
|
user: user,
|
||||||
|
op: op,
|
||||||
|
favorite: favorite
|
||||||
|
} do
|
||||||
|
object_id = object.id
|
||||||
|
user_id = user.id
|
||||||
|
|
||||||
|
ActivityPubMock
|
||||||
|
|> expect(:stream_out, fn ^delete -> nil end)
|
||||||
|
|> expect(:stream_out_participations, fn %Object{id: ^object_id}, %User{id: ^user_id} ->
|
||||||
|
nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:ok, _delete, _} = SideEffects.handle(delete)
|
||||||
|
user = User.get_cached_by_ap_id(object.data["actor"])
|
||||||
|
|
||||||
|
object = Object.get_by_id(object.id)
|
||||||
|
assert object.data["type"] == "Tombstone"
|
||||||
|
refute Activity.get_by_id(post.id)
|
||||||
|
refute Activity.get_by_id(favorite.id)
|
||||||
|
|
||||||
|
user = User.get_by_id(user.id)
|
||||||
|
assert user.note_count == 0
|
||||||
|
|
||||||
|
object = Object.normalize(op.data["object"], false)
|
||||||
|
|
||||||
|
assert object.data["repliesCount"] == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it handles object deletions when the object itself has been pruned", %{
|
||||||
|
delete: delete,
|
||||||
|
post: post,
|
||||||
|
object: object,
|
||||||
|
user: user,
|
||||||
|
op: op
|
||||||
|
} do
|
||||||
|
object_id = object.id
|
||||||
|
user_id = user.id
|
||||||
|
|
||||||
|
ActivityPubMock
|
||||||
|
|> expect(:stream_out, fn ^delete -> nil end)
|
||||||
|
|> expect(:stream_out_participations, fn %Object{id: ^object_id}, %User{id: ^user_id} ->
|
||||||
|
nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:ok, _delete, _} = SideEffects.handle(delete)
|
||||||
|
user = User.get_cached_by_ap_id(object.data["actor"])
|
||||||
|
|
||||||
|
object = Object.get_by_id(object.id)
|
||||||
|
assert object.data["type"] == "Tombstone"
|
||||||
|
refute Activity.get_by_id(post.id)
|
||||||
|
|
||||||
|
user = User.get_by_id(user.id)
|
||||||
|
assert user.note_count == 0
|
||||||
|
|
||||||
|
object = Object.normalize(op.data["object"], false)
|
||||||
|
|
||||||
|
assert object.data["repliesCount"] == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it logs issues with objects deletion", %{
|
||||||
|
delete: delete,
|
||||||
|
object: object
|
||||||
|
} do
|
||||||
|
{:ok, _object} =
|
||||||
|
object
|
||||||
|
|> Object.change(%{data: Map.delete(object.data, "actor")})
|
||||||
|
|> Repo.update()
|
||||||
|
|
||||||
|
LoggerMock
|
||||||
|
|> expect(:error, fn str -> assert str =~ "The object doesn't have an actor" end)
|
||||||
|
|
||||||
|
{:error, :no_object_actor} = SideEffects.handle(delete)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -19,7 +19,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
||||||
alias Pleroma.Web.ActivityPub.SideEffects
|
alias Pleroma.Web.ActivityPub.SideEffects
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
import ExUnit.CaptureLog
|
|
||||||
import Mock
|
import Mock
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
@ -131,115 +130,6 @@ test "it uses a given changeset to update", %{user: user, update: update} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "delete objects" do
|
|
||||||
setup do
|
|
||||||
user = insert(:user)
|
|
||||||
other_user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
|
|
||||||
{:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
|
|
||||||
{:ok, favorite} = CommonAPI.favorite(user, post.id)
|
|
||||||
object = Object.normalize(post)
|
|
||||||
{:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
|
|
||||||
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
|
|
||||||
{:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
|
|
||||||
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
|
|
||||||
|
|
||||||
%{
|
|
||||||
user: user,
|
|
||||||
delete: delete,
|
|
||||||
post: post,
|
|
||||||
object: object,
|
|
||||||
delete_user: delete_user,
|
|
||||||
op: op,
|
|
||||||
favorite: favorite
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it handles object deletions", %{
|
|
||||||
delete: delete,
|
|
||||||
post: post,
|
|
||||||
object: object,
|
|
||||||
user: user,
|
|
||||||
op: op,
|
|
||||||
favorite: favorite
|
|
||||||
} do
|
|
||||||
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
|
|
||||||
stream_out: fn _ -> nil end,
|
|
||||||
stream_out_participations: fn _, _ -> nil end do
|
|
||||||
{:ok, delete, _} = SideEffects.handle(delete)
|
|
||||||
user = User.get_cached_by_ap_id(object.data["actor"])
|
|
||||||
|
|
||||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
|
|
||||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
|
|
||||||
end
|
|
||||||
|
|
||||||
object = Object.get_by_id(object.id)
|
|
||||||
assert object.data["type"] == "Tombstone"
|
|
||||||
refute Activity.get_by_id(post.id)
|
|
||||||
refute Activity.get_by_id(favorite.id)
|
|
||||||
|
|
||||||
user = User.get_by_id(user.id)
|
|
||||||
assert user.note_count == 0
|
|
||||||
|
|
||||||
object = Object.normalize(op.data["object"], false)
|
|
||||||
|
|
||||||
assert object.data["repliesCount"] == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it handles object deletions when the object itself has been pruned", %{
|
|
||||||
delete: delete,
|
|
||||||
post: post,
|
|
||||||
object: object,
|
|
||||||
user: user,
|
|
||||||
op: op
|
|
||||||
} do
|
|
||||||
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
|
|
||||||
stream_out: fn _ -> nil end,
|
|
||||||
stream_out_participations: fn _, _ -> nil end do
|
|
||||||
{:ok, delete, _} = SideEffects.handle(delete)
|
|
||||||
user = User.get_cached_by_ap_id(object.data["actor"])
|
|
||||||
|
|
||||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
|
|
||||||
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
|
|
||||||
end
|
|
||||||
|
|
||||||
object = Object.get_by_id(object.id)
|
|
||||||
assert object.data["type"] == "Tombstone"
|
|
||||||
refute Activity.get_by_id(post.id)
|
|
||||||
|
|
||||||
user = User.get_by_id(user.id)
|
|
||||||
assert user.note_count == 0
|
|
||||||
|
|
||||||
object = Object.normalize(op.data["object"], false)
|
|
||||||
|
|
||||||
assert object.data["repliesCount"] == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it handles user deletions", %{delete_user: delete, user: user} do
|
|
||||||
{:ok, _delete, _} = SideEffects.handle(delete)
|
|
||||||
ObanHelpers.perform_all()
|
|
||||||
|
|
||||||
assert User.get_cached_by_ap_id(user.ap_id).deactivated
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it logs issues with objects deletion", %{
|
|
||||||
delete: delete,
|
|
||||||
object: object
|
|
||||||
} do
|
|
||||||
{:ok, object} =
|
|
||||||
object
|
|
||||||
|> Object.change(%{data: Map.delete(object.data, "actor")})
|
|
||||||
|> Repo.update()
|
|
||||||
|
|
||||||
Object.invalid_object_cache(object)
|
|
||||||
|
|
||||||
assert capture_log(fn ->
|
|
||||||
{:error, :no_object_actor} = SideEffects.handle(delete)
|
|
||||||
end) =~ "object doesn't have an actor"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "EmojiReact objects" do
|
describe "EmojiReact objects" do
|
||||||
setup do
|
setup do
|
||||||
poster = insert(:user)
|
poster = insert(:user)
|
||||||
|
|
|
@ -138,6 +138,8 @@ defp json_response_and_validate_schema(conn, _status) do
|
||||||
|
|
||||||
Pleroma.DataCase.stub_pipeline()
|
Pleroma.DataCase.stub_pipeline()
|
||||||
|
|
||||||
|
Mox.verify_on_exit!()
|
||||||
|
|
||||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -85,6 +85,8 @@ def clear_cachex do
|
||||||
|
|
||||||
stub_pipeline()
|
stub_pipeline()
|
||||||
|
|
||||||
|
Mox.verify_on_exit!()
|
||||||
|
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,10 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
Mox.defmock(Pleroma.Web.ActivityPub.ActivityPubMock,
|
Mox.defmock(Pleroma.Web.ActivityPub.ActivityPubMock,
|
||||||
for: Pleroma.Web.ActivityPub.ActivityPub.Persisting
|
for: [
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.Persisting,
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.Streaming
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
Mox.defmock(Pleroma.Web.ActivityPub.SideEffectsMock,
|
Mox.defmock(Pleroma.Web.ActivityPub.SideEffectsMock,
|
||||||
|
@ -23,3 +26,5 @@
|
||||||
Mox.defmock(Pleroma.Web.FederatorMock, for: Pleroma.Web.Federator.Publishing)
|
Mox.defmock(Pleroma.Web.FederatorMock, for: Pleroma.Web.Federator.Publishing)
|
||||||
|
|
||||||
Mox.defmock(Pleroma.ConfigMock, for: Pleroma.Config.Getting)
|
Mox.defmock(Pleroma.ConfigMock, for: Pleroma.Config.Getting)
|
||||||
|
|
||||||
|
Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging)
|
||||||
|
|
Loading…
Reference in a new issue