From ea932d1e20e544dbec47bda2dfef45d6a8eace2e Mon Sep 17 00:00:00 2001 From: itepechi <72330683+itepechi@users.noreply.github.com> Date: Sat, 16 Sep 2023 07:08:07 +0900 Subject: [PATCH] Implement media-only support for status search w/ some refactors and updates --- lib/pleroma/search/database_search.ex | 10 ++++++++++ lib/pleroma/search/elasticsearch.ex | 6 +++++- lib/pleroma/search/elasticsearch/store.ex | 4 ++-- lib/pleroma/search/meilisearch.ex | 3 ++- .../api_spec/operations/search_operation.ex | 2 +- .../controllers/search_controller.ex | 18 +++++++++++++++++- 6 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/search/database_search.ex b/lib/pleroma/search/database_search.ex index d92a37906..6298b301a 100644 --- a/lib/pleroma/search/database_search.ex +++ b/lib/pleroma/search/database_search.ex @@ -26,6 +26,7 @@ defmodule Pleroma.Search.DatabaseSearch do limit = Enum.min([Keyword.get(options, :limit), 40]) offset = Keyword.get(options, :offset, 0) author = Keyword.get(options, :author) + only_media = Keyword.get(options, :only_media, false) search_function = if :persistent_term.get({Pleroma.Repo, :postgres_version}) >= 11 do @@ -43,6 +44,7 @@ defmodule Pleroma.Search.DatabaseSearch do |> maybe_restrict_local(user) |> maybe_restrict_author(author) |> maybe_restrict_blocked(user) + |> maybe_only_media(only_media) |> Pagination.fetch_paginated( %{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum}, :offset @@ -173,4 +175,12 @@ defmodule Pleroma.Search.DatabaseSearch do _ -> activities end end + + def maybe_only_media(q, true) do + from([a, o] in q, + where: fragment("not (?)->'attachment' = (?)", o.data, ^[]) + ) + end + + def maybe_only_media(q, _), do: q end diff --git a/lib/pleroma/search/elasticsearch.ex b/lib/pleroma/search/elasticsearch.ex index 20e03e1f0..c2b12b856 100644 --- a/lib/pleroma/search/elasticsearch.ex +++ b/lib/pleroma/search/elasticsearch.ex @@ -43,6 +43,7 @@ defmodule Pleroma.Search.Elasticsearch do def search(user, query, options) do limit = Enum.min([Keyword.get(options, :limit), 40]) offset = Keyword.get(options, :offset, 0) + only_media = Keyword.get(options, :only_media, false) parsed_query = query @@ -62,7 +63,10 @@ defmodule Pleroma.Search.Elasticsearch do |> Pleroma.Search.Elasticsearch.Store.search(q) |> Enum.filter(fn x -> x.data["type"] == "Create" && x.object.data["type"] == "Note" && - Visibility.visible_for_user?(x, user) + Visibility.visible_for_user?(x, user) && + # i'm not going to implement this very seriously because the support for + # elasticsearch is already kinda broken + if only_media, do: length(x.object.data["attachment"]) > 0, else: true end) end) diff --git a/lib/pleroma/search/elasticsearch/store.ex b/lib/pleroma/search/elasticsearch/store.ex index 3b7bbb838..3f06eb08d 100644 --- a/lib/pleroma/search/elasticsearch/store.ex +++ b/lib/pleroma/search/elasticsearch/store.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Search.Elasticsearch.Store do {:ok, results} else {:error, e} -> - Logger.error(e) + Logger.error("Unable to search with Elasiticsearch: #{inspect(e)}") {:error, e} end end @@ -44,7 +44,7 @@ defmodule Pleroma.Search.Elasticsearch.Store do |> Pleroma.Activity.all_by_ids_with_object() else e -> - Logger.error(e) + Logger.error("Unable to search with Elasiticsearch: #{inspect(e)}") [] end end diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex index 8fcf9310a..b0cf292a3 100644 --- a/lib/pleroma/search/meilisearch.ex +++ b/lib/pleroma/search/meilisearch.ex @@ -79,6 +79,7 @@ defmodule Pleroma.Search.Meilisearch do limit = Enum.min([Keyword.get(options, :limit), 40]) offset = Keyword.get(options, :offset, 0) author = Keyword.get(options, :author) + only_media = Keyword.get(options, :only_media, false) res = meili_post( @@ -93,11 +94,11 @@ defmodule Pleroma.Search.Meilisearch do hits |> Activity.create_by_object_ap_id() |> Activity.with_preloaded_object() - |> Activity.with_preloaded_object() |> Activity.restrict_deactivated_users() |> maybe_restrict_local(user) |> maybe_restrict_author(author) |> maybe_restrict_blocked(user) + |> maybe_only_media(only_media) |> maybe_fetch(user, query) |> order_by([object: obj], desc: obj.data["published"]) |> Pleroma.Repo.all() diff --git a/lib/pleroma/web/api_spec/operations/search_operation.ex b/lib/pleroma/web/api_spec/operations/search_operation.ex index f90c54853..8d5e35841 100644 --- a/lib/pleroma/web/api_spec/operations/search_operation.ex +++ b/lib/pleroma/web/api_spec/operations/search_operation.ex @@ -75,7 +75,7 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do Operation.parameter( :type, :query, - %Schema{type: :string, enum: ["accounts", "hashtags", "statuses"]}, + %Schema{type: :string, enum: ["accounts", "hashtags", "statuses", "media"]}, "Search type" ), Operation.parameter(:q, :query, %Schema{type: :string}, "What to search for", diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 94fbdceca..c0110adb4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -47,7 +47,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do query = String.trim(query) options = search_options(params, user) timeout = Keyword.get(Repo.config(), :timeout, 15_000) - default_values = %{"statuses" => [], "accounts" => [], "hashtags" => []} + default_values = %{"statuses" => [], "media" => [], "accounts" => [], "hashtags" => []} result = default_values @@ -107,6 +107,22 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do ) end + defp resource_search(_, "media", query, options) do + statuses = + with_fallback(fn -> + Pleroma.Search.search( + query, + Keyword.put(options, :only_media, true) + ) + end) + + StatusView.render("index.json", + activities: statuses, + for: options[:for_user], + as: :activity + ) + end + defp resource_search(:v2, "hashtags", query, options) do tags_path = Endpoint.url() <> "/tag/"