X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser.ex;h=3c6fb4f9b614f46ed9f9a225527bc64ad9322e89;hb=f635b675b2cc0bc10b395cd71ae1720b0696d364;hp=3610348876d6c2a0ee769dd40b64386fdfc2946c;hpb=57501defb40955b1edc2552ecf422b48c573aaee;p=akkoma diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 361034887..3c6fb4f9b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -5,13 +5,23 @@ defmodule Pleroma.User do use Ecto.Schema - import Ecto.{Changeset, Query} - alias Pleroma.{Repo, User, Object, Web, Activity, Notification} + import Ecto.Changeset + import Ecto.Query + + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.Object + alias Pleroma.Web + alias Pleroma.Activity + alias Pleroma.Notification alias Comeonin.Pbkdf2 alias Pleroma.Formatter alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils - alias Pleroma.Web.{OStatus, Websub, OAuth} - alias Pleroma.Web.ActivityPub.{Utils, ActivityPub} + alias Pleroma.Web.OStatus + alias Pleroma.Web.Websub + alias Pleroma.Web.OAuth + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.ActivityPub.ActivityPub require Logger @@ -227,6 +237,7 @@ defmodule Pleroma.User do changeset |> put_change(:password_hash, hashed) |> put_change(:ap_id, ap_id) + |> unique_constraint(:ap_id) |> put_change(:following, [followers]) |> put_change(:follower_address, followers) else @@ -251,6 +262,7 @@ defmodule Pleroma.User do def register(%Ecto.Changeset{} = changeset) do with {:ok, user} <- Repo.insert(changeset), {:ok, user} <- autofollow_users(user), + {:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user), {:ok, _} <- try_send_confirmation_email(user) do {:ok, user} end @@ -261,7 +273,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 @@ -301,12 +313,12 @@ defmodule Pleroma.User do end end - @doc "A mass follow for local users. Respects blocks but does not create activities." + @doc "A mass follow for local users. Respects blocks in both directions but does not create activities." @spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()} def follow_all(follower, followeds) do followed_addresses = followeds - |> Enum.reject(fn %{ap_id: ap_id} -> ap_id in follower.info.blocks end) + |> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end) |> Enum.map(fn %{follower_address: fa} -> fa end) q = @@ -608,6 +620,32 @@ defmodule Pleroma.User do ) end + def update_follow_request_count(%User{} = user) do + subquery = + user + |> User.get_follow_requests_query() + |> select([a], %{count: count(a.id)}) + + User + |> where(id: ^user.id) + |> join(:inner, [u], s in subquery(subquery)) + |> update([u, s], + set: [ + info: + fragment( + "jsonb_set(?, '{follow_request_count}', ?::varchar::jsonb, true)", + u.info, + s.count + ) + ] + ) + |> Repo.update_all([], returning: true) + |> case do + {1, [user]} -> {:ok, user} + _ -> {:error, user} + end + end + def get_follow_requests(%User{} = user) do q = get_follow_requests_query(user) reqs = Repo.all(q) @@ -717,24 +755,47 @@ defmodule Pleroma.User do Repo.all(query) end - def search(query, resolve \\ false, for_user \\ nil) do + def search(term, options \\ %{}) do # Strip the beginning @ off if there is a query - query = String.trim_leading(query, "@") + term = String.trim_leading(term, "@") + query = options[:query] || User - if resolve, do: User.get_or_fetch_by_nickname(query) + if options[:resolve], do: get_or_fetch(term) - fts_results = do_search(fts_search_subquery(query), for_user) + fts_results = + do_search(fts_search_subquery(term, query), options[:for_user], limit: options[:limit]) {:ok, trigram_results} = Repo.transaction(fn -> Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", []) - do_search(trigram_search_subquery(query), for_user) + + do_search(trigram_search_subquery(term, query), options[:for_user], limit: options[:limit]) end) Enum.uniq_by(fts_results ++ trigram_results, & &1.id) end - defp do_search(subquery, for_user, options \\ []) do + def all(page, page_size) do + from( + u in User, + limit: ^page_size, + offset: ^((page - 1) * page_size), + order_by: u.id + ) + |> Repo.all() + end + + def count_all_except_one(user) do + query = + from( + u in User, + where: u.id != ^user.id + ) + + Repo.aggregate(query, :count, :id) + end + + defp do_search(subquery, for_user, options) do q = from( s in subquery(subquery), @@ -750,9 +811,9 @@ defmodule Pleroma.User do boost_search_results(results, for_user) end - defp fts_search_subquery(query) do + defp fts_search_subquery(term, query) do processed_query = - query + term |> String.replace(~r/\W+/, " ") |> String.trim() |> String.split() @@ -760,7 +821,7 @@ defmodule Pleroma.User do |> Enum.join(" | ") from( - u in User, + u in query, select_merge: %{ search_rank: fragment( @@ -790,19 +851,19 @@ defmodule Pleroma.User do ) end - defp trigram_search_subquery(query) do + defp trigram_search_subquery(term, query) do from( - u in User, + u in query, 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 @@ -850,6 +911,30 @@ defmodule Pleroma.User do ) end + def mute(muter, %User{ap_id: ap_id}) do + info_cng = + muter.info + |> User.Info.add_to_mutes(ap_id) + + cng = + change(muter) + |> put_embed(:info, info_cng) + + update_and_set_cache(cng) + end + + def unmute(muter, %{ap_id: ap_id}) do + info_cng = + muter.info + |> User.Info.remove_from_mutes(ap_id) + + cng = + change(muter) + |> put_embed(:info, info_cng) + + update_and_set_cache(cng) + end + def block(blocker, %User{ap_id: ap_id} = blocked) do # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213) blocker = @@ -892,6 +977,8 @@ defmodule Pleroma.User do update_and_set_cache(cng) end + def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.info.mutes, ap_id) + def blocks?(user, %{ap_id: ap_id}) do blocks = user.info.blocks domain_blocks = user.info.domain_blocks @@ -903,6 +990,9 @@ defmodule Pleroma.User do end) end + def muted_users(user), + do: Repo.all(from(u in User, where: u.ap_id in ^user.info.mutes)) + def blocked_users(user), do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) @@ -930,6 +1020,10 @@ defmodule Pleroma.User do update_and_set_cache(cng) end + def maybe_local_user_query(local) do + if local, do: local_user_query(), else: User + end + def local_user_query do from( u in User, @@ -1120,9 +1214,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) @@ -1131,7 +1222,8 @@ defmodule Pleroma.User do end) bio - |> CommonUtils.format_input(mentions, tags, "text/plain", user_links: [format: :full]) + |> CommonUtils.format_input("text/plain", mentions_format: :full) + |> elem(0) |> Formatter.emojify(emoji) end @@ -1163,7 +1255,7 @@ defmodule Pleroma.User do {:ok, updated_user} = user |> change(%{tags: new_tags}) - |> Repo.update() + |> update_and_set_cache() updated_user end @@ -1217,4 +1309,13 @@ 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 end