X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser.ex;h=f49ede149eec5a1e5fbe085d1a10877d0ff24654;hb=46200d8facfa63343360c9e14cf94f34c55c7d53;hp=35ba4ad995246a7362a8a05cb14ca6f53610d714;hpb=11b3c10c54254ecad4b52f27856b8d95629e541c;p=akkoma diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 35ba4ad99..f49ede149 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -22,6 +22,7 @@ defmodule Pleroma.User do alias Pleroma.Web.OAuth alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.RelMe require Logger @@ -273,7 +274,7 @@ defmodule Pleroma.User do Pleroma.Config.get([:instance, :account_activation_required]) do user |> Pleroma.UserEmail.account_confirmation_email() - |> Pleroma.Mailer.deliver() + |> Pleroma.Mailer.deliver_async() else {:ok, :noop} end @@ -531,6 +532,10 @@ defmodule Pleroma.User do _e -> with [_nick, _domain] <- String.split(nickname, "@"), {:ok, user} <- fetch_by_nickname(nickname) do + if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do + {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) + end + user else _e -> nil @@ -538,6 +543,17 @@ defmodule Pleroma.User do end end + @doc "Fetch some posts when the user has just been federated with" + def fetch_initial_posts(user) do + pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) + + Enum.each( + # Insert all the posts in reverse order, so they're in the right order on the timeline + Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), + &Pleroma.Web.Federator.incoming_ap_doc/1 + ) + end + def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do from( u in User, @@ -547,11 +563,8 @@ defmodule Pleroma.User do end def get_followers_query(user, page) do - from( - u in get_followers_query(user, nil), - limit: 20, - offset: ^((page - 1) * 20) - ) + from(u in get_followers_query(user, nil)) + |> paginate(page, 20) end def get_followers_query(user), do: get_followers_query(user, nil) @@ -577,11 +590,8 @@ defmodule Pleroma.User do end def get_friends_query(user, page) do - from( - u in get_friends_query(user, nil), - limit: 20, - offset: ^((page - 1) * 20) - ) + from(u in get_friends_query(user, nil)) + |> paginate(page, 20) end def get_friends_query(user), do: get_friends_query(user, nil) @@ -613,71 +623,65 @@ defmodule Pleroma.User do ), where: fragment( - "? @> ?", + "coalesce((?)->'object'->>'id', (?)->>'object') = ?", a.data, - ^%{"object" => user.ap_id} + a.data, + ^user.ap_id ) ) end - def update_follow_request_count(%User{} = user) do - subquery = + def get_follow_requests(%User{} = user) do + users = user |> User.get_follow_requests_query() - |> select([a], %{count: count(a.id)}) + |> join(:inner, [a], u in User, a.actor == u.ap_id) + |> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address])) + |> group_by([a, u], u.id) + |> select([a, u], u) + |> Repo.all() + + {:ok, users} + end + def increase_note_count(%User{} = user) do User |> where(id: ^user.id) - |> join(:inner, [u], s in subquery(subquery)) - |> update([u, s], + |> update([u], set: [ info: fragment( - "jsonb_set(?, '{follow_request_count}', ?::varchar::jsonb, true)", + "jsonb_set(?, '{note_count}', ((?->>'note_count')::int + 1)::varchar::jsonb, true)", u.info, - s.count + u.info ) ] ) |> Repo.update_all([], returning: true) |> case do - {1, [user]} -> {:ok, user} + {1, [user]} -> set_cache(user) _ -> {:error, user} end end - def get_follow_requests(%User{} = user) do - q = get_follow_requests_query(user) - reqs = Repo.all(q) - - users = - Enum.map(reqs, fn req -> req.actor end) - |> Enum.uniq() - |> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end) - |> Enum.filter(fn u -> !is_nil(u) end) - |> Enum.filter(fn u -> !following?(u, user) end) - - {:ok, users} - end - - def increase_note_count(%User{} = user) do - info_cng = User.Info.add_to_note_count(user.info, 1) - - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) - end - def decrease_note_count(%User{} = user) do - info_cng = User.Info.add_to_note_count(user.info, -1) - - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + User + |> where(id: ^user.id) + |> update([u], + set: [ + info: + fragment( + "jsonb_set(?, '{note_count}', (greatest(0, (?->>'note_count')::int - 1))::varchar::jsonb, true)", + u.info, + u.info + ) + ] + ) + |> Repo.update_all([], returning: true) + |> case do + {1, [user]} -> set_cache(user) + _ -> {:error, user} + end end def update_note_count(%User{} = user) do @@ -701,24 +705,29 @@ defmodule Pleroma.User do def update_follower_count(%User{} = user) do follower_count_query = - from( - u in User, - where: ^user.follower_address in u.following, - where: u.id != ^user.id, - select: count(u.id) - ) - - follower_count = Repo.one(follower_count_query) - - info_cng = - user.info - |> User.Info.set_follower_count(follower_count) - - cng = - change(user) - |> put_embed(:info, info_cng) + User + |> where([u], ^user.follower_address in u.following) + |> where([u], u.id != ^user.id) + |> select([u], %{count: count(u.id)}) - update_and_set_cache(cng) + User + |> where(id: ^user.id) + |> join(:inner, [u], s in subquery(follower_count_query)) + |> update([u, s], + set: [ + info: + fragment( + "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)", + u.info, + s.count + ) + ] + ) + |> Repo.update_all([], returning: true) + |> case do + {1, [user]} -> set_cache(user) + _ -> {:error, user} + end end def get_users_from_set_query(ap_ids, false) do @@ -755,6 +764,59 @@ defmodule Pleroma.User do Repo.all(query) end + @spec search_for_admin(%{ + local: boolean(), + page: number(), + page_size: number() + }) :: {:ok, [Pleroma.User.t()], number()} + def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do + query = + from(u in User, order_by: u.id) + |> maybe_local_user_query(local) + + paginated_query = + query + |> paginate(page, page_size) + + count = + query + |> Repo.aggregate(:count, :id) + + {:ok, Repo.all(paginated_query), count} + end + + @spec search_for_admin(%{ + query: binary(), + admin: Pleroma.User.t(), + local: boolean(), + page: number(), + page_size: number() + }) :: {:ok, [Pleroma.User.t()], number()} + def search_for_admin(%{ + query: term, + admin: admin, + local: local, + page: page, + page_size: page_size + }) do + term = String.trim_leading(term, "@") + + local_paginated_query = + User + |> maybe_local_user_query(local) + |> paginate(page, page_size) + + search_query = fts_search_subquery(term, local_paginated_query) + + count = + term + |> fts_search_subquery() + |> maybe_local_user_query(local) + |> Repo.aggregate(:count, :id) + + {:ok, do_search(search_query, admin), count} + end + def search(query, resolve \\ false, for_user \\ nil) do # Strip the beginning @ off if there is a query query = String.trim_leading(query, "@") @@ -788,9 +850,9 @@ defmodule Pleroma.User do boost_search_results(results, for_user) end - defp fts_search_subquery(query) do + defp fts_search_subquery(term, query \\ User) do processed_query = - query + term |> String.replace(~r/\W+/, " ") |> String.trim() |> String.split() @@ -798,7 +860,7 @@ defmodule Pleroma.User do |> Enum.join(" | ") from( - u in User, + u in query, select_merge: %{ search_rank: fragment( @@ -828,19 +890,19 @@ defmodule Pleroma.User do ) end - defp trigram_search_subquery(query) do + defp trigram_search_subquery(term) do from( u in User, select_merge: %{ search_rank: fragment( "similarity(?, trim(? || ' ' || coalesce(?, '')))", - ^query, + ^term, u.nickname, u.name ) }, - where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^query) + where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term) ) end @@ -954,6 +1016,7 @@ defmodule Pleroma.User do update_and_set_cache(cng) end + def mutes?(nil, _), do: false def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.info.mutes, ap_id) def blocks?(user, %{ap_id: ap_id}) do @@ -997,9 +1060,13 @@ defmodule Pleroma.User do update_and_set_cache(cng) end - def local_user_query do + def maybe_local_user_query(query, local) do + if local, do: local_user_query(query), else: query + end + + def local_user_query(query \\ User) do from( - u in User, + u in query, where: u.local == true, where: not is_nil(u.nickname) ) @@ -1069,24 +1136,36 @@ defmodule Pleroma.User do def html_filter_policy(_), do: @default_scrubbers + def fetch_by_ap_id(ap_id) do + ap_try = ActivityPub.make_user_from_ap_id(ap_id) + + case ap_try do + {:ok, user} -> + user + + _ -> + case OStatus.make_user(ap_id) do + {:ok, user} -> user + _ -> {:error, "Could not fetch by AP id"} + end + end + end + def get_or_fetch_by_ap_id(ap_id) do user = get_by_ap_id(ap_id) if !is_nil(user) and !User.needs_update?(user) do user else - ap_try = ActivityPub.make_user_from_ap_id(ap_id) + user = fetch_by_ap_id(ap_id) - case ap_try do - {:ok, user} -> - user - - _ -> - case OStatus.make_user(ap_id) do - {:ok, user} -> user - _ -> {:error, "Could not fetch by AP id"} - end + if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do + with %User{} = user do + {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) + end end + + user end end @@ -1187,9 +1266,6 @@ defmodule Pleroma.User do def parse_bio(bio, _user) when bio == "", do: bio def parse_bio(bio, user) do - mentions = Formatter.parse_mentions(bio) - tags = Formatter.parse_tags(bio) - emoji = (user.info.source_data["tag"] || []) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) @@ -1197,8 +1273,15 @@ defmodule Pleroma.User do {String.trim(name, ":"), url} end) + # TODO: get profile URLs other than user.ap_id + profile_urls = [user.ap_id] + bio - |> CommonUtils.format_input(mentions, tags, "text/plain", user_links: [format: :full]) + |> CommonUtils.format_input("text/plain", + mentions_format: :full, + rel: &RelMe.maybe_put_rel_me(&1, profile_urls) + ) + |> elem(0) |> Formatter.emojify(emoji) end @@ -1284,4 +1367,20 @@ defmodule Pleroma.User do inserted_at: NaiveDateTime.utc_now() } end + + def all_superusers do + from( + u in User, + where: u.local == true, + where: fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info) + ) + |> Repo.all() + end + + defp paginate(query, page, page_size) do + from(u in query, + limit: ^page_size, + offset: ^((page - 1) * page_size) + ) + end end