Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85805344
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
31 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/config/test.exs b/config/test.exs
index 19d7cca5f..96ecf3592 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -1,87 +1,89 @@
use Mix.Config
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :pleroma, Pleroma.Web.Endpoint,
http: [port: 4001],
url: [port: 4001],
server: true
# Disable captha for tests
config :pleroma, Pleroma.Captcha,
# It should not be enabled for automatic tests
enabled: false,
# A fake captcha service for tests
method: Pleroma.Captcha.Mock
# Print only warnings and errors during test
config :logger, level: :warn
config :pleroma, :auth, oauth_consumer_strategies: []
config :pleroma, Pleroma.Upload, filters: [], link_name: false
config :pleroma, Pleroma.Uploaders.Local, uploads: "test/uploads"
config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Test, enabled: true
config :pleroma, :instance,
email: "admin@example.com",
notify_email: "noreply@example.com",
skip_thread_containment: false,
federating: false
# Configure your database
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
username: "postgres",
password: "postgres",
database: "pleroma_test",
hostname: System.get_env("DB_HOST") || "localhost",
pool: Ecto.Adapters.SQL.Sandbox
# Reduce hash rounds for testing
config :pbkdf2_elixir, rounds: 1
config :tesla, adapter: Tesla.Mock
config :pleroma, :rich_media,
enabled: false,
ignore_hosts: [],
ignore_tld: ["local", "localdomain", "lan"]
config :web_push_encryption, :vapid_details,
subject: "mailto:administrator@example.com",
public_key:
"BLH1qVhJItRGCfxgTtONfsOKDc9VRAraXw-3NsmjMngWSh7NxOizN6bkuRA7iLTMPS82PjwJAr3UoK9EC1IFrz4",
private_key: "_-XZ0iebPrRfZ_o0-IatTdszYa8VCH1yLN-JauK7HHA"
config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock
config :pleroma_job_queue, disabled: true
config :pleroma, Pleroma.ScheduledActivity,
daily_user_limit: 2,
total_user_limit: 3,
enabled: false
-config :pleroma, :rate_limit, app_account_creation: {10_000, 5}
+config :pleroma, :rate_limit,
+ search: [{1000, 30}, {1000, 30}],
+ app_account_creation: {10_000, 5}
config :pleroma, :http_security, report_uri: "https://endpoint.com"
config :pleroma, :http, send_user_agent: false
rum_enabled = System.get_env("RUM_ENABLED") == "true"
config :pleroma, :database, rum_enabled: rum_enabled
IO.puts("RUM enabled: #{rum_enabled}")
config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
try do
import_config "test.secret.exs"
rescue
_ ->
IO.puts(
"You may want to create test.secret.exs to declare custom database connection parameters."
)
end
diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex
index f6b0f9625..0cc3770a7 100644
--- a/lib/pleroma/activity/search.ex
+++ b/lib/pleroma/activity/search.ex
@@ -1,97 +1,92 @@
# 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.Pagination
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Visibility
import Ecto.Query
def search(user, search_query, options \\ []) do
index_type = if Pleroma.Config.get([:database, :rum_enabled]), do: :rum, else: :gin
limit = Enum.min([Keyword.get(options, :limit), 40])
offset = Keyword.get(options, :offset, 0)
author = Keyword.get(options, :author)
Activity
|> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users()
|> restrict_public()
|> query_with(index_type, search_query)
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
- |> paginate(limit, offset)
- |> Repo.all()
+ |> Pagination.fetch_paginated(%{"offset" => offset, "limit" => limit}, :offset)
|> maybe_fetch(user, search_query)
end
def maybe_restrict_author(query, %User{} = author) do
from([a, o] in query,
where: a.actor == ^author.ap_id
)
end
def maybe_restrict_author(query, _), do: query
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
)
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
)
)
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
defp maybe_restrict_local(q, user) do
limit = Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)
case {limit, user} do
{:all, _} -> restrict_local(q)
{:unauthenticated, %User{}} -> q
{:unauthenticated, _} -> restrict_local(q)
{false, _} -> q
end
end
defp 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
-
- defp paginate(query, limit, offset) do
- from(q in query, limit: ^limit, offset: ^offset)
- end
end
diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex
index 3d7dd9e6a..2b869ccdc 100644
--- a/lib/pleroma/pagination.ex
+++ b/lib/pleroma/pagination.ex
@@ -1,88 +1,111 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Pagination do
@moduledoc """
Implements Mastodon-compatible pagination.
"""
import Ecto.Query
import Ecto.Changeset
alias Pleroma.Repo
@default_limit 20
- def fetch_paginated(query, params) do
+ def fetch_paginated(query, params, type \\ :keyset)
+
+ def fetch_paginated(query, params, :keyset) do
options = cast_params(params)
query
- |> paginate(options)
+ |> paginate(options, :keyset)
|> Repo.all()
|> enforce_order(options)
end
- def paginate(query, options) do
+ def fetch_paginated(query, params, :offset) do
+ options = cast_params(params)
+
+ query
+ |> paginate(options, :offset)
+ |> Repo.all()
+ end
+
+ def paginate(query, options, method \\ :keyset)
+
+ def paginate(query, options, :keyset) do
query
|> restrict(:min_id, options)
|> restrict(:since_id, options)
|> restrict(:max_id, options)
|> restrict(:order, options)
|> restrict(:limit, options)
end
+ def paginate(query, options, :offset) do
+ query
+ |> restrict(:offset, options)
+ |> restrict(:limit, options)
+ end
+
defp cast_params(params) do
param_types = %{
min_id: :string,
since_id: :string,
max_id: :string,
+ offset: :integer,
limit: :integer
}
params =
Enum.reduce(params, %{}, fn
{key, _value}, acc when is_atom(key) -> Map.drop(acc, [key])
{key, value}, acc -> Map.put(acc, key, value)
end)
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
changeset.changes
end
defp restrict(query, :min_id, %{min_id: min_id}) do
where(query, [q], q.id > ^min_id)
end
defp restrict(query, :since_id, %{since_id: since_id}) do
where(query, [q], q.id > ^since_id)
end
defp restrict(query, :max_id, %{max_id: max_id}) do
where(query, [q], q.id < ^max_id)
end
defp restrict(query, :order, %{min_id: _}) do
order_by(query, [u], fragment("? asc nulls last", u.id))
end
defp restrict(query, :order, _options) do
order_by(query, [u], fragment("? desc nulls last", u.id))
end
+ defp restrict(query, :offset, %{offset: offset}) do
+ offset(query, ^offset)
+ end
+
defp restrict(query, :limit, options) do
limit = Map.get(options, :limit, @default_limit)
query
|> limit(^limit)
end
defp restrict(query, _, _), do: query
defp enforce_order(result, %{min_id: _}) do
result
|> Enum.reverse()
end
defp enforce_order(result, _), do: result
end
diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex
index 64eb6d2bc..9d8121e7a 100644
--- a/lib/pleroma/user/search.ex
+++ b/lib/pleroma/user/search.ex
@@ -1,216 +1,212 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.Search do
+ alias Pleroma.Pagination
alias Pleroma.Repo
alias Pleroma.User
import Ecto.Query
@similarity_threshold 0.25
@limit 20
def search(query_string, opts \\ []) do
resolve = Keyword.get(opts, :resolve, false)
following = Keyword.get(opts, :following, false)
result_limit = Keyword.get(opts, :limit, @limit)
offset = Keyword.get(opts, :offset, 0)
for_user = Keyword.get(opts, :for_user)
# Strip the beginning @ off if there is a query
query_string = String.trim_leading(query_string, "@")
maybe_resolve(resolve, for_user, query_string)
{:ok, results} =
Repo.transaction(fn ->
Ecto.Adapters.SQL.query(
Repo,
"select set_limit(#{@similarity_threshold})",
[]
)
query_string
|> search_query(for_user, following)
- |> paginate(result_limit, offset)
- |> Repo.all()
+ |> Pagination.fetch_paginated(%{"offset" => offset, "limit" => result_limit}, :offset)
end)
results
end
defp search_query(query_string, for_user, following) do
for_user
|> base_query(following)
|> filter_blocked_user(for_user)
|> filter_blocked_domains(for_user)
|> search_subqueries(query_string)
|> union_subqueries
|> distinct_query()
|> boost_search_rank_query(for_user)
|> subquery()
|> order_by(desc: :search_rank)
|> maybe_restrict_local(for_user)
end
defp base_query(_user, false), do: User
defp base_query(user, true), do: User.get_followers_query(user)
defp filter_blocked_user(query, %User{info: %{blocks: blocks}})
when length(blocks) > 0 do
from(q in query, where: not (q.ap_id in ^blocks))
end
defp filter_blocked_user(query, _), do: query
defp filter_blocked_domains(query, %User{info: %{domain_blocks: domain_blocks}})
when length(domain_blocks) > 0 do
domains = Enum.join(domain_blocks, ",")
from(
q in query,
where: fragment("substring(ap_id from '.*://([^/]*)') NOT IN (?)", ^domains)
)
end
defp filter_blocked_domains(query, _), do: query
- defp paginate(query, limit, offset) do
- from(q in query, limit: ^limit, offset: ^offset)
- end
-
defp union_subqueries({fts_subquery, trigram_subquery}) do
from(s in trigram_subquery, union_all: ^fts_subquery)
end
defp search_subqueries(base_query, query_string) do
{
fts_search_subquery(base_query, query_string),
trigram_search_subquery(base_query, query_string)
}
end
defp distinct_query(q) do
from(s in subquery(q), order_by: s.search_type, distinct: s.id)
end
defp maybe_resolve(true, user, query) do
case {limit(), user} do
{:all, _} -> :noop
{:unauthenticated, %User{}} -> User.get_or_fetch(query)
{:unauthenticated, _} -> :noop
{false, _} -> User.get_or_fetch(query)
end
end
defp maybe_resolve(_, _, _), do: :noop
defp maybe_restrict_local(q, user) do
case {limit(), user} do
{:all, _} -> restrict_local(q)
{:unauthenticated, %User{}} -> q
{:unauthenticated, _} -> restrict_local(q)
{false, _} -> q
end
end
defp limit, do: Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)
defp restrict_local(q), do: where(q, [u], u.local == true)
defp boost_search_rank_query(query, nil), do: query
defp boost_search_rank_query(query, for_user) do
friends_ids = User.get_friends_ids(for_user)
followers_ids = User.get_followers_ids(for_user)
from(u in subquery(query),
select_merge: %{
search_rank:
fragment(
"""
CASE WHEN (?) THEN 0.5 + (?) * 1.3
WHEN (?) THEN 0.5 + (?) * 1.2
WHEN (?) THEN (?) * 1.1
ELSE (?) END
""",
u.id in ^friends_ids and u.id in ^followers_ids,
u.search_rank,
u.id in ^friends_ids,
u.search_rank,
u.id in ^followers_ids,
u.search_rank,
u.search_rank
)
}
)
end
@spec fts_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
defp fts_search_subquery(query, term) do
processed_query =
String.trim_trailing(term, "@" <> local_domain())
|> String.replace(~r/\W+/, " ")
|> String.trim()
|> String.split()
|> Enum.map(&(&1 <> ":*"))
|> Enum.join(" | ")
from(
u in query,
select_merge: %{
search_type: ^0,
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
)
)
|> User.restrict_deactivated()
end
@spec trigram_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
defp trigram_search_subquery(query, term) do
term = String.trim_trailing(term, "@" <> local_domain())
from(
u in query,
select_merge: %{
# ^1 gives 'Postgrex expected a binary, got 1' for some weird reason
search_type: fragment("?", 1),
search_rank:
fragment(
"similarity(?, trim(? || ' ' || coalesce(?, '')))",
^term,
u.nickname,
u.name
)
},
where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term)
)
|> User.restrict_deactivated()
end
defp local_domain, do: Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
end
diff --git a/lib/pleroma/web/mastodon_api/search_controller.ex b/lib/pleroma/web/mastodon_api/search_controller.ex
index 5ddf6664d..9072aa7a4 100644
--- a/lib/pleroma/web/mastodon_api/search_controller.ex
+++ b/lib/pleroma/web/mastodon_api/search_controller.ex
@@ -1,107 +1,120 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller
alias Pleroma.Activity
alias Pleroma.Plugs.RateLimiter
+ alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.StatusView
require Logger
plug(RateLimiter, :search when action in [:search, :search2, :account_search])
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, search_options(params, user))
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
json(conn, res)
end
def search2(conn, params), do: do_search(:v2, conn, params)
def search(conn, params), do: do_search(:v1, conn, params)
defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = params) do
options = search_options(params, user)
+ timeout = Keyword.get(Repo.config(), :timeout, 15_000)
+ default_values = %{"statuses" => [], "accounts" => [], "hashtags" => []}
result =
- %{"statuses" => [], "accounts" => [], "hashtags" => []}
- |> Enum.reduce(%{}, fn {resource_type, default_value}, acc ->
- if params["type"] == nil or params["type"] == resource_type do
- result = resource_search(version, resource_type, query, options)
- Map.put(acc, resource_type, result)
+ default_values
+ |> Enum.map(fn {resource, default_value} ->
+ if params["type"] == nil or params["type"] == resource do
+ {resource, fn -> resource_search(version, resource, query, options) end}
else
- Map.put(acc, resource_type, default_value)
+ {resource, fn -> default_value end}
end
end)
+ |> Task.async_stream(fn {resource, f} -> {resource, with_fallback(f)} end,
+ timeout: timeout,
+ on_timeout: :kill_task
+ )
+ |> Enum.reduce(default_values, fn
+ {:ok, {resource, result}}, acc ->
+ Map.put(acc, resource, result)
+
+ _error, acc ->
+ acc
+ end)
json(conn, result)
end
defp search_options(params, user) do
[
resolve: params["resolve"] == "true",
following: params["following"] == "true",
limit: ControllerHelper.fetch_integer_param(params, "limit"),
offset: ControllerHelper.fetch_integer_param(params, "offset"),
type: params["type"],
author: get_author(params),
for_user: user
]
|> Enum.filter(&elem(&1, 1))
end
defp resource_search(_, "accounts", query, options) do
accounts = with_fallback(fn -> User.search(query, options) end)
AccountView.render("accounts.json", users: accounts, for: options[:for_user], as: :user)
end
defp resource_search(_, "statuses", query, options) do
statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
StatusView.render("index.json", activities: statuses, for: options[:for_user], as: :activity)
end
defp resource_search(:v2, "hashtags", query, _options) do
tags_path = Web.base_url() <> "/tag/"
query
|> prepare_tags()
|> Enum.map(fn tag ->
tag = String.trim_leading(tag, "#")
%{name: tag, url: tags_path <> tag}
end)
end
defp resource_search(:v1, "hashtags", query, _options) do
query
|> prepare_tags()
|> Enum.map(fn tag -> String.trim_leading(tag, "#") end)
end
defp prepare_tags(query) do
query
|> String.split()
|> Enum.uniq()
|> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
end
defp with_fallback(f, fallback \\ []) do
try do
f.()
rescue
error ->
Logger.error("#{__MODULE__} search error: #{inspect(error)}")
fallback
end
end
defp get_author(%{"account_id" => account_id}) when is_binary(account_id),
do: User.get_cached_by_id(account_id)
defp get_author(_params), do: nil
end
diff --git a/test/web/mastodon_api/search_controller_test.exs b/test/web/mastodon_api/search_controller_test.exs
index 576342a6b..9f50c09f4 100644
--- a/test/web/mastodon_api/search_controller_test.exs
+++ b/test/web/mastodon_api/search_controller_test.exs
@@ -1,268 +1,267 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Object
alias Pleroma.Web
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
import ExUnit.CaptureLog
import Tesla.Mock
import Mock
setup do
mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
describe ".search2" do
test "it returns empty result if user or status search return undefined error", %{conn: conn} do
with_mocks [
{Pleroma.User, [], [search: fn _q, _o -> raise "Oops" end]},
- {Pleroma.Activity, [], [search: fn _u, _q -> raise "Oops" end]}
+ {Pleroma.Activity, [], [search: fn _u, _q, _o -> raise "Oops" end]}
] do
conn = get(conn, "/api/v2/search", %{"q" => "2hu"})
assert results = json_response(conn, 200)
assert results["accounts"] == []
assert results["statuses"] == []
end
end
test "search", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, %{nickname: "shp@shitposter.club"})
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
{:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu private"})
{:ok, _activity} =
CommonAPI.post(user, %{
"status" => "This is about 2hu, but private",
"visibility" => "private"
})
{:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
conn = get(conn, "/api/v2/search", %{"q" => "2hu #private"})
assert results = json_response(conn, 200)
- # IO.inspect results
[account | _] = results["accounts"]
assert account["id"] == to_string(user_three.id)
assert results["hashtags"] == [
%{"name" => "private", "url" => "#{Web.base_url()}/tag/private"}
]
[status] = results["statuses"]
assert status["id"] == to_string(activity.id)
end
end
describe ".account_search" do
test "account search", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, %{nickname: "shp@shitposter.club"})
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
results =
conn
|> assign(:user, user)
|> get("/api/v1/accounts/search", %{"q" => "shp"})
|> json_response(200)
result_ids = for result <- results, do: result["acct"]
assert user_two.nickname in result_ids
assert user_three.nickname in result_ids
results =
conn
|> assign(:user, user)
|> get("/api/v1/accounts/search", %{"q" => "2hu"})
|> json_response(200)
result_ids = for result <- results, do: result["acct"]
assert user_three.nickname in result_ids
end
end
describe ".search" do
test "it returns empty result if user or status search return undefined error", %{conn: conn} do
with_mocks [
{Pleroma.User, [], [search: fn _q, _o -> raise "Oops" end]},
- {Pleroma.Activity, [], [search: fn _u, _q -> raise "Oops" end]}
+ {Pleroma.Activity, [], [search: fn _u, _q, _o -> raise "Oops" end]}
] do
conn =
conn
|> get("/api/v1/search", %{"q" => "2hu"})
assert results = json_response(conn, 200)
assert results["accounts"] == []
assert results["statuses"] == []
end
end
test "search", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, %{nickname: "shp@shitposter.club"})
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
{:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
{:ok, _activity} =
CommonAPI.post(user, %{
"status" => "This is about 2hu, but private",
"visibility" => "private"
})
{:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
conn =
conn
|> get("/api/v1/search", %{"q" => "2hu"})
assert results = json_response(conn, 200)
[account | _] = results["accounts"]
assert account["id"] == to_string(user_three.id)
assert results["hashtags"] == []
[status] = results["statuses"]
assert status["id"] == to_string(activity.id)
end
test "search fetches remote statuses", %{conn: conn} do
capture_log(fn ->
conn =
conn
|> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
assert results = json_response(conn, 200)
[status] = results["statuses"]
assert status["uri"] ==
"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
end)
end
test "search doesn't show statuses that it shouldn't", %{conn: conn} do
{:ok, activity} =
CommonAPI.post(insert(:user), %{
"status" => "This is about 2hu, but private",
"visibility" => "private"
})
capture_log(fn ->
conn =
conn
|> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
assert results = json_response(conn, 200)
[] = results["statuses"]
end)
end
test "search fetches remote accounts", %{conn: conn} do
user = insert(:user)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
assert results = json_response(conn, 200)
[account] = results["accounts"]
assert account["acct"] == "shp@social.heldscal.la"
end
test "search doesn't fetch remote accounts if resolve is false", %{conn: conn} do
conn =
conn
|> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "false"})
assert results = json_response(conn, 200)
assert [] == results["accounts"]
end
- end
- test "search with limit and offset", %{conn: conn} do
- user = insert(:user)
- _user_two = insert(:user, %{nickname: "shp@shitposter.club"})
- _user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+ test "search with limit and offset", %{conn: conn} do
+ user = insert(:user)
+ _user_two = insert(:user, %{nickname: "shp@shitposter.club"})
+ _user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
- {:ok, _activity1} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
- {:ok, _activity2} = CommonAPI.post(user, %{"status" => "This is also about 2hu"})
+ {:ok, _activity1} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+ {:ok, _activity2} = CommonAPI.post(user, %{"status" => "This is also about 2hu"})
- result =
- conn
- |> get("/api/v1/search", %{"q" => "2hu", "limit" => 1})
+ result =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "limit" => 1})
- assert results = json_response(result, 200)
- assert [%{"id" => activity_id1}] = results["statuses"]
- assert [_] = results["accounts"]
+ assert results = json_response(result, 200)
+ assert [%{"id" => activity_id1}] = results["statuses"]
+ assert [_] = results["accounts"]
- results =
- conn
- |> get("/api/v1/search", %{"q" => "2hu", "limit" => 1, "offset" => 1})
- |> json_response(200)
+ results =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "limit" => 1, "offset" => 1})
+ |> json_response(200)
- assert [%{"id" => activity_id2}] = results["statuses"]
- assert [] = results["accounts"]
+ assert [%{"id" => activity_id2}] = results["statuses"]
+ assert [] = results["accounts"]
- assert activity_id1 != activity_id2
- end
+ assert activity_id1 != activity_id2
+ end
- test "search returns results only for the given type", %{conn: conn} do
- user = insert(:user)
- _user_two = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+ test "search returns results only for the given type", %{conn: conn} do
+ user = insert(:user)
+ _user_two = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
- {:ok, _activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+ {:ok, _activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
- assert %{"statuses" => [_activity], "accounts" => [], "hashtags" => []} =
- conn
- |> get("/api/v1/search", %{"q" => "2hu", "type" => "statuses"})
- |> json_response(200)
+ assert %{"statuses" => [_activity], "accounts" => [], "hashtags" => []} =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "type" => "statuses"})
+ |> json_response(200)
- assert %{"statuses" => [], "accounts" => [_user_two], "hashtags" => []} =
- conn
- |> get("/api/v1/search", %{"q" => "2hu", "type" => "accounts"})
- |> json_response(200)
- end
+ assert %{"statuses" => [], "accounts" => [_user_two], "hashtags" => []} =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "type" => "accounts"})
+ |> json_response(200)
+ end
- test "search uses account_id to filter statuses by the author", %{conn: conn} do
- user = insert(:user, %{nickname: "shp@shitposter.club"})
- user_two = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+ test "search uses account_id to filter statuses by the author", %{conn: conn} do
+ user = insert(:user, %{nickname: "shp@shitposter.club"})
+ user_two = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
- {:ok, activity1} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
- {:ok, activity2} = CommonAPI.post(user_two, %{"status" => "This is also about 2hu"})
+ {:ok, activity1} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+ {:ok, activity2} = CommonAPI.post(user_two, %{"status" => "This is also about 2hu"})
- results =
- conn
- |> get("/api/v1/search", %{"q" => "2hu", "account_id" => user.id})
- |> json_response(200)
+ results =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "account_id" => user.id})
+ |> json_response(200)
- assert [%{"id" => activity_id1}] = results["statuses"]
- assert activity_id1 == activity1.id
- assert [_] = results["accounts"]
+ assert [%{"id" => activity_id1}] = results["statuses"]
+ assert activity_id1 == activity1.id
+ assert [_] = results["accounts"]
- results =
- conn
- |> get("/api/v1/search", %{"q" => "2hu", "account_id" => user_two.id})
- |> json_response(200)
+ results =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "account_id" => user_two.id})
+ |> json_response(200)
- assert [%{"id" => activity_id2}] = results["statuses"]
- assert activity_id2 == activity2.id
+ assert [%{"id" => activity_id2}] = results["statuses"]
+ assert activity_id2 == activity2.id
+ end
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Oct 11, 8:26 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785675
Default Alt Text
(31 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment