Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms
authorlain <lain@soykaf.club>
Mon, 25 May 2020 11:57:27 +0000 (13:57 +0200)
committerlain <lain@soykaf.club>
Mon, 25 May 2020 11:57:27 +0000 (13:57 +0200)
13 files changed:
1  2 
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/builder.ex
lib/pleroma/web/activity_pub/object_validator.ex
lib/pleroma/web/activity_pub/side_effects.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/common_api/common_api.ex
lib/pleroma/web/common_api/utils.ex
lib/pleroma/web/mastodon_api/views/instance_view.ex
lib/pleroma/web/router.ex
test/web/activity_pub/object_validator_test.exs
test/web/activity_pub/side_effects_test.exs
test/web/common_api/common_api_test.exs
test/web/mastodon_api/views/notification_view_test.exs

index 7f1e0171cfc828f1e6f15c8aff3a644cef853744,2599067a87089141db941ff3cdb94a94e117ece8..c01c5f78067dc57395e0ce90ce098d86e74c112d
@@@ -11,8 -11,7 +11,9 @@@ defmodule Pleroma.Web.ActivityPub.Objec
  
    alias Pleroma.Object
    alias Pleroma.User
+   alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
 +  alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
 +  alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
    alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
    alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
    alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
      end
    end
  
 +  def validate(%{"type" => "Create", "object" => object} = create_activity, meta) do
 +    with {:ok, object_data} <- cast_and_apply(object),
 +         meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
 +         {:ok, create_activity} <-
 +           create_activity
 +           |> CreateChatMessageValidator.cast_and_validate(meta)
 +           |> Ecto.Changeset.apply_action(:insert) do
 +      create_activity = stringify_keys(create_activity)
 +      {:ok, create_activity, meta}
 +    end
 +  end
 +
+   def validate(%{"type" => "Announce"} = object, meta) do
+     with {:ok, object} <-
+            object
+            |> AnnounceValidator.cast_and_validate()
+            |> Ecto.Changeset.apply_action(:insert) do
+       object = stringify_keys(object |> Map.from_struct())
+       {:ok, object, meta}
+     end
+   end
 +  def cast_and_apply(%{"type" => "ChatMessage"} = object) do
 +    ChatMessageValidator.cast_and_apply(object)
 +  end
 +
 +  def cast_and_apply(o), do: {:error, {:validator_not_set, o}}
 +
    def stringify_keys(%{__struct__: _} = object) do
      object
      |> Map.from_struct()
index 8e64b4615bde849670cebc041827bf9f27c82d49,7eae0c52ccf906cff1b00ab6b14a0255e52f3d9c..f0f0659c2cd6f989ef666d5f6aa611dbf08ff79a
@@@ -29,19 -27,21 +29,34 @@@ defmodule Pleroma.Web.ActivityPub.SideE
      {:ok, object, meta}
    end
  
 +  # Tasks this handles
 +  # - Actually create object
 +  # - Rollback if we couldn't create it
 +  # - Set up notifications
 +  def handle(%{data: %{"type" => "Create"}} = activity, meta) do
 +    with {:ok, _object, _meta} <- handle_object_creation(meta[:object_data], meta) do
 +      Notification.create_notifications(activity)
 +      {:ok, activity, meta}
 +    else
 +      e -> Repo.rollback(e)
 +    end
 +  end
 +
