aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/user
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/user')
-rw-r--r--lib/pleroma/user/query.ex19
-rw-r--r--lib/pleroma/user/search.ex27
-rw-r--r--lib/pleroma/user/synchronization.ex60
-rw-r--r--lib/pleroma/user/synchronization_worker.ex32
4 files changed, 135 insertions, 3 deletions
diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex
index ace9c05f2..f9bcc9e19 100644
--- a/lib/pleroma/user/query.ex
+++ b/lib/pleroma/user/query.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.User.Query do
User query builder module. Builds query from new query or another user query.
## Example:
- query = Pleroma.User.Query(%{nickname: "nickname"})
+ query = Pleroma.User.Query.build(%{nickname: "nickname"})
another_query = Pleroma.User.Query.build(query, %{email: "email@example.com"})
Pleroma.Repo.all(query)
Pleroma.Repo.all(another_query)
@@ -47,7 +47,10 @@ defmodule Pleroma.User.Query do
friends: User.t(),
recipients_from_activity: [String.t()],
nickname: [String.t()],
- ap_id: [String.t()]
+ ap_id: [String.t()],
+ order_by: term(),
+ select: term(),
+ limit: pos_integer()
}
| %{}
@@ -141,6 +144,18 @@ defmodule Pleroma.User.Query do
where(query, [u], u.ap_id in ^to or fragment("? && ?", u.following, ^to))
end
+ defp compose_query({:order_by, key}, query) do
+ order_by(query, [u], field(u, ^key))
+ end
+
+ defp compose_query({:select, keys}, query) do
+ select(query, [u], ^keys)
+ end
+
+ defp compose_query({:limit, limit}, query) do
+ limit(query, ^limit)
+ end
+
defp compose_query(_unsupported_param, query), do: query
defp prepare_tag_criteria(tag, query) do
diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex
index ed06c2ab9..64eb6d2bc 100644
--- a/lib/pleroma/user/search.ex
+++ b/lib/pleroma/user/search.ex
@@ -43,6 +43,8 @@ defmodule Pleroma.User.Search do
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()
@@ -55,6 +57,25 @@ defmodule Pleroma.User.Search do
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
@@ -129,7 +150,7 @@ defmodule Pleroma.User.Search do
@spec fts_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
defp fts_search_subquery(query, term) do
processed_query =
- term
+ String.trim_trailing(term, "@" <> local_domain())
|> String.replace(~r/\W+/, " ")
|> String.trim()
|> String.split()
@@ -171,6 +192,8 @@ defmodule Pleroma.User.Search do
@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: %{
@@ -188,4 +211,6 @@ defmodule Pleroma.User.Search do
)
|> User.restrict_deactivated()
end
+
+ defp local_domain, do: Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
end
diff --git a/lib/pleroma/user/synchronization.ex b/lib/pleroma/user/synchronization.ex
new file mode 100644
index 000000000..93660e08c
--- /dev/null
+++ b/lib/pleroma/user/synchronization.ex
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.Synchronization do
+ alias Pleroma.HTTP
+ alias Pleroma.User
+
+ @spec call([User.t()], map(), keyword()) :: {User.t(), map()}
+ def call(users, errors, opts \\ []) do
+ do_call(users, errors, opts)
+ end
+
+ defp do_call([user | []], errors, opts) do
+ updated = fetch_counters(user, errors, opts)
+ {user, updated}
+ end
+
+ defp do_call([user | others], errors, opts) do
+ updated = fetch_counters(user, errors, opts)
+ do_call(others, updated, opts)
+ end
+
+ defp fetch_counters(user, errors, opts) do
+ %{host: host} = URI.parse(user.ap_id)
+
+ info = %{}
+ {following, errors} = fetch_counter(user.ap_id <> "/following", host, errors, opts)
+ info = if following, do: Map.put(info, :following_count, following), else: info
+
+ {followers, errors} = fetch_counter(user.ap_id <> "/followers", host, errors, opts)
+ info = if followers, do: Map.put(info, :follower_count, followers), else: info
+
+ User.set_info_cache(user, info)
+ errors
+ end
+
+ defp available_domain?(domain, errors, opts) do
+ max_retries = Keyword.get(opts, :max_retries, 3)
+ not (Map.has_key?(errors, domain) && errors[domain] >= max_retries)
+ end
+
+ defp fetch_counter(url, host, errors, opts) do
+ with true <- available_domain?(host, errors, opts),
+ {:ok, %{body: body, status: code}} when code in 200..299 <-
+ HTTP.get(
+ url,
+ [{:Accept, "application/activity+json"}]
+ ),
+ {:ok, data} <- Jason.decode(body) do
+ {data["totalItems"], errors}
+ else
+ false ->
+ {nil, errors}
+
+ _ ->
+ {nil, Map.update(errors, host, 1, &(&1 + 1))}
+ end
+ end
+end
diff --git a/lib/pleroma/user/synchronization_worker.ex b/lib/pleroma/user/synchronization_worker.ex
new file mode 100644
index 000000000..ba9cc3556
--- /dev/null
+++ b/lib/pleroma/user/synchronization_worker.ex
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-onl
+
+defmodule Pleroma.User.SynchronizationWorker do
+ use GenServer
+
+ def start_link do
+ config = Pleroma.Config.get([:instance, :external_user_synchronization])
+
+ if config[:enabled] do
+ GenServer.start_link(__MODULE__, interval: config[:interval])
+ else
+ :ignore
+ end
+ end
+
+ def init(opts) do
+ schedule_next(opts)
+ {:ok, opts}
+ end
+
+ def handle_info(:sync_follow_counters, opts) do
+ Pleroma.User.sync_follow_counter()
+ schedule_next(opts)
+ {:noreply, opts}
+ end
+
+ defp schedule_next(opts) do
+ Process.send_after(self(), :sync_follow_counters, opts[:interval])
+ end
+end