[#3213] Reinstated DISTINCT clause for hashtag "any" filtering with 2+ terms. Added...
authorIvan Tashkinov <ivantashkinov@gmail.com>
Thu, 28 Jan 2021 21:17:33 +0000 (00:17 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Thu, 28 Jan 2021 21:17:33 +0000 (00:17 +0300)
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
test/pleroma/web/activity_pub/activity_pub_test.exs

index be81e0833d44745c8d2352a5dec8f665c82e3db4..0a21ac2f2e623fc21875b58500bb40dad0eb7e3c 100644 (file)
@@ -846,11 +846,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   defp restrict_hashtag_any(query, %{tag: tags}) when is_list(tags) do
-    from(
-      [_activity, object] in query,
-      join: hashtag in assoc(object, :hashtags),
-      where: hashtag.name in ^tags
-    )
+    query =
+      from(
+        [_activity, object] in query,
+        join: hashtag in assoc(object, :hashtags),
+        where: hashtag.name in ^tags
+      )
+
+    if length(tags) > 1 do
+      distinct(query, [activity], true)
+    else
+      query
+    end
   end
 
   defp restrict_hashtag_any(query, %{tag: tag}) when is_binary(tag) do
index 08e6f23b98cf8eb8fa8a261c030795359e37a7da..1fb954a9b1007f695eb13ee5116171fc26db5252 100644 (file)
@@ -134,9 +134,9 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
     tags =
       [params[:tag], params[:any]]
       |> List.flatten()
-      |> Enum.uniq()
       |> Enum.reject(&is_nil/1)
       |> Enum.map(&String.downcase/1)
+      |> Enum.uniq()
 
     tag_all =
       params
index 1fcaf74d3037a8a4b31c69f95c7c2486bc7b2f38..0b18269cddae15c7b7dc18917f8a624d655d0e4a 100644 (file)
@@ -217,6 +217,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"})
     {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"})
 
+    {:ok, status_four} = CommonAPI.post(user, %{status: ". #any1 #any2"})
+    {:ok, status_five} = CommonAPI.post(user, %{status: ". #any2 #any1"})
+
     for hashtag_timeline_strategy <- [true, :prefer_aggregation, false] do
       clear_config([:instance, :improved_hashtag_timeline], hashtag_timeline_strategy)
 
@@ -238,8 +241,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
           tag_all: ["test", "reject"]
         })
 
-      [fetch_one, fetch_two, fetch_three, fetch_four] =
-        Enum.map([fetch_one, fetch_two, fetch_three, fetch_four], fn statuses ->
+      # This test would fail if JOIN with 2+ terms in "any" clause is done without DISTINCT.
+      # The :limit is important (w/o DISTINCT 2 records are deduped by Ecto to 1 b/c of preload).
+      fetch_five =
+        ActivityPub.fetch_activities([], %{
+          type: "Create",
+          tag: ["any1", "any2"],
+          limit: 2
+        })
+
+      [fetch_one, fetch_two, fetch_three, fetch_four, fetch_five] =
+        Enum.map([fetch_one, fetch_two, fetch_three, fetch_four, fetch_five], fn statuses ->
           Enum.map(statuses, fn s -> Repo.preload(s, object: :hashtags) end)
         end)
 
@@ -247,6 +259,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert fetch_two == [status_one, status_two, status_three]
       assert fetch_three == [status_one, status_two]
       assert fetch_four == [status_three]
+      assert fetch_five == [status_four, status_five]
     end
   end