X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser.ex;h=18137106e1643b2cb6c1df4541900f85d59fbb67;hb=4a278cd80a02fa1882db17397bb97b155c76570e;hp=2488697bb3bf217d362903ff022f3beab392850f;hpb=5b8f9ff8c14b5992e3db7a0c890ca5539e6a0086;p=akkoma diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 2488697bb..18137106e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -447,8 +447,7 @@ defmodule Pleroma.User do def get_by_nickname(nickname) do Repo.get_by(User, nickname: nickname) || if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do - [local_nickname, _] = String.split(nickname, "@") - Repo.get_by(User, nickname: local_nickname) + Repo.get_by(User, nickname: local_nickname(nickname)) end end @@ -679,46 +678,28 @@ defmodule Pleroma.User do end def search(query, resolve \\ false, for_user \\ nil) do - # strip the beginning @ off if there is a query + # Strip the beginning @ off if there is a query query = String.trim_leading(query, "@") - if resolve do - User.get_or_fetch_by_nickname(query) - end + if resolve, do: User.get_or_fetch_by_nickname(query) - processed_query = - query - |> String.replace(~r/\W+/, " ") - |> String.trim() - |> String.split() - |> Enum.map(&(&1 <> ":*")) - |> Enum.join(" | ") + fts_results = do_search(fts_search_subquery(query), for_user) - inner = - from( - u in User, - select_merge: %{ - search_rank: - fragment( - """ - ts_rank_cd( - setweight(to_tsvector('simple', regexp_replace(nickname, '\\W', ' ', 'g')), 'A') || - setweight(to_tsvector('simple', regexp_replace(coalesce(name, ''), '\\W', ' ', 'g')), 'B'), - to_tsquery('simple', ?), - 32 - ) - """, - ^processed_query - ) - }, - where: not is_nil(u.nickname) - ) + {:ok, trigram_results} = + Repo.transaction(fn -> + Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", []) + do_search(trigram_search_subquery(query), for_user) + end) + Enum.uniq_by(fts_results ++ trigram_results, & &1.id) + end + + defp do_search(subquery, for_user, options \\ []) do q = from( - s in subquery(inner), + s in subquery(subquery), order_by: [desc: s.search_rank], - limit: 20 + limit: ^(options[:limit] || 20) ) results = @@ -726,35 +707,90 @@ defmodule Pleroma.User do |> Repo.all() |> Enum.filter(&(&1.search_rank > 0)) - weighted_results = - if for_user do - friends_ids = get_friends_ids(for_user) - followers_ids = get_followers_ids(for_user) + boost_search_results(results, for_user) + end - Enum.map( - results, - fn u -> - search_rank_coef = - cond do - u.id in friends_ids -> - 1.2 + defp fts_search_subquery(query) do + processed_query = + query + |> String.replace(~r/\W+/, " ") + |> String.trim() + |> String.split() + |> Enum.map(&(&1 <> ":*")) + |> Enum.join(" | ") - u.id in followers_ids -> - 1.1 + from( + u in User, + select_merge: %{ + search_rank: + fragment( + """ + ts_rank_cd( + setweight(to_tsvector('simple', regexp_replace(?, '\\W', ' ', 'g')), 'A') || + setweight(to_tsvector('simple', regexp_replace(coalesce(?, ''), '\\W', ' ', 'g')), 'B'), + to_tsquery('simple', ?), + 32 + ) + """, + u.nickname, + u.name, + ^processed_query + ) + }, + where: + fragment( + """ + (setweight(to_tsvector('simple', regexp_replace(?, '\\W', ' ', 'g')), 'A') || + setweight(to_tsvector('simple', regexp_replace(coalesce(?, ''), '\\W', ' ', 'g')), 'B')) @@ to_tsquery('simple', ?) + """, + u.nickname, + u.name, + ^processed_query + ) + ) + end - true -> - 1 - end + defp trigram_search_subquery(query) do + from( + u in User, + select_merge: %{ + search_rank: + fragment( + "similarity(?, trim(? || ' ' || coalesce(?, '')))", + ^query, + u.nickname, + u.name + ) + }, + where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^query) + ) + end + + defp boost_search_results(results, nil), do: results + + defp boost_search_results(results, for_user) do + friends_ids = get_friends_ids(for_user) + followers_ids = get_followers_ids(for_user) - Map.put(u, :search_rank, u.search_rank * search_rank_coef) + Enum.map( + results, + fn u -> + search_rank_coef = + cond do + u.id in friends_ids -> + 1.2 + + u.id in followers_ids -> + 1.1 + + true -> + 1 end - ) - |> Enum.sort_by(&(-&1.search_rank)) - else - results - end - weighted_results + Map.put(u, :search_rank, u.search_rank * search_rank_coef) + end + ) + |> Enum.sort_by(&(-&1.search_rank)) end def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do @@ -854,7 +890,7 @@ defmodule Pleroma.User do update_and_set_cache(cng) end - def local_user_query() do + def local_user_query do from( u in User, where: u.local == true, @@ -862,7 +898,14 @@ defmodule Pleroma.User do ) end - def moderator_user_query() do + def active_local_user_query do + from( + u in local_user_query(), + where: fragment("not (?->'deactivated' @> 'true')", u.info) + ) + end + + def moderator_user_query do from( u in User, where: u.local == true, @@ -1048,7 +1091,7 @@ defmodule Pleroma.User do end) bio - |> CommonUtils.format_input(mentions, tags, "text/plain") + |> CommonUtils.format_input(mentions, tags, "text/plain", user_links: [format: :full]) |> Formatter.emojify(emoji) end @@ -1098,4 +1141,24 @@ defmodule Pleroma.User do @strict_local_nickname_regex end end + + def local_nickname(nickname_or_mention) do + nickname_or_mention + |> full_nickname() + |> String.split("@") + |> hd() + end + + def full_nickname(nickname_or_mention), + do: String.trim_leading(nickname_or_mention, "@") + + def error_user(ap_id) do + %User{ + name: ap_id, + ap_id: ap_id, + info: %User.Info{}, + nickname: "erroruser@example.com", + inserted_at: NaiveDateTime.utc_now() + } + end end