Merge branch 'features/column_media_streaming' into 'develop'
authorlambda <pleromagit@rogerbraun.net>
Tue, 19 Jun 2018 09:50:05 +0000 (09:50 +0000)
committerlambda <pleromagit@rogerbraun.net>
Tue, 19 Jun 2018 09:50:05 +0000 (09:50 +0000)
Add streaming to media tabs of federated and local TLs

See merge request pleroma/pleroma!225

lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
priv/repo/migrations/20180617221540_create_activities_in_reply_to_index.exs [new file with mode: 0644]
test/fixtures/mastodon-post-activity-contentmap.json [new file with mode: 0644]
test/user_test.exs
test/web/activity_pub/transmogrifier_test.exs
test/web/mastodon_api/account_view_test.exs

index b27397e13956fc5ae16e638ff3e2ef69c1e21d2b..aba8742a09be5dfd4c639324a7e859f3a72ce1c8 100644 (file)
@@ -505,15 +505,33 @@ defmodule Pleroma.User do
     Repo.all(q)
   end
 
-  def block(user, %{ap_id: ap_id}) do
-    blocks = user.info["blocks"] || []
+  def block(blocker, %User{ap_id: ap_id} = blocked) do
+    # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
+    blocker =
+      if following?(blocker, blocked) do
+        {:ok, blocker, _} = unfollow(blocker, blocked)
+        blocker
+      else
+        blocker
+      end
+
+    if following?(blocked, blocker) do
+      unfollow(blocked, blocker)
+    end
+
+    blocks = blocker.info["blocks"] || []
     new_blocks = Enum.uniq([ap_id | blocks])
-    new_info = Map.put(user.info, "blocks", new_blocks)
+    new_info = Map.put(blocker.info, "blocks", new_blocks)
 
-    cs = User.info_changeset(user, %{info: new_info})
+    cs = User.info_changeset(blocker, %{info: new_info})
     update_and_set_cache(cs)
   end
 
+  # helper to handle the block given only an actor's AP id
+  def block(blocker, %{ap_id: ap_id}) do
+    block(blocker, User.get_by_ap_id(ap_id))
+  end
+
   def unblock(user, %{ap_id: ap_id}) do
     blocks = user.info["blocks"] || []
     new_blocks = List.delete(blocks, ap_id)
index 554202f6bd6b79db6179539134ae8328bcc08e71..dfcc5b9eda804ceb5e322a967de960758aa4e37d 100644 (file)
@@ -438,6 +438,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   defp restrict_media(query, _), do: query
 
+  defp restrict_replies(query, %{"exclude_replies" => val}) when val == "true" or val == "1" do
+    from(
+      activity in query,
+      where: fragment("?->'object'->>'inReplyTo' is null", activity.data)
+    )
+  end
+
+  defp restrict_replies(query, _), do: query
+
   # Only search through last 100_000 activities by default
   defp restrict_recent(query, %{"whole_db" => true}), do: query
 
@@ -495,6 +504,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> restrict_blocked(opts)
     |> restrict_media(opts)
     |> restrict_visibility(opts)
+    |> restrict_replies(opts)
   end
 
   def fetch_activities(recipients, opts \\ %{}) do
index 300e0fcdd350ecbec0a2b8b64a6b148258d7cdb2..30cd70fb656096df97ee86fe285d8fbe3a174dc3 100644 (file)
@@ -24,6 +24,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     |> fix_in_reply_to
     |> fix_emoji
     |> fix_tag
+    |> fix_content_map
   end
 
   def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
@@ -107,6 +108,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     |> Map.put("tag", combined)
   end
 
+  # content map usually only has one language so this will do for now.
+  def fix_content_map(%{"contentMap" => content_map} = object) do
+    content_groups = Map.to_list(content_map)
+    {_, content} = Enum.at(content_groups, 0)
+
+    object
+    |> Map.put("content", content)
+  end
+
+  def fix_content_map(object), do: object
+
   # TODO: validate those with a Ecto scheme
   # - tags
   # - emoji
