Contain search for unauthenticated users
authorEgor Kislitsyn <egor@kislitsyn.com>
Fri, 31 May 2019 09:22:13 +0000 (16:22 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Wed, 5 Jun 2019 09:37:43 +0000 (16:37 +0700)
lib/pleroma/activity.ex
lib/pleroma/activity/search.ex [new file with mode: 0644]
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
test/activity_test.exs

index 99589590c1b3bddba86134e849d3935adf26145a..6db41fe6e36e9882f91649a98dff3a50e8440dbf 100644 (file)
@@ -343,4 +343,6 @@ defmodule Pleroma.Activity do
         )
     )
   end
+
+  defdelegate search(user, query), to: Pleroma.Activity.Search
 end
diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex
new file mode 100644 (file)
index 0000000..f2fdfff
--- /dev/null
@@ -0,0 +1,75 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Activity.Search do
+  alias Pleroma.Activity
+  alias Pleroma.Object.Fetcher
+  alias Pleroma.Repo
+  alias Pleroma.User
+  alias Pleroma.Web.ActivityPub.Visibility
+
+  import Ecto.Query
+
+  def search(user, search_query) do
+    index_type = if Pleroma.Config.get([:database, :rum_enabled]), do: :rum, else: :gin
+
+    Activity
+    |> Activity.with_preloaded_object()
+    |> Activity.restrict_deactivated_users()
+    |> restrict_public()
+    |> query_with(index_type, search_query)
+    |> maybe_restrict_local(user)
+    |> Repo.all()
+    |> maybe_fetch(user, search_query)
+  end
+
+  defp restrict_public(q) do
+    from([a, o] in q,
+      where: fragment("?->>'type' = 'Create'", a.data),
+      where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
+      limit: 40
+    )
+  end
+
+  defp query_with(q, :gin, search_query) do
+    from([a, o] in q,
+      where:
+        fragment(
+          "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
+          o.data,
+          ^search_query
+        ),
+      order_by: [desc: :id]
+    )
+  end
+
+  defp query_with(q, :rum, search_query) do
+    from([a, o] in q,
+      where:
+        fragment(
+          "? @@ plainto_tsquery('english', ?)",
+          o.fts_content,
+          ^search_query
+        ),
+      order_by: [fragment("? <=> now()::date", o.inserted_at)]
+    )
+  end
+
+  # users can search everything
+  defp maybe_restrict_local(q, %User{}), do: q
+
+  # unauthenticated users can only search local activities
+  defp maybe_restrict_local(q, _), do: where(q, local: true)
+
+  defp maybe_fetch(activities, user, search_query) do
+    with true <- Regex.match?(~r/https?:/, search_query),
+         {:ok, object} <- Fetcher.fetch_object_from_id(search_query),
+         %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
+         true <- Visibility.visible_for_user?(activity, user) do
+      activities ++ [activity]
+    else
+      _ -> activities
+    end
+  end
+end
index d825555c6823b94c796ec9346877ac9a31ec4808..92cd77f62f8201f4de7d2fa71a9d6a6fd900afd4 100644 (file)
@@ -14,7 +14,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   alias Pleroma.HTTP
   alias Pleroma.Notification
   alias Pleroma.Object
-  alias Pleroma.Object.Fetcher
   alias Pleroma.Pagination
   alias Pleroma.Repo
   alias Pleroma.ScheduledActivity
@@ -1125,64 +1124,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  def status_search_query_with_gin(q, query) do
-    from([a, o] in q,
-      where:
-        fragment(
-          "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
-          o.data,
-          ^query
-        ),
-      order_by: [desc: :id]
-    )
-  end
-
-  def status_search_query_with_rum(q, query) do
-    from([a, o] in q,
-      where:
-        fragment(
-          "? @@ plainto_tsquery('english', ?)",
-          o.fts_content,
-          ^query
-        ),
-      order_by: [fragment("? <=> now()::date", o.inserted_at)]
-    )
-  end
-
-  def status_search(user, query) do
-    fetched =
-      if Regex.match?(~r/https?:/, query) do
-        with {:ok, object} <- Fetcher.fetch_object_from_id(query),
-             %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
-             true <- Visibility.visible_for_user?(activity, user) do
-          [activity]
-        else
-          _e -> []
-        end
-      end || []
-
-    q =
-      from([a, o] in Activity.with_preloaded_object(Activity),
-        where: fragment("?->>'type' = 'Create'", a.data),
-        where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
-        limit: 40
-      )
-
-    q =
-      if Pleroma.Config.get([:database, :rum_enabled]) do
-        status_search_query_with_rum(q, query)
-      else
-        status_search_query_with_gin(q, query)
-      end
-
-    Repo.all(q) ++ fetched
-  end
-
   def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
     accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
-
-    statuses = status_search(user, query)
-
+    statuses = Activity.search(user, query)
     tags_path = Web.base_url() <> "/tag/"
 
     tags =
@@ -1205,8 +1149,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 
   def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
     accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
-
-    statuses = status_search(user, query)
+    statuses = Activity.search(user, query)
 
     tags =
       query
index 15c95502ab4af78beae377dac861439a57977e0d..5260ebb9e1f4245cc9f23d2619cf78839972250a 100644 (file)
@@ -99,4 +99,42 @@ defmodule Pleroma.ActivityTest do
       assert Activity.get_bookmark(queried_activity, user) == bookmark
     end
   end
+
+  describe "search" do
+    setup do
+      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+      user = insert(:user)
+
+      params = %{
+        "@context" => "https://www.w3.org/ns/activitystreams",
+        "actor" => "http://mastodon.example.org/users/admin",
+        "type" => "Create",
+        "id" => "http://mastodon.example.org/users/admin/activities/1",
+        "object" => %{
+          "type" => "Note",
+          "content" => "find me!",
+          "id" => "http://mastodon.example.org/users/admin/objects/1",
+          "attributedTo" => "http://mastodon.example.org/users/admin"
+        },
+        "to" => ["https://www.w3.org/ns/activitystreams#Public"]
+      }
+
+      {:ok, local_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "find me!"})
+      {:ok, remote_activity} = Pleroma.Web.Federator.incoming_ap_doc(params)
+      %{local_activity: local_activity, remote_activity: remote_activity, user: user}
+    end
+
+    test "find local and remote statuses for authenticated users", %{
+      local_activity: local_activity,
+      remote_activity: remote_activity,
+      user: user
+    } do
+      assert [^remote_activity, ^local_activity] = Activity.search(user, "find me")
+    end
+
+    test "find only local statuses for unauthenticated users", %{local_activity: local_activity} do
+      assert [^local_activity] = Activity.search(nil, "find me")
+    end
+  end
 end