From 080e1aa70e4af4e9cdc0589f28648468bf116d6b Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 16:04:39 +0300 Subject: [PATCH 01/13] add option skip_thread_containment --- config/config.exs | 3 +- docs/config.md | 1 + lib/pleroma/user/info.ex | 5 +- lib/pleroma/web/activity_pub/activity_pub.ex | 7 +- lib/pleroma/web/streamer.ex | 25 +++++-- test/web/activity_pub/visibilty_test.exs | 43 +++++++++++ test/web/streamer_test.exs | 78 ++++++++++++++++++++ 7 files changed, 150 insertions(+), 12 deletions(-) diff --git a/config/config.exs b/config/config.exs index 68168b279..ada4fb48d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -237,7 +237,8 @@ max_report_comment_size: 1000, safe_dm_mentions: false, healthcheck: false, - remote_post_retention_days: 90 + remote_post_retention_days: 90, + skip_thread_containment: false config :pleroma, :app_account_creation, enabled: true, max_requests: 25, interval: 1800 diff --git a/docs/config.md b/docs/config.md index 67b062fe9..fbb9079e6 100644 --- a/docs/config.md +++ b/docs/config.md @@ -105,6 +105,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). (Default: `false`) * `healthcheck`: if set to true, system data will be shown on ``/api/pleroma/healthcheck``. * `remote_post_retention_days`: the default amount of days to retain remote posts when pruning the database +* `skip_thread_containment`: Skip filter out broken threads. the default is `false`. ## :app_account_creation REST API for creating an account settings diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index ef506c8da..d1fb4fe75 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -49,6 +49,8 @@ defmodule Pleroma.User.Info do default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} ) + field(:skip_thread_containment, :boolean, default: false) + # Found in the wild # ap_id -> Where is this used? # bio -> Where is this used? @@ -208,7 +210,8 @@ def profile_update(info, params) do :hide_followers, :hide_favorites, :background, - :show_role + :show_role, + :skip_thread_containment ]) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8add62406..f121ef01b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Conversation alias Pleroma.Notification alias Pleroma.Object @@ -73,7 +74,7 @@ defp check_actor_is_active(actor) do end defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do - limit = Pleroma.Config.get([:instance, :remote_limit]) + limit = Config.get([:instance, :remote_limit]) String.length(content) <= limit end @@ -399,8 +400,8 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru end def block(blocker, blocked, activity_id \\ nil, local \\ true) do - outgoing_blocks = Pleroma.Config.get([:activitypub, :outgoing_blocks]) - unfollow_blocked = Pleroma.Config.get([:activitypub, :unfollow_blocked]) + outgoing_blocks = Config.get([:activitypub, :outgoing_blocks]) + unfollow_blocked = Config.get([:activitypub, :unfollow_blocked]) if unfollow_blocked do follow_activity = fetch_latest_follow(blocker, blocked) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 133decfc4..a23f80f26 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.Streamer do use GenServer require Logger alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Object @@ -224,11 +225,10 @@ def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = ite mutes = user.info.mutes || [] reblog_mutes = user.info.muted_reblogs || [] - parent = Object.normalize(item) - - unless is_nil(parent) or item.actor in blocks or item.actor in mutes or - item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or - parent.data["actor"] in blocks or parent.data["actor"] in mutes do + with parent when not is_nil(parent) <- Object.normalize(item), + true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), + true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + true <- thread_containment(item, user) do send(socket.transport_pid, {:text, represent_update(item, user)}) end else @@ -264,8 +264,8 @@ def push_to_socket(topics, topic, item) do blocks = user.info.blocks || [] mutes = user.info.mutes || [] - unless item.actor in blocks or item.actor in mutes or - not ActivityPub.contain_activity(item, user) do + with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), + true <- thread_containment(item, user) do send(socket.transport_pid, {:text, represent_update(item, user)}) end else @@ -279,4 +279,15 @@ defp internal_topic(topic, socket) when topic in ~w[user direct] do end defp internal_topic(topic, _), do: topic + + @spec thread_containment(Activity.t(), User.t()) :: boolean() + defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + + defp thread_containment(activity, user) do + if Config.get([:instance, :skip_thread_containment]) do + true + else + ActivityPub.contain_activity(activity, user) + end + end end diff --git a/test/web/activity_pub/visibilty_test.exs b/test/web/activity_pub/visibilty_test.exs index 466d980dc..e24df3cab 100644 --- a/test/web/activity_pub/visibilty_test.exs +++ b/test/web/activity_pub/visibilty_test.exs @@ -1,6 +1,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do use Pleroma.DataCase + alias Pleroma.Activity alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.CommonAPI import Pleroma.Factory @@ -121,4 +122,46 @@ test "get_visibility", %{ test "get_visibility with directMessage flag" do assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct" end + + describe "entire_thread_visible_for_user?/2" do + test "returns false if not found activity", %{user: user} do + refute Visibility.entire_thread_visible_for_user?(%Activity{}, user) + end + + test "returns true if activity hasn't 'Create' type", %{user: user} do + activity = insert(:like_activity) + assert Visibility.entire_thread_visible_for_user?(activity, user) + end + + test "returns false when invalid recipients", %{user: user} do + author = insert(:user) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["test-user"]} + ) + ) + + refute Visibility.entire_thread_visible_for_user?(activity, user) + end + + test "returns true if user following to author" do + author = insert(:user) + user = insert(:user, following: [author.ap_id]) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => [user.ap_id]} + ) + ) + + assert Visibility.entire_thread_visible_for_user?(activity, user) + end + end end diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index bfe18cb7f..c18b9f9fe 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -11,6 +11,16 @@ defmodule Pleroma.Web.StreamerTest do alias Pleroma.Web.Streamer import Pleroma.Factory + setup do + skip_thread_containment = Pleroma.Config.get([:instance, :skip_thread_containment]) + + on_exit(fn -> + Pleroma.Config.put([:instance, :skip_thread_containment], skip_thread_containment) + end) + + :ok + end + test "it sends to public" do user = insert(:user) other_user = insert(:user) @@ -68,6 +78,74 @@ test "it sends to public" do Task.await(task) end + describe "thread_containment" do + test "it doesn't send to user if recipients invalid and thread containment is enabled" do + Pleroma.Config.put([:instance, :skip_thread_containment], false) + author = insert(:user) + user = insert(:user, following: [author.ap_id]) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["TEST-FFF"]} + ) + ) + + task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + topics = %{"public" => [fake_socket]} + Streamer.push_to_socket(topics, "public", activity) + + Task.await(task) + end + + test "it sends message if recipients invalid and thread containment is disabled" do + Pleroma.Config.put([:instance, :skip_thread_containment], true) + author = insert(:user) + user = insert(:user, following: [author.ap_id]) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["TEST-FFF"]} + ) + ) + + task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + topics = %{"public" => [fake_socket]} + Streamer.push_to_socket(topics, "public", activity) + + Task.await(task) + end + + test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do + Pleroma.Config.put([:instance, :skip_thread_containment], false) + author = insert(:user) + user = insert(:user, following: [author.ap_id], info: %{skip_thread_containment: true}) + + activity = + insert(:note_activity, + note: + insert(:note, + user: author, + data: %{"to" => ["TEST-FFF"]} + ) + ) + + task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) + fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} + topics = %{"public" => [fake_socket]} + Streamer.push_to_socket(topics, "public", activity) + + Task.await(task) + end + end + test "it doesn't send to blocked users" do user = insert(:user) blocked_user = insert(:user) From f13d6c7f78cfae4005b351248ce3e9069abf93e2 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 21:02:02 +0300 Subject: [PATCH 02/13] update api to set skip_thread_containment --- docs/api/differences_in_mastoapi_responses.md | 1 + .../mastodon_api/mastodon_api_controller.ex | 10 +++++++- .../web/mastodon_api/views/account_view.ex | 3 ++- .../web/twitter_api/twitter_api_controller.ex | 10 +++++++- .../web/twitter_api/views/user_view.ex | 3 ++- .../mastodon_api_controller_test.exs | 13 ++++++++++ .../twitter_api_controller_test.exs | 25 ++++++++++++++++++- 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 36b47608e..ed156836d 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -80,6 +80,7 @@ Additional parameters can be added to the JSON body/Form data: - `hide_favorites` - if true, user's favorites timeline will be hidden - `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API - `default_scope` - the scope returned under `privacy` key in Source subentity +- `skip_thread_containment` - if true, skip filtering out broken threads ## Authentication diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0d81fb840..52eed51c1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -117,7 +117,15 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do |> Enum.dedup() info_params = - [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role] + [ + :no_rich_text, + :locked, + :hide_followers, + :hide_follows, + :hide_favorites, + :show_role, + :skip_thread_containment + ] |> Enum.reduce(%{}, fn key, acc -> add_if_present(acc, params, to_string(key), key, fn value -> {:ok, ControllerHelper.truthy_param?(value)} diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b82d3319b..7b7e58eac 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -124,7 +124,8 @@ defp do_render("account.json", %{user: user} = opts) do hide_followers: user.info.hide_followers, hide_follows: user.info.hide_follows, hide_favorites: user.info.hide_favorites, - relationship: relationship + relationship: relationship, + skip_thread_containment: user.info.skip_thread_containment } } |> maybe_put_role(user, opts[:for]) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 1b6b33e69..6cf107d17 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -632,7 +632,15 @@ def raw_empty_array(conn, _params) do defp build_info_cng(user, params) do info_params = - ["no_rich_text", "locked", "hide_followers", "hide_follows", "hide_favorites", "show_role"] + [ + "no_rich_text", + "locked", + "hide_followers", + "hide_follows", + "hide_favorites", + "show_role", + "skip_thread_containment" + ] |> Enum.reduce(%{}, fn key, res -> if value = params[key] do Map.put(res, key, value == "true") diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index f0a4ddbd3..84875613a 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -118,7 +118,8 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do "pleroma" => %{ "confirmation_pending" => user_info.confirmation_pending, - "tags" => user.tags + "tags" => user.tags, + "skip_thread_containment" => user.info.skip_thread_containment } |> maybe_with_activation_status(user, for_user) } diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f5f87d8af..587df0481 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2378,6 +2378,19 @@ test "updates the user's hide_followers status", %{conn: conn} do assert user["pleroma"]["hide_followers"] == true end + test "updates the user's skip_thread_containment option", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{skip_thread_containment: "true"}) + |> json_response(200) + + assert response["pleroma"]["skip_thread_containment"] == true + assert refresh_record(user).info.skip_thread_containment + end + test "updates the user's hide_follows status", %{conn: conn} do user = insert(:user) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index bcd0f522d..8187ffd0e 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1495,7 +1495,7 @@ test "it sets and un-sets hide_follows", %{conn: conn} do "hide_follows" => "false" }) - user = Repo.get!(User, user.id) + user = refresh_record(user) assert user.info.hide_follows == false assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) end @@ -1548,6 +1548,29 @@ test "it sets and un-sets show_role", %{conn: conn} do assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) end + test "it sets and un-sets skip_thread_containment", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "true"}) + |> json_response(200) + + assert response["pleroma"]["skip_thread_containment"] == true + user = refresh_record(user) + assert user.info.skip_thread_containment + + response = + conn + |> assign(:user, user) + |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "false"}) + |> json_response(200) + + assert response["pleroma"]["skip_thread_containment"] == false + refute refresh_record(user).info.skip_thread_containment + end + test "it locks an account", %{conn: conn} do user = insert(:user) From 46c7e16512a4e51e2c062b9985bd04fb76487a28 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 21:05:45 +0300 Subject: [PATCH 03/13] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1fff876..419dcf3b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - OAuth: added job to clean expired access tokens - MRF: Support for rejecting reports from specific instances (`mrf_simple`) - MRF: Support for stripping avatars and banner images from specific instances (`mrf_simple`) +- Configuration: `skip_thread_containment` option ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer From 64ada7f960eb45d5e06d431c0c27be1014106ff9 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 3 Jun 2019 22:51:14 +0300 Subject: [PATCH 04/13] fix tests --- test/web/mastodon_api/account_view_test.exs | 9 ++++++--- test/web/twitter_api/views/user_view_test.exs | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index aaf2261bb..66ae8b4bb 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -67,7 +67,8 @@ test "Represent a user account" do hide_favorites: true, hide_followers: false, hide_follows: false, - relationship: %{} + relationship: %{}, + skip_thread_containment: false } } @@ -132,7 +133,8 @@ test "Represent a Service(bot) account" do hide_favorites: true, hide_followers: false, hide_follows: false, - relationship: %{} + relationship: %{}, + skip_thread_containment: false } } @@ -233,7 +235,8 @@ test "represent an embedded relationship" do domain_blocking: false, showing_reblogs: true, endorsed: false - } + }, + skip_thread_containment: false } } diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index 74526673c..9870c17c0 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -99,7 +99,8 @@ test "A user" do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" @@ -152,7 +153,8 @@ test "A user for a given other follower", %{user: user} do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" @@ -197,7 +199,8 @@ test "A user that follows you", %{user: user} do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" @@ -279,7 +282,8 @@ test "A blocked user for the blocker" do "fields" => [], "pleroma" => %{ "confirmation_pending" => false, - "tags" => [] + "tags" => [], + "skip_thread_containment" => false }, "rights" => %{"admin" => false, "delete_others_notice" => false}, "role" => "member" From 96121315f3e9aebc57d36a669fc4003905cd0ba6 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 4 Jun 2019 12:41:24 +0300 Subject: [PATCH 05/13] fix merge --- docs/api/differences_in_mastoapi_responses.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 88a43de38..623d4fbf5 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -90,7 +90,6 @@ Pleroma has mechanism that allows frontends to save blobs of json for each user The parameter should have a form of `{frontend_name: {...}}`, with `frontend_name` identifying your type of client, e.g. `pleroma_fe`. It will overwrite everything under this property, but will not overwrite other frontend's settings. This information is returned in the `verify_credentials` endpoint. ->>>>>>> develop ## Authentication From 29b022bb597f36621ef3f5056c5ca2b7f0c8edbe Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 4 Jun 2019 12:42:10 +0300 Subject: [PATCH 06/13] Restrict `get_existing_votes` to only get Create activities --- lib/pleroma/web/activity_pub/utils.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index b8159e9e5..faae7e747 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -794,6 +794,7 @@ def get_existing_votes(actor, %{data: %{"id" => id}}) do query = from( [activity, object: object] in Activity.with_preloaded_object(Activity), + where: fragment("(?)->>'type' = 'Create'", activity.data), where: fragment("(?)->>'actor' = ?", activity.data, ^actor), where: fragment( From e74581a5c4c3aca68a304efb683dffed80d1337f Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 4 Jun 2019 12:01:21 +0200 Subject: [PATCH 07/13] Emoji: Don't die when files are present in the emoji folder. --- lib/pleroma/emoji.ex | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 7d12eff7f..de7fcc1ce 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -97,10 +97,22 @@ defp load do # There was some other error Logger.error("Could not access the custom emoji directory #{emoji_dir_path}: #{e}") - {:ok, packs} -> + {:ok, results} -> + grouped = Enum.group_by(results, &File.dir?/1) + packs = grouped[true] || [] + files = grouped[false] || [] + # Print the packs we've found Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}") + if not Enum.empty?(files) do + Logger.warn( + "Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{ + Enum.join(files, ", ") + }" + ) + end + emojis = Enum.flat_map( packs, From 17383861edf6c9d7308101182607e7ff9202af73 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 4 Jun 2019 13:38:24 +0300 Subject: [PATCH 08/13] Fix CommonAPI.vote returning tuples inside of the activity array instead of just activities --- lib/pleroma/web/common_api/common_api.ex | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 5212d5ce5..ad3c03c55 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -132,13 +132,16 @@ def vote(user, object, choices) do Enum.map(choices, fn index -> answer_data = make_answer_data(user, object, Enum.at(options, index)["name"]) - ActivityPub.create(%{ - to: answer_data["to"], - actor: user, - context: object.data["context"], - object: answer_data, - additional: %{"cc" => answer_data["cc"]} - }) + {:ok, activity} = + ActivityPub.create(%{ + to: answer_data["to"], + actor: user, + context: object.data["context"], + object: answer_data, + additional: %{"cc" => answer_data["cc"]} + }) + + activity end) object = Object.get_cached_by_ap_id(object.data["id"]) From bbff7554de7f8c3965387fb3509728c1f2c2d04b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 4 Jun 2019 13:47:53 +0300 Subject: [PATCH 09/13] Add tests for get_existing_votes --- test/web/activity_pub/utils_test.exs | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index c57fae437..de741c64b 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -1,6 +1,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils @@ -204,4 +205,46 @@ test "make_json_ld_header/0" do ] } end + + describe "get_existing_votes" do + test "fetches existing votes" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "How do I pronounce LaTeX?", + "poll" => %{ + "options" => ["laytekh", "lahtekh", "latex"], + "expires_in" => 20, + "multiple" => true + } + }) + + object = Object.normalize(activity) + {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1]) + assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes) + end + + test "fetches only Create activities" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "Are we living in a society?", + "poll" => %{ + "options" => ["yes", "no"], + "expires_in" => 20 + } + }) + + object = Object.normalize(activity) + {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0]) + vote_object = Object.normalize(vote) + {:ok, _activity, _object} = ActivityPub.like(user, vote_object) + [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object) + assert fetched_vote.id == vote.id + end + end end From a3a7178b604d8bc589a8e3ac06abac094cce5e17 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 4 Jun 2019 13:58:36 +0200 Subject: [PATCH 10/13] Participations: Filter out participations without activities. --- lib/pleroma/conversation/participation.ex | 1 + test/conversation/participation_test.exs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 2a11f9069..2c13c4b40 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -79,5 +79,6 @@ def for_user_with_last_activity_id(user, params \\ %{}) do | last_activity_id: activity_id } end) + |> Enum.filter(& &1.last_activity_id) end end diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 568953b07..0e60bfca5 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -86,4 +86,17 @@ test "gets all the participations for a user, ordered by updated at descending" assert participation_one.last_activity_id == activity_three.id end + + test "Doesn't die when the conversation gets empty" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + [participation] = Participation.for_user_with_last_activity_id(user) + + assert participation.last_activity_id == activity.id + + {:ok, _} = CommonAPI.delete(activity.id, user) + + [] = Participation.for_user_with_last_activity_id(user) + end end From 0acfcf6c522a82ca416b6664d588d3daa32a6fba Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 4 Jun 2019 15:04:36 +0300 Subject: [PATCH 11/13] update ActivityPub#fetch_activities_query --- lib/pleroma/web/activity_pub/activity_pub.ex | 32 +++++++++----------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8c4d0c15d..eefed5832 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -558,14 +558,11 @@ defp restrict_visibility(query, %{visibility: visibility}) defp restrict_visibility(query, %{visibility: visibility}) when visibility in @valid_visibilities do - query = - from( - a in query, - where: - fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) - ) - - query + from( + a in query, + where: + fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) + ) end defp restrict_visibility(_query, %{visibility: visibility}) @@ -575,17 +572,17 @@ defp restrict_visibility(_query, %{visibility: visibility}) defp restrict_visibility(query, _visibility), do: query - defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do - query = - from( - a in query, - where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) - ) + defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), + do: query - query + defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}, _) do + from( + a in query, + where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) + ) end - defp restrict_thread_visibility(query, _), do: query + defp restrict_thread_visibility(query, _, _), do: query def fetch_user_activities(user, reading_user, params \\ %{}) do params = @@ -863,6 +860,7 @@ defp maybe_order(query, _), do: query def fetch_activities_query(recipients, opts \\ %{}) do base_query = from(activity in Activity) + config = Enum.into(Config.get([:instance]), %{}) base_query |> maybe_preload_objects(opts) @@ -883,7 +881,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_muted(opts) |> restrict_media(opts) |> restrict_visibility(opts) - |> restrict_thread_visibility(opts) + |> restrict_thread_visibility(opts, config) |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) From 1e7bb69a957c279eb75ed72cca779caa9d8f25ce Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 4 Jun 2019 15:20:24 +0300 Subject: [PATCH 12/13] update ActivityPub#fetch_activities_query --- lib/pleroma/web/activity_pub/activity_pub.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index eefed5832..c0e3d1478 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -575,6 +575,13 @@ defp restrict_visibility(query, _visibility), do: query defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), do: query + defp restrict_thread_visibility( + query, + %{"user" => %User{info: %{skip_thread_containment: true}}}, + _ + ), + do: query + defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}, _) do from( a in query, @@ -860,7 +867,10 @@ defp maybe_order(query, _), do: query def fetch_activities_query(recipients, opts \\ %{}) do base_query = from(activity in Activity) - config = Enum.into(Config.get([:instance]), %{}) + + config = %{ + skip_thread_containment: Config.get([:instance, :skip_thread_containment]) + } base_query |> maybe_preload_objects(opts) From b5e3b1e58ad9f4d8237821572e4d149eea881ff2 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 4 Jun 2019 16:44:56 +0200 Subject: [PATCH 13/13] Mix: Swallow git error messages during version number handling. Otherwise sometimes a 'fatal' message will be printed, confusing users. --- mix.exs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index df1a7ced4..9447a2e4f 100644 --- a/mix.exs +++ b/mix.exs @@ -157,7 +157,8 @@ defp aliases do # * the mix environment if different than prod defp version(version) do {git_tag, git_pre_release} = - with {tag, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=0"]), + with {tag, 0} <- + System.cmd("git", ["describe", "--tags", "--abbrev=0"], stderr_to_stdout: true), tag = String.trim(tag), {describe, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=8"]), describe = String.trim(describe),