diff --git a/priv/repo/migrations/20180617221540_create_activities_in_reply_to_index.exs b/priv/repo/migrations/20180617221540_create_activities_in_reply_to_index.exs
new file mode 100644 (file)
index 0000000..1fee6fd
--- /dev/null
@@ -0,0 +1,8 @@
+defmodule Pleroma.Repo.Migrations.CreateActivitiesInReplyToIndex do
+  use Ecto.Migration
+  @disable_ddl_transaction true
+
+  def change do
+    create index(:activities, ["(data->'object'->>'inReplyTo')"], concurrently: true, name: :activities_in_reply_to)
+  end
+end
diff --git a/test/fixtures/mastodon-post-activity-contentmap.json b/test/fixtures/mastodon-post-activity-contentmap.json
new file mode 100644 (file)
index 0000000..2e94380
--- /dev/null
@@ -0,0 +1,67 @@
+{
+    "@context": [
+        "https://www.w3.org/ns/activitystreams",
+        "https://w3id.org/security/v1",
+        {
+            "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#"
+        }
+    ],
+    "actor": "http://mastodon.example.org/users/admin",
+    "cc": [
+        "http://mastodon.example.org/users/admin/followers",
+        "http://localtesting.pleroma.lol/users/lain"
+    ],
+    "id": "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity",
+    "nickname": "lain",
+    "object": {
+        "atomUri": "http://mastodon.example.org/users/admin/statuses/99512778738411822",
+        "attachment": [],
+        "attributedTo": "http://mastodon.example.org/users/admin",
+        "cc": [
+            "http://mastodon.example.org/users/admin/followers",
+            "http://localtesting.pleroma.lol/users/lain"
+        ],
+        "contentMap": {
+            "en": "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
+        },
+        "conversation": "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation",
+        "id": "http://mastodon.example.org/users/admin/statuses/99512778738411822",
+        "inReplyTo": null,
+        "inReplyToAtomUri": null,
+        "published": "2018-02-12T14:08:20Z",
+        "sensitive": true,
+        "summary": "cw",
+        "tag": [
+            {
+                "href": "http://localtesting.pleroma.lol/users/lain",
+                "name": "@lain@localtesting.pleroma.lol",
+                "type": "Mention"
+            }
+        ],
+        "to": [
+            "https://www.w3.org/ns/activitystreams#Public"
+        ],
+        "type": "Note",
+        "url": "http://mastodon.example.org/@admin/99512778738411822"
+    },
+    "published": "2018-02-12T14:08:20Z",
+    "signature": {
+        "created": "2018-02-12T14:08:20Z",
+        "creator": "http://mastodon.example.org/users/admin#main-key",
+        "signatureValue": "rnNfcopkc6+Ju73P806popcfwrK9wGYHaJVG1/ZvrlEbWVDzaHjkXqj9Q3/xju5l8CSn9tvSgCCtPFqZsFQwn/pFIFUcw7ZWB2xi4bDm3NZ3S4XQ8JRaaX7og5hFxAhWkGhJhAkfxVnOg2hG+w2d/7d7vRVSC1vo5ip4erUaA/PkWusZvPIpxnRWoXaxJsFmVx0gJgjpJkYDyjaXUlp+jmaoseeZ4EPQUWqHLKJ59PRG0mg8j2xAjYH9nQaN14qMRmTGPxY8gfv/CUFcatA+8VJU9KEsJkDAwLVvglydNTLGrxpAJU78a2eaht0foV43XUIZGe3DKiJPgE+UOKGCJw==",
+        "type": "RsaSignature2017"
+    },
+    "to": [
+        "https://www.w3.org/ns/activitystreams#Public"
+    ],
+    "type": "Create"
+}
index 200352981cf12f98b91271fbcad45a9135c6b742..352a1668771a80e0831b525397802c5166482fd3 100644 (file)
@@ -359,6 +359,61 @@ defmodule Pleroma.UserTest do
 
       refute User.blocks?(user, blocked_user)
     end
