X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser.ex;h=cf378d46772d73f41bee44e5dcbb3547e3f488a1;hb=5e2b491276d5cd8d90fddf219f7653d1c9b31ef3;hp=cd1815b85fd1d8bdf96862ca10b49942d75315f7;hpb=37925cbe78b7fc73f28cc85ffcf1e16fb00f7a24;p=akkoma diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cd1815b85..cf378d467 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -10,7 +10,6 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Pleroma.Activity - alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Registration @@ -53,7 +52,6 @@ defmodule Pleroma.User do field(:search_rank, :float, virtual: true) field(:search_type, :integer, virtual: true) field(:tags, {:array, :string}, default: []) - field(:bookmarks, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime_usec) has_many(:notifications, Notification) has_many(:registrations, Registration) @@ -107,10 +105,8 @@ defmodule Pleroma.User do def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers" def user_info(%User{} = user) do - oneself = if user.local, do: 1, else: 0 - %{ - following_count: length(user.following) - oneself, + following_count: following_count(user), note_count: user.info.note_count, follower_count: user.info.follower_count, locked: user.info.locked, @@ -119,6 +115,20 @@ defmodule Pleroma.User do } end + defp restrict_deactivated(query) do + from(u in query, + where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) + ) + end + + def following_count(%User{following: []}), do: 0 + + def following_count(%User{} = user) do + user + |> get_friends_query() + |> Repo.aggregate(:count, :id) + end + def remote_user_creation(params) do params = params @@ -206,14 +216,15 @@ defmodule Pleroma.User do end def register_changeset(struct, params \\ %{}, opts \\ []) do - confirmation_status = - if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do - :confirmed + need_confirmation? = + if is_nil(opts[:need_confirmation]) do + Pleroma.Config.get([:instance, :account_activation_required]) else - :unconfirmed + opts[:need_confirmation] end - info_change = User.Info.confirmation_changeset(%User.Info{}, confirmation_status) + info_change = + User.Info.confirmation_changeset(%User.Info{}, need_confirmation: need_confirmation?) changeset = struct @@ -256,10 +267,7 @@ defmodule Pleroma.User do candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames]) autofollowed_users = - from(u in User, - where: u.local == true, - where: u.nickname in ^candidates - ) + User.Query.build(%{nickname: candidates, local: true, deactivated: false}) |> Repo.all() follow_all(user, autofollowed_users) @@ -269,6 +277,7 @@ defmodule Pleroma.User do def register(%Ecto.Changeset{} = changeset) do with {:ok, user} <- Repo.insert(changeset), {:ok, user} <- autofollow_users(user), + {:ok, user} <- set_cache(user), {:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user), {:ok, _} <- try_send_confirmation_email(user) do {:ok, user} @@ -279,8 +288,10 @@ defmodule Pleroma.User do if user.info.confirmation_pending && Pleroma.Config.get([:instance, :account_activation_required]) do user - |> Pleroma.UserEmail.account_confirmation_email() - |> Pleroma.Mailer.deliver_async() + |> Pleroma.Emails.UserEmail.account_confirmation_email() + |> Pleroma.Emails.Mailer.deliver_async() + + {:ok, :enqueued} else {:ok, :noop} end @@ -419,7 +430,7 @@ defmodule Pleroma.User do Enum.map( followed_identifiers, fn followed_identifier -> - with %User{} = followed <- get_or_fetch(followed_identifier), + with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier), {:ok, follower} <- maybe_direct_follow(follower, followed), {:ok, _} <- ActivityPub.follow(follower, followed) do followed @@ -451,10 +462,13 @@ defmodule Pleroma.User do name = List.last(String.split(ap_id, "/")) nickname = "#{name}@#{domain}" - get_by_nickname(nickname) + get_cached_by_nickname(nickname) end - def set_cache(user) do + def set_cache({:ok, user}), do: set_cache(user) + def set_cache({:error, err}), do: {:error, err} + + def set_cache(%User{} = user) do Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user) Cachex.put(:user_cache, "nickname:#{user.nickname}", user) Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user)) @@ -500,7 +514,15 @@ defmodule Pleroma.User do def get_cached_by_nickname(nickname) do key = "nickname:#{nickname}" - Cachex.fetch!(:user_cache, key, fn _ -> get_or_fetch_by_nickname(nickname) end) + + Cachex.fetch!(:user_cache, key, fn -> + user_result = get_or_fetch_by_nickname(nickname) + + case user_result do + {:ok, user} -> {:commit, user} + {:error, _error} -> {:ignore, nil} + end + end) end def get_cached_by_nickname_or_id(nickname_or_id) do @@ -536,18 +558,19 @@ defmodule Pleroma.User do def get_or_fetch_by_nickname(nickname) do with %User{} = user <- get_by_nickname(nickname) do - user + {:ok, user} else _e -> with [_nick, _domain] <- String.split(nickname, "@"), {:ok, user} <- fetch_by_nickname(nickname) do if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do + # TODO turn into job {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) end - user + {:ok, user} else - _e -> nil + _e -> {:error, "not found " <> nickname} end end end @@ -563,19 +586,17 @@ defmodule Pleroma.User do ) end - def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do - from( - u in User, - where: fragment("? <@ ?", ^[follower_address], u.following), - where: u.id != ^id - ) + @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() + def get_followers_query(%User{} = user, nil) do + User.Query.build(%{followers: user, deactivated: false}) end def get_followers_query(user, page) do from(u in get_followers_query(user, nil)) - |> paginate(page, 20) + |> User.Query.paginate(page, 20) end + @spec get_followers_query(User.t()) :: Ecto.Query.t() def get_followers_query(user), do: get_followers_query(user, nil) def get_followers(user, page \\ nil) do @@ -590,19 +611,17 @@ defmodule Pleroma.User do Repo.all(from(u in q, select: u.id)) end - def get_friends_query(%User{id: id, following: following}, nil) do - from( - u in User, - where: u.follower_address in ^following, - where: u.id != ^id - ) + @spec get_friends_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() + def get_friends_query(%User{} = user, nil) do + User.Query.build(%{friends: user, deactivated: false}) end def get_friends_query(user, page) do from(u in get_friends_query(user, nil)) - |> paginate(page, 20) + |> User.Query.paginate(page, 20) end + @spec get_friends_query(User.t()) :: Ecto.Query.t() def get_friends_query(user), do: get_friends_query(user, nil) def get_friends(user, page \\ nil) do @@ -617,33 +636,10 @@ defmodule Pleroma.User do Repo.all(from(u in q, select: u.id)) end - def get_follow_requests_query(%User{} = user) do - from( - a in Activity, - where: - fragment( - "? ->> 'type' = 'Follow'", - a.data - ), - where: - fragment( - "? ->> 'state' = 'pending'", - a.data - ), - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - a.data, - a.data, - ^user.ap_id - ) - ) - end - + @spec get_follow_requests(User.t()) :: {:ok, [User.t()]} def get_follow_requests(%User{} = user) do users = - user - |> User.get_follow_requests_query() + Activity.follow_requests_for_actor(user) |> join(:inner, [a], u in User, on: a.actor == u.ap_id) |> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address])) |> group_by([a, u], u.id) @@ -707,18 +703,15 @@ defmodule Pleroma.User do info_cng = User.Info.set_note_count(user.info, note_count) - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() end def update_follower_count(%User{} = user) do follower_count_query = - User - |> where([u], ^user.follower_address in u.following) - |> where([u], u.id != ^user.id) + User.Query.build(%{followers: user, deactivated: false}) |> select([u], %{count: count(u.id)}) User @@ -742,38 +735,19 @@ defmodule Pleroma.User do end end - def get_users_from_set_query(ap_ids, false) do - from( - u in User, - where: u.ap_id in ^ap_ids - ) - end - - def get_users_from_set_query(ap_ids, true) do - query = get_users_from_set_query(ap_ids, false) - - from( - u in query, - where: u.local == true - ) - end - + @spec get_users_from_set([String.t()], boolean()) :: [User.t()] def get_users_from_set(ap_ids, local_only \\ true) do - get_users_from_set_query(ap_ids, local_only) + criteria = %{ap_id: ap_ids, deactivated: false} + criteria = if local_only, do: Map.put(criteria, :local, true), else: criteria + + User.Query.build(criteria) |> Repo.all() end + @spec get_recipients_from_activity(Activity.t()) :: [User.t()] def get_recipients_from_activity(%Activity{recipients: to}) do - query = - from( - u in User, - where: u.ap_id in ^to, - or_where: fragment("? && ?", u.following, ^to) - ) - - query = from(u in query, where: u.local == true) - - Repo.all(query) + User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false}) + |> Repo.all() end def search(query, resolve \\ false, for_user \\ nil) do @@ -870,6 +844,7 @@ defmodule Pleroma.User do ^processed_query ) ) + |> restrict_deactivated() end defp trigram_search_subquery(term) do @@ -888,13 +863,14 @@ defmodule Pleroma.User do }, where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term) ) + |> restrict_deactivated() end def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do Enum.map( blocked_identifiers, fn blocked_identifier -> - with %User{} = blocked <- get_or_fetch(blocked_identifier), + with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), {:ok, blocker} <- block(blocker, blocked), {:ok, _} <- ActivityPub.block(blocker, blocked) do blocked @@ -931,6 +907,38 @@ defmodule Pleroma.User do update_and_set_cache(cng) end + def subscribe(subscriber, %{ap_id: ap_id}) do + deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) + + with %User{} = subscribed <- get_cached_by_ap_id(ap_id) do + blocked = blocks?(subscribed, subscriber) and deny_follow_blocked + + if blocked do + {:error, "Could not subscribe: #{subscribed.nickname} is blocking you"} + else + info_cng = + subscribed.info + |> User.Info.add_to_subscribers(subscriber.ap_id) + + change(subscribed) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end + end + end + + def unsubscribe(unsubscriber, %{ap_id: ap_id}) do + with %User{} = user <- get_cached_by_ap_id(ap_id) do + info_cng = + user.info + |> User.Info.remove_from_subscribers(unsubscriber.ap_id) + + change(user) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end + end + def block(blocker, %User{ap_id: ap_id} = blocked) do # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213) blocker = @@ -941,10 +949,20 @@ defmodule Pleroma.User do blocker end + blocker = + if subscribed_to?(blocked, blocker) do + {:ok, blocker} = unsubscribe(blocked, blocker) + blocker + else + blocker + end + if following?(blocked, blocker) do unfollow(blocked, blocker) end + {:ok, blocker} = update_follower_count(blocker) + info_cng = blocker.info |> User.Info.add_to_block(ap_id) @@ -958,7 +976,7 @@ defmodule Pleroma.User do # helper to handle the block given only an actor's AP id def block(blocker, %{ap_id: ap_id}) do - block(blocker, User.get_by_ap_id(ap_id)) + block(blocker, get_cached_by_ap_id(ap_id)) end def unblock(blocker, %{ap_id: ap_id}) do @@ -987,11 +1005,29 @@ 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 subscribed_to?(user, %{ap_id: ap_id}) do + with %User{} = target <- get_cached_by_ap_id(ap_id) do + Enum.member?(target.info.subscribers, user.ap_id) + end + end - def blocked_users(user), - do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) + @spec muted_users(User.t()) :: [User.t()] + def muted_users(user) do + User.Query.build(%{ap_id: user.info.mutes, deactivated: false}) + |> Repo.all() + end + + @spec blocked_users(User.t()) :: [User.t()] + def blocked_users(user) do + User.Query.build(%{ap_id: user.info.blocks, deactivated: false}) + |> Repo.all() + end + + @spec subscribers(User.t()) :: [User.t()] + def subscribers(user) do + User.Query.build(%{ap_id: user.info.subscribers, deactivated: false}) + |> Repo.all() + end def block_domain(user, domain) do info_cng = @@ -1017,112 +1053,75 @@ defmodule Pleroma.User do update_and_set_cache(cng) end - def maybe_local_user_query(query, local) do - if local, do: local_user_query(query), else: query + def deactivate_async(user, status \\ true) do + PleromaJobQueue.enqueue(:background, __MODULE__, [:deactivate_async, user, status]) end - def local_user_query(query \\ User) do - from( - u in query, - where: u.local == true, - where: not is_nil(u.nickname) - ) - end - - def maybe_external_user_query(query, external) do - if external, do: external_user_query(query), else: query - end - - def external_user_query(query \\ User) do - from( - u in query, - where: u.local == false, - where: not is_nil(u.nickname) - ) - end + def perform(:deactivate_async, user, status), do: deactivate(user, status) - def maybe_active_user_query(query, active) do - if active, do: active_user_query(query), else: query - end + def deactivate(%User{} = user, status \\ true) do + info_cng = User.Info.set_activation_status(user.info, status) - def active_user_query(query \\ User) do - from( - u in query, - where: fragment("not (?->'deactivated' @> 'true')", u.info), - where: not is_nil(u.nickname) - ) - end + with {:ok, friends} <- User.get_friends(user), + {:ok, followers} <- User.get_followers(user), + {:ok, user} <- + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() do + Enum.each(followers, &invalidate_cache(&1)) + Enum.each(friends, &update_follower_count(&1)) - def maybe_deactivated_user_query(query, deactivated) do - if deactivated, do: deactivated_user_query(query), else: query + {:ok, user} + end end - def deactivated_user_query(query \\ User) do - from( - u in query, - where: fragment("(?->'deactivated' @> 'true')", u.info), - where: not is_nil(u.nickname) - ) - end + def update_notification_settings(%User{} = user, settings \\ %{}) do + info_changeset = User.Info.update_notification_settings(user.info, settings) - def active_local_user_query do - from( - u in local_user_query(), - where: fragment("not (?->'deactivated' @> 'true')", u.info) - ) + change(user) + |> put_embed(:info, info_changeset) + |> update_and_set_cache() end - def moderator_user_query do - from( - u in User, - where: u.local == true, - where: fragment("?->'is_moderator' @> 'true'", u.info) - ) - end + @spec delete(User.t()) :: :ok + def delete(%User{} = user), + do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user]) - def deactivate(%User{} = user, status \\ true) do - info_cng = User.Info.set_activation_status(user.info, status) - - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) - end - - def delete(%User{} = user) do + @spec perform(atom(), User.t()) :: {:ok, User.t()} + def perform(:delete, %User{} = user) do {:ok, user} = User.deactivate(user) # Remove all relationships {:ok, followers} = User.get_followers(user) - followers - |> Enum.each(fn follower -> User.unfollow(follower, user) end) + Enum.each(followers, fn follower -> User.unfollow(follower, user) end) {:ok, friends} = User.get_friends(user) - friends - |> Enum.each(fn followed -> User.unfollow(user, followed) end) + Enum.each(friends, fn followed -> User.unfollow(user, followed) end) - query = - from(a in Activity, where: a.actor == ^user.ap_id) + delete_user_activities(user) + end + + def delete_user_activities(%User{ap_id: ap_id} = user) do + stream = + ap_id + |> Activity.query_by_actor() |> Activity.with_preloaded_object() + |> Repo.stream() - Repo.all(query) - |> Enum.each(fn activity -> - case activity.data["type"] do - "Create" -> - ActivityPub.delete(Object.normalize(activity)) - - # TODO: Do something with likes, follows, repeats. - _ -> - "Doing nothing" - end - end) + Repo.transaction(fn -> Enum.each(stream, &delete_activity(&1)) end, timeout: :infinity) {:ok, user} end + defp delete_activity(%{data: %{"type" => "Create"}} = activity) do + Object.normalize(activity) |> ActivityPub.delete() + end + + defp delete_activity(_activity), do: "Doing nothing" + def html_filter_policy(%User{info: %{no_rich_text: true}}) do Pleroma.HTML.Scrubber.TwitterText end @@ -1136,41 +1135,41 @@ defmodule Pleroma.User do case ap_try do {:ok, user} -> - user + {:ok, user} _ -> case OStatus.make_user(ap_id) do - {:ok, user} -> user + {:ok, user} -> {:ok, 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) + user = get_cached_by_ap_id(ap_id) if !is_nil(user) and !User.needs_update?(user) do - user + {:ok, user} else # Whether to fetch initial posts for the user (if it's a new user & the fetching is enabled) should_fetch_initial = is_nil(user) and Pleroma.Config.get([:fetch_initial_posts, :enabled]) - user = fetch_by_ap_id(ap_id) + resp = fetch_by_ap_id(ap_id) if should_fetch_initial do - with %User{} = user do + with {:ok, %User{} = user} = resp do {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) end end - user + resp end end def get_or_create_instance_user do relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay" - if user = get_by_ap_id(relay_uri) do + if user = get_cached_by_ap_id(relay_uri) do user else changes = @@ -1205,7 +1204,7 @@ defmodule Pleroma.User do end def get_public_key_for_ap_id(ap_id) do - with %User{} = user <- get_or_fetch_by_ap_id(ap_id), + with {:ok, %User{} = user} <- get_or_fetch_by_ap_id(ap_id), {:ok, public_key} <- public_key_from_info(user.info) do {:ok, public_key} else @@ -1217,13 +1216,11 @@ defmodule Pleroma.User do defp blank?(n), do: n def insert_or_update_user(data) do - data = - data - |> Map.put(:name, blank?(data[:name]) || data[:nickname]) - - cs = User.remote_user_creation(data) - - Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname) + data + |> Map.put(:name, blank?(data[:name]) || data[:nickname]) + |> remote_user_creation() + |> Repo.insert(on_conflict: :replace_all, conflict_target: :nickname) + |> set_cache() end def ap_enabled?(%User{local: true}), do: true @@ -1231,7 +1228,7 @@ defmodule Pleroma.User do def ap_enabled?(_), do: false @doc "Gets or fetch a user by uri or nickname." - @spec get_or_fetch(String.t()) :: User.t() + @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()} def get_or_fetch("http" <> _host = uri), do: get_or_fetch_by_ap_id(uri) def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname) @@ -1239,8 +1236,8 @@ defmodule Pleroma.User do # this is because we have synchronous follow APIs and need to simulate them # with an async handshake def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do - with %User{} = a <- User.get_by_id(a.id), - %User{} = b <- User.get_by_id(b.id) do + with %User{} = a <- User.get_cached_by_id(a.id), + %User{} = b <- User.get_cached_by_id(b.id) do {:ok, a, b} else _e -> @@ -1250,8 +1247,8 @@ defmodule Pleroma.User do def wait_and_refresh(timeout, %User{} = a, %User{} = b) do with :ok <- :timer.sleep(timeout), - %User{} = a <- User.get_by_id(a.id), - %User{} = b <- User.get_by_id(b.id) do + %User{} = a <- User.get_cached_by_id(a.id), + %User{} = b <- User.get_cached_by_id(b.id) do {:ok, a, b} else _e -> @@ -1259,18 +1256,15 @@ defmodule Pleroma.User do end end - def parse_bio(bio, user \\ %User{info: %{source_data: %{}}}) - def parse_bio(nil, _user), do: "" - def parse_bio(bio, _user) when bio == "", do: bio + def parse_bio(bio) when is_binary(bio) and bio != "" do + bio + |> CommonUtils.format_input("text/plain", mentions_format: :full) + |> elem(0) + end - def parse_bio(bio, user) do - emoji = - (user.info.source_data["tag"] || []) - |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) - |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> - {String.trim(name, ":"), url} - end) + def parse_bio(_), do: "" + def parse_bio(bio, user) when is_binary(bio) and bio != "" do # TODO: get profile URLs other than user.ap_id profile_urls = [user.ap_id] @@ -1280,9 +1274,10 @@ defmodule Pleroma.User do rel: &RelMe.maybe_put_rel_me(&1, profile_urls) ) |> elem(0) - |> Formatter.emojify(emoji) end + def parse_bio(_, _), do: "" + def tag(user_identifiers, tags) when is_list(user_identifiers) do Repo.transaction(fn -> for user_identifier <- user_identifiers, do: tag(user_identifier, tags) @@ -1290,7 +1285,7 @@ defmodule Pleroma.User do end def tag(nickname, tags) when is_binary(nickname), - do: tag(User.get_by_nickname(nickname), tags) + do: tag(get_by_nickname(nickname), tags) def tag(%User{} = user, tags), do: update_tags(user, Enum.uniq((user.tags || []) ++ normalize_tags(tags))) @@ -1302,7 +1297,7 @@ defmodule Pleroma.User do end def untag(nickname, tags) when is_binary(nickname), - do: untag(User.get_by_nickname(nickname), tags) + do: untag(get_by_nickname(nickname), tags) def untag(%User{} = user, tags), do: update_tags(user, (user.tags || []) -- normalize_tags(tags)) @@ -1316,22 +1311,6 @@ defmodule Pleroma.User do updated_user end - def bookmark(%User{} = user, status_id) do - bookmarks = Enum.uniq(user.bookmarks ++ [status_id]) - update_bookmarks(user, bookmarks) - end - - def unbookmark(%User{} = user, status_id) do - bookmarks = Enum.uniq(user.bookmarks -- [status_id]) - update_bookmarks(user, bookmarks) - end - - def update_bookmarks(%User{} = user, bookmarks) do - user - |> change(%{bookmarks: bookmarks}) - |> update_and_set_cache - end - defp normalize_tags(tags) do [tags] |> List.flatten() @@ -1366,22 +1345,12 @@ defmodule Pleroma.User do } end + @spec all_superusers() :: [User.t()] 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) - ) + User.Query.build(%{super_users: true, local: true, deactivated: false}) |> Repo.all() end - defp paginate(query, page, page_size) do - from(u in query, - limit: ^page_size, - offset: ^((page - 1) * page_size) - ) - end - def showing_reblogs?(%User{} = user, %User{} = target) do target.ap_id not in user.info.muted_reblogs end