+   # Tasks this handles:
+   # - Add announce to object
+   # - Set up notification
+   # - Stream out the announce
+   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)
+     ActivityPub.stream_out(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
index afc63d6b7cd7c95ca06b5dbe8f7d3246e3cdfb90,d594c64f486e56542629a7d5424119632a0db920..a7f33c332d27c36bcb9f1ff914e9a1d34743c836
@@@ -662,17 -662,8 +662,18 @@@ defmodule Pleroma.Web.ActivityPub.Trans
      |> handle_incoming(options)
    end
  
-   def handle_incoming(%{"type" => type} = data, _options) when type in ["Like", "EmojiReact"] do
 +  def handle_incoming(
 +        %{"type" => "Create", "object" => %{"type" => "ChatMessage"}} = data,
 +        _options
 +      ) do
 +    with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
 +         {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
 +      {:ok, activity}
 +    end
 +  end
 +
+   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
Simple merge
Simple merge
index d63264de982ef70fe94cf5f34d11132ad3c7000e,a80104ea78cdd44f047781ad59ae4aef802da42e..fb4411c072b2faab99beb9052fb66e5820c1099a
@@@ -291,89 -290,60 +291,146 @@@ defmodule Pleroma.Web.ActivityPub.SideE
      end
    end
  
 +  describe "creation of ChatMessages" do
 +    test "notifies the recipient" do
 +      author = insert(:user, local: false)
 +      recipient = insert(:user, local: true)
 +
 +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
 +
 +      {:ok, create_activity_data, _meta} =
 +        Builder.create(author, chat_message_data["id"], [recipient.ap_id])
 +
 +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
 +
 +      {:ok, _create_activity, _meta} =
 +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
 +
 +      assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
 +    end
 +
 +    test "it creates a Chat for the local users and bumps the unread count, except for the author" do
 +      author = insert(:user, local: true)
 +      recipient = insert(:user, local: true)
 +
 +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
 +
 +      {:ok, create_activity_data, _meta} =
 +        Builder.create(author, chat_message_data["id"], [recipient.ap_id])
 +
 +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
 +
 +      {:ok, _create_activity, _meta} =
 +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
 +
 +      chat = Chat.get(author.id, recipient.ap_id)
 +      assert chat.unread == 0
 +
 +      chat = Chat.get(recipient.id, author.ap_id)
 +      assert chat.unread == 1
 +    end
 +
 +    test "it creates a Chat for the local users and bumps the unread count" do
 +      author = insert(:user, local: false)
 +      recipient = insert(:user, local: true)
 +
 +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
 +
 +      {:ok, create_activity_data, _meta} =
 +        Builder.create(author, chat_message_data["id"], [recipient.ap_id])
 +
 +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
 +
 +      {:ok, _create_activity, _meta} =
 +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
 +
 +      # An object is created
 +      assert Object.get_by_ap_id(chat_message_data["id"])
 +
 +      # The remote user won't get a chat
 +      chat = Chat.get(author.id, recipient.ap_id)
 +      refute chat
 +
 +      # The local user will get a chat
 +      chat = Chat.get(recipient.id, author.ap_id)
 +      assert chat
 +
 +      author = insert(:user, local: true)
 +      recipient = insert(:user, local: true)
 +
 +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
 +
 +      {:ok, create_activity_data, _meta} =
 +        Builder.create(author, chat_message_data["id"], [recipient.ap_id])
 +
 +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
 +
 +      {:ok, _create_activity, _meta} =
 +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
 +
 +      # Both users are local and get the chat
 +      chat = Chat.get(author.id, recipient.ap_id)
 +      assert chat
 +
 +      chat = Chat.get(recipient.id, author.ap_id)
 +      assert chat
 +    end
 +  end
++
+   describe "announce objects" do
+     setup do
+       poster = insert(:user)
+       user = insert(:user)
+       {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
+       {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
+       {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
+       {:ok, private_announce_data, _meta} =
+         Builder.announce(user, private_post.object, public: false)
+       {:ok, relay_announce_data, _meta} =
+         Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
+       {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
+       {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
+       {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
+       %{
+         announce: announce,
+         user: user,
+         poster: poster,
+         private_announce: private_announce,
+         relay_announce: relay_announce
+       }
+     end
+     test "adds 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 "does not add the announce to the original object if the actor is a service actor", %{
+       relay_announce: announce
+     } do
+       {:ok, announce, _} = SideEffects.handle(announce)
+       object = Object.get_by_ap_id(announce.data["object"])
+       assert object.data["announcement_count"] == nil
+     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
+     test "it streams out the announce", %{announce: announce} do
+       with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do
+         {:ok, announce, _} = SideEffects.handle(announce)
+         assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce))
+       end
+     end
+   end
  end