+
+    test "blocks tear down cyclical follow relationships" do
+      blocker = insert(:user)
+      blocked = insert(:user)
+
+      {:ok, blocker} = User.follow(blocker, blocked)
+      {:ok, blocked} = User.follow(blocked, blocker)
+
+      assert User.following?(blocker, blocked)
+      assert User.following?(blocked, blocker)
+
+      {:ok, blocker} = User.block(blocker, blocked)
+      blocked = Repo.get(User, blocked.id)
+
+      assert User.blocks?(blocker, blocked)
+
+      refute User.following?(blocker, blocked)
+      refute User.following?(blocked, blocker)
+    end
+
+    test "blocks tear down blocker->blocked follow relationships" do
+      blocker = insert(:user)
+      blocked = insert(:user)
+
+      {:ok, blocker} = User.follow(blocker, blocked)
+
+      assert User.following?(blocker, blocked)
+      refute User.following?(blocked, blocker)
+
+      {:ok, blocker} = User.block(blocker, blocked)
+      blocked = Repo.get(User, blocked.id)
+
+      assert User.blocks?(blocker, blocked)
+
+      refute User.following?(blocker, blocked)
+      refute User.following?(blocked, blocker)
+    end
+
+    test "blocks tear down blocked->blocker follow relationships" do
+      blocker = insert(:user)
+      blocked = insert(:user)
+
+      {:ok, blocked} = User.follow(blocked, blocker)
+
+      refute User.following?(blocker, blocked)
+      assert User.following?(blocked, blocker)
+
+      {:ok, blocker} = User.block(blocker, blocked)
+      blocked = Repo.get(User, blocked.id)
+
+      assert User.blocks?(blocker, blocked)
+
+      refute User.following?(blocker, blocked)
+      refute User.following?(blocked, blocker)
+    end
   end
 
   describe "domain blocking" do
index 7e771b9f8f5232c7df84abb7f68df6fcaba94d35..838ae169dc1f2ff26ac2195a8c4baaa77999fa51 100644 (file)
@@ -102,6 +102,16 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert Enum.at(data["object"]["tag"], 2) == "moo"
     end
 
+    test "it works for incoming notices with contentMap" do
+      data =
+        File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+      assert data["object"]["content"] ==
+               "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
+    end
+
     test "it works for incoming follow requests" do
       user = insert(:user)
 
@@ -382,6 +392,37 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert User.blocks?(blocker, user)
     end
 
+    test "incoming blocks successfully tear down any follow relationship" do
+      blocker = insert(:user)
+      blocked = insert(:user)
+
+      data =
+        File.read!("test/fixtures/mastodon-block-activity.json")
+        |> Poison.decode!()
+        |> Map.put("object", blocked.ap_id)
+        |> Map.put("actor", blocker.ap_id)
+
+      {:ok, blocker} = User.follow(blocker, blocked)
+      {:ok, blocked} = User.follow(blocked, blocker)
+
+      assert User.following?(blocker, blocked)
+      assert User.following?(blocked, blocker)
+
+      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+      assert data["type"] == "Block"
+      assert data["object"] == blocked.ap_id
+      assert data["actor"] == blocker.ap_id
+
+      blocker = User.get_by_ap_id(data["actor"])
+      blocked = User.get_by_ap_id(data["object"])
+
+      assert User.blocks?(blocker, blocked)
+
+      refute User.following?(blocker, blocked)
+      refute User.following?(blocked, blocker)
+    end
+
     test "it works for incoming unblocks with an existing block" do
       user = insert(:user)
 
index 597690bf74913d0f04e811595df3be8c7a7a7ce8..f7b8d74387c2a1aa108b68c2cc68a9dd521f96f7 100644 (file)
@@ -60,7 +60,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
 
     expected = %{
       id: to_string(other_user.id),
-      following: true,
+      following: false,
       followed_by: false,
       blocking: true,
       muting: false,