import Ecto.Changeset
import Ecto.Query
+ alias Comeonin.Pbkdf2
+ alias Pleroma.Activity
+ alias Pleroma.Formatter
+ alias Pleroma.Notification
+ alias Pleroma.Object
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.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
+ alias Pleroma.Web.OAuth
alias Pleroma.Web.OStatus
+ alias Pleroma.Web.RelMe
alias Pleroma.Web.Websub
- alias Pleroma.Web.OAuth
- alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Web.ActivityPub.ActivityPub
require Logger
@primary_key {:id, Pleroma.FlakeId, autogenerate: true}
+ # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
@strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true
def needs_update?(%User{local: false} = user) do
- NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86400
+ NaiveDateTime.diff(NaiveDateTime.utc_now(), user.last_refreshed_at) >= 86_400
end
def needs_update?(_), do: true
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
Repo.get_by(User, ap_id: ap_id)
end
- # This is mostly an SPC migration fix. This guesses the user nickname (by taking the last part of the ap_id and the domain) and tries to get that user
+ # This is mostly an SPC migration fix. This guesses the user nickname by taking the last part
+ # of the ap_id and the domain and tries to get that user
def get_by_guessed_nickname(ap_id) do
domain = URI.parse(ap_id).host
name = List.last(String.split(ap_id, "/"))
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, error}
+ end
+ end)
end
def get_cached_by_nickname_or_id(nickname_or_id) 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
- user
+ if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
+ {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
+ end
+
+ {:ok, user}
else
- _e -> nil
+ e -> {:error, e}
end
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,
Repo.all(query)
end
- @spec search_for_admin(binary(), %{
+ @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(term, %{admin: admin, local: local, page: page, page_size: page_size}) do
+ 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 =
{:ok, do_search(search_query, admin), count}
end
- @spec all_for_admin(number(), number()) :: {:ok, [Pleroma.User.t()], number()}
- def all_for_admin(page, page_size) do
- query = from(u in User, order_by: u.id)
-
- paginated_query =
- query
- |> paginate(page, page_size)
-
- count =
- query
- |> Repo.aggregate(:count, :id)
-
- {:ok, Repo.all(paginated_query), 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, "@")
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
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
+ {:ok, user}
else
- ap_try = ActivityPub.make_user_from_ap_id(ap_id)
-
- case ap_try do
- {:ok, user} ->
- user
+ with %User{} = user <- fetch_by_ap_id(ap_id) do
+ if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do
+ {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user])
+ end
- _ ->
- case OStatus.make_user(ap_id) do
- {:ok, user} -> user
- _ -> {:error, "Could not fetch by AP id"}
- end
+ {:ok, user}
+ else
+ _ -> {:error, "Could not fetch by AP id"}
end
end
end
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
{String.trim(name, ":"), url}
end)
+ # TODO: get profile URLs other than user.ap_id
+ profile_urls = [user.ap_id]
+
bio
- |> CommonUtils.format_input("text/plain", mentions_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
|> Enum.map(&String.downcase(&1))
end
- defp local_nickname_regex() do
+ defp local_nickname_regex do
if Pleroma.Config.get([:instance, :extended_nickname_format]) do
@extended_local_nickname_regex
else