summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlain <lain@soykaf.club>2020-05-20 15:44:37 +0200
committerlain <lain@soykaf.club>2020-05-20 15:44:37 +0200
commite42bc5f55732d42bf40ed9129ec737e654a911b8 (patch)
tree7d9ff56c7c810fa293dd8011001aef5aff43a42a
parentc7cdc553ff9bd7a068274d9b4b71008d9df04723 (diff)
Announcements: Handle through common pipeline.
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex30
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex15
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex2
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/announce_validator.ex5
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex12
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex19
-rw-r--r--lib/pleroma/web/common_api/common_api.ex23
-rw-r--r--test/fixtures/mastodon-note-object.json50
-rw-r--r--test/web/activity_pub/side_effects_test.exs25
-rw-r--r--test/web/activity_pub/transmogrifier/announce_handling_test.exs20
-rw-r--r--test/web/common_api/common_api_test.exs13
11 files changed, 135 insertions, 79 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index d752f4f04..2cea55285 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -356,36 +356,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- @spec announce(User.t(), Object.t(), String.t() | nil, boolean(), boolean()) ::
- {:ok, Activity.t(), Object.t()} | {:error, any()}
- def announce(
- %User{ap_id: _} = user,
- %Object{data: %{"id" => _}} = object,
- activity_id \\ nil,
- local \\ true,
- public \\ true
- ) do
- with {:ok, result} <-
- Repo.transaction(fn -> do_announce(user, object, activity_id, local, public) end) do
- result
- end
- end
-
- defp do_announce(user, object, activity_id, local, public) do
- with true <- is_announceable?(object, user, public),
- object <- Object.get_by_id(object.id),
- announce_data <- make_announce_data(user, object, activity_id, public),
- {:ok, activity} <- insert(announce_data, local),
- {:ok, object} <- add_announce_to_object(activity, object),
- _ <- notify_and_stream(activity),
- :ok <- maybe_federate(activity) do
- {:ok, activity, object}
- else
- false -> {:error, false}
- {:error, error} -> Repo.rollback(error)
- end
- end
-
@spec follow(User.t(), User.t(), String.t() | nil, boolean()) ::
{:ok, Activity.t()} | {:error, any()}
def follow(follower, followed, activity_id \\ nil, local \\ true) do
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 63f89c2b4..7ece764f5 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -10,6 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
+ require Pleroma.Constants
+
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do
@@ -83,9 +85,17 @@ defmodule Pleroma.Web.ActivityPub.Builder do
end
end
- def announce(actor, object) do
+ def announce(actor, object, options \\ []) do
+ public? = Keyword.get(options, :public, false)
to = [actor.follower_address, object.data["actor"]]
+ to =
+ if public? do
+ [Pleroma.Constants.as_public() | to]
+ else
+ to
+ end
+
{:ok,
%{
"id" => Utils.generate_activity_id(),
@@ -93,7 +103,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"object" => object.data["id"],
"to" => to,
"context" => object.data["context"],
- "type" => "Announce"
+ "type" => "Announce",
+ "published" => Utils.make_date()
}, []}
end
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 600e58123..2599067a8 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -88,7 +88,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
def fetch_actor_and_object(object) do
fetch_actor(object)
- Object.normalize(object["object"])
+ Object.normalize(object["object"], true)
:ok
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
index 158ae199d..082fdea4d 100644
--- a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
@@ -18,9 +18,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
field(:type, :string)
field(:object, Types.ObjectID)
field(:actor, Types.ObjectID)
- field(:context, :string)
+ field(:context, :string, autogenerate: {Utils, :generate_context_id, []})
field(:to, Types.Recipients, default: [])
field(:cc, Types.Recipients, default: [])
+ field(:published, Types.DateTime)
end
def cast_and_validate(data) do
@@ -47,7 +48,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
def validate_data(data_cng) do
data_cng
|> validate_inclusion(:type, ["Announce"])
- |> validate_required([:id, :type, :object, :actor, :context, :to, :cc])
+ |> validate_required([:id, :type, :object, :actor, :to, :cc])
|> validate_actor_presence()
|> validate_object_presence()
|> validate_existing_announce()
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index bfc2ab845..bc0d31c45 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -27,6 +27,18 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:ok, object, meta}
end
+ # Tasks this handles:
+ # - Add announce to object
+ # - Set up notification
+ def handle(%{data: %{"type" => "Announce"}} = object, meta) do
+ announced_object = Object.get_by_ap_id(object.data["object"])
+ Utils.add_announce_to_object(object, announced_object)
+
+ Notification.create_notifications(object)
+
+ {:ok, object, meta}
+ end
+
def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
with undone_object <- Activity.get_by_ap_id(undone_object),
:ok <- handle_undoing(undone_object) do
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 6104af4f9..d594c64f4 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -662,7 +662,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> handle_incoming(options)
end
- def handle_incoming(%{"type" => type} = data, _options) when type in ["Like", "EmojiReact"] do
+ def handle_incoming(%{"type" => type} = data, _options)
+ when type in ["Like", "EmojiReact", "Announce"] do
with :ok <- ObjectValidator.fetch_actor_and_object(data),
{:ok, activity, _meta} <-
Pipeline.common_pipeline(data, local: false) do
@@ -673,22 +674,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def handle_incoming(
- %{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
- _options
- ) do
- with actor <- Containment.get_actor(data),
- {_, {:ok, %User{} = actor}} <- {:fetch_user, User.get_or_fetch_by_ap_id(actor)},
- {_, {:ok, object}} <- {:get_embedded, get_embedded_obj_helper(object_id, actor)},
- public <- Visibility.is_public?(data),
- {_, {:ok, activity, _object}} <-
- {:announce, ActivityPub.announce(actor, object, id, false, public)} do
- {:ok, activity}
- else
- e -> {:error, e}
- end
- end
-
- def handle_incoming(
%{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} =
data,
_options
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 447dbe4e6..dbb3d7ade 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -127,18 +127,19 @@ defmodule Pleroma.Web.CommonAPI do
end
def repeat(id, user, params \\ %{}) do
- with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id) do
- object = Object.normalize(activity)
- announce_activity = Utils.get_existing_announce(user.ap_id, object)
- public = public_announce?(object, params)
-
- if announce_activity do
- {:ok, announce_activity, object}
- else
- ActivityPub.announce(user, object, nil, true, public)
- end
+ with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
+ object = %Object{} <- Object.normalize(activity, false),
+ {_, nil} <- {:existing_announce, Utils.get_existing_announce(user.ap_id, object)},
+ public = public_announce?(object, params),
+ {:ok, announce, _} <- Builder.announce(user, object, public: public),
+ {:ok, activity, _} <- Pipeline.common_pipeline(announce, local: true) do
+ {:ok, activity}
else
- _ -> {:error, :not_found}
+ {:existing_announce, %Activity{} = announce} ->
+ {:ok, announce}
+
+ _ ->
+ {:error, :not_found}
end
end
diff --git a/test/fixtures/mastodon-note-object.json b/test/fixtures/mastodon-note-object.json
index 75bed9625..d28c7fbe9 100644
--- a/test/fixtures/mastodon-note-object.json
+++ b/test/fixtures/mastodon-note-object.json
@@ -1,9 +1,45 @@
-{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":"as:movedTo","Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji"}],"id":"http://mastodon.example.org/users/admin/statuses/99541947525187367","type":"Note","summary":null,"content":"\u003cp\u003eyeah.\u003c/p\u003e","inReplyTo":null,"published":"2018-02-17T17:46:20Z","url":"http://mastodon.example.org/@admin/99541947525187367","attributedTo":"http://mastodon.example.org/users/admin","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["http://mastodon.example.org/users/admin/followers"],"sensitive":false,"atomUri":"http://mastodon.example.org/users/admin/statuses/99541947525187367","inReplyToAtomUri":null,"conversation":"tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation","tag":[],
- "attachment": [
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
{
- "url": "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg",
- "type": "Document",
- "name": null,
- "mediaType": "image/jpeg"
+ "Emoji" : "toot:Emoji",
+ "Hashtag" : "as:Hashtag",
+ "atomUri" : "ostatus:atomUri",
+ "conversation" : "ostatus:conversation",
+ "inReplyToAtomUri" : "ostatus:inReplyToAtomUri",
+ "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers",
+ "movedTo" : "as:movedTo",
+ "ostatus" : "http://ostatus.org#",
+ "sensitive" : "as:sensitive",
+ "toot" : "http://joinmastodon.org/ns#"
}
- ]}
+ ],
+ "atomUri" : "http://mastodon.example.org/users/admin/statuses/99541947525187367",
+ "attachment" : [
+ {
+ "mediaType" : "image/jpeg",
+ "name" : null,
+ "type" : "Document",
+ "url" : "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg"
+ }
+ ],
+ "attributedTo" : "http://mastodon.example.org/users/admin",
+ "cc" : [
+ "http://mastodon.example.org/users/admin/followers"
+ ],
+ "content" : "<p>yeah.</p>",
+ "conversation" : "tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation",
+ "id" : "http://mastodon.example.org/users/admin/statuses/99541947525187367",
+ "inReplyTo" : null,
+ "inReplyToAtomUri" : null,
+ "published" : "2018-02-17T17:46:20Z",
+ "sensitive" : false,
+ "summary" : null,
+ "tag" : [],
+ "to" : [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type" : "Note",
+ "url" : "http://mastodon.example.org/@admin/99541947525187367"
+}
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index a46254a05..5dede3957 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -289,4 +289,29 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
end
end
+
+ describe "announce objects" do
+ setup do
+ poster = insert(:user)
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
+
+ {:ok, announce_data, _meta} = Builder.announce(user, post.object)
+ {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
+
+ %{announce: announce, user: user, poster: poster}
+ end
+
+ test "add the announce to the original object", %{announce: announce, user: user} do
+ {:ok, announce, _} = SideEffects.handle(announce)
+ object = Object.get_by_ap_id(announce.data["object"])
+ assert object.data["announcement_count"] == 1
+ assert user.ap_id in object.data["announcements"]
+ end
+
+ test "creates a notification", %{announce: announce, poster: poster} do
+ {:ok, announce, _} = SideEffects.handle(announce)
+ assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
+ end
+ end
end
diff --git a/test/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/web/activity_pub/transmogrifier/announce_handling_test.exs
index 8a4af6546..50bcb307f 100644
--- a/test/web/activity_pub/transmogrifier/announce_handling_test.exs
+++ b/test/web/activity_pub/transmogrifier/announce_handling_test.exs
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
import Pleroma.Factory
test "it works for incoming honk announces" do
- _user = insert(:user, ap_id: "https://honktest/u/test", local: false)
+ user = insert(:user, ap_id: "https://honktest/u/test", local: false)
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
@@ -28,6 +28,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
}
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce)
+
+ object = Object.get_by_ap_id(post.data["object"])
+
+ assert length(object.data["announcements"]) == 1
+ assert user.ap_id in object.data["announcements"]
end
test "it works for incoming announces with actor being inlined (kroeg)" do
@@ -48,8 +53,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
end
test "it works for incoming announces, fetching the announced object" do
- Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
- data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
+ data =
+ File.read!("test/fixtures/mastodon-announce.json")
+ |> Poison.decode!()
+ |> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367")
+
+ Tesla.Mock.mock(fn
+ %{method: :get} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")}
+ end)
_user = insert(:user, local: false, ap_id: data["actor"])
@@ -92,6 +104,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
end
+ # Ignore inlined activities for now
+ @tag skip: true
test "it works for incoming announces with an inlined activity" do
data =
File.read!("test/fixtures/mastodon-announce-private.json")
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 52e95397c..e68a6a7d2 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -416,7 +416,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
- {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
+ {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
+ assert Visibility.is_public?(announce_activity)
end
test "can't repeat a repeat" do
@@ -424,9 +425,9 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
- {:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user)
+ {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user)
- refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user))
+ refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user))
end
test "repeating a status privately" do
@@ -435,7 +436,7 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
- {:ok, %Activity{} = announce_activity, _} =
+ {:ok, %Activity{} = announce_activity} =
CommonAPI.repeat(activity.id, user, %{visibility: "private"})
assert Visibility.is_private?(announce_activity)
@@ -458,8 +459,8 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
- {:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user)
- {:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user)
+ {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user)
+ {:ok, ^announce} = CommonAPI.repeat(activity.id, user)
end
test "favoriting a status twice returns ok, but without the like activity" do