# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User do
timestamps()
end
- def auth_active?(%User{} = user) do
- (user.info && !user.info.confirmation_pending) ||
- !Pleroma.Config.get([:instance, :account_activation_required])
+ def auth_active?(%User{local: false}), do: true
+
+ def auth_active?(%User{info: %User.Info{confirmation_pending: false}}), do: true
+
+ def auth_active?(%User{info: %User.Info{confirmation_pending: true}}),
+ do: !Pleroma.Config.get([:instance, :account_activation_required])
+
+ def auth_active?(_), do: false
+
+ def visible_for?(user, for_user \\ nil)
+
+ def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true
+
+ def visible_for?(%User{} = user, for_user) do
+ auth_active?(user) || superuser?(for_user)
end
- def superuser?(%User{} = user), do: user.info && User.Info.superuser?(user.info)
+ def visible_for?(_, _), do: false
+
+ def superuser?(%User{local: true, info: %User.Info{is_admin: true}}), do: true
+ def superuser?(%User{local: true, info: %User.Info{is_moderator: true}}), do: true
+ def superuser?(_), do: false
def avatar_url(user) do
case user.avatar do
end
end
+ defp autofollow_users(user) do
+ candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames])
+
+ autofollowed_users =
+ from(u in User,
+ where: u.local == true,
+ where: u.nickname in ^candidates
+ )
+ |> Repo.all()
+
+ follow_all(user, autofollowed_users)
+ end
+
@doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)"
def register(%Ecto.Changeset{} = changeset) do
with {:ok, user} <- Repo.insert(changeset),
- {:ok, _} = try_send_confirmation_email(user) do
+ {:ok, _} <- try_send_confirmation_email(user),
+ {:ok, user} <- autofollow_users(user) do
{:ok, user}
end
end
end
end
+ @doc "A mass follow for local users. Ignores blocks and has no side effects"
+ @spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()}
+ def follow_all(follower, followeds) do
+ following =
+ (follower.following ++ Enum.map(followeds, fn %{follower_address: fa} -> fa end))
+ |> Enum.uniq()
+
+ {:ok, follower} =
+ follower
+ |> follow_changeset(%{following: following})
+ |> update_and_set_cache
+
+ Enum.each(followeds, fn followed ->
+ update_follower_count(followed)
+ end)
+
+ {:ok, follower}
+ end
+
def follow(%User{} = follower, %User{info: info} = followed) do
user_config = Application.get_env(:pleroma, :user)
deny_follow_blocked = Keyword.get(user_config, :deny_follow_blocked)
user.info.locked || false
end
+ def get_by_id(id) do
+ Repo.get_by(User, id: id)
+ end
+
def get_by_ap_id(ap_id) do
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
+ def get_by_guessed_nickname(ap_id) do
+ domain = URI.parse(ap_id).host
+ name = List.last(String.split(ap_id, "/"))
+ nickname = "#{name}@#{domain}"
+
+ get_by_nickname(nickname)
+ end
+
def update_and_set_cache(changeset) do
with {:ok, user} <- Repo.update(changeset) do
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
Cachex.fetch!(:user_cache, key, fn _ -> get_by_ap_id(ap_id) end)
end
+ def get_cached_by_id(id) do
+ key = "id:#{id}"
+
+ ap_id =
+ Cachex.fetch!(:user_cache, key, fn _ ->
+ user = get_by_id(id)
+ Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
+ {:commit, user.ap_id}
+ end)
+
+ get_cached_by_ap_id(ap_id)
+ end
+
def get_cached_by_nickname(nickname) do
key = "nickname:#{nickname}"
Cachex.fetch!(:user_cache, key, fn _ -> get_or_fetch_by_nickname(nickname) end)
end
+ def get_cached_by_nickname_or_id(nickname_or_id) do
+ get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id)
+ end
+
def get_by_nickname(nickname) do
- Repo.get_by(User, nickname: nickname)
+ Repo.get_by(User, nickname: nickname) ||
+ if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do
+ [local_nickname, _] = String.split(nickname, "@")
+ Repo.get_by(User, nickname: local_nickname)
+ end
end
def get_by_nickname_or_email(nickname_or_email) do
end
end
- def get_followers_query(%User{id: id, follower_address: follower_address}) do
+ def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do
from(
u in User,
where: fragment("? <@ ?", ^[follower_address], u.following),
)
end
- def get_followers(user) do
- q = get_followers_query(user)
+ def get_followers_query(user, page) do
+ from(
+ u in get_followers_query(user, nil),
+ limit: 20,
+ offset: ^((page - 1) * 20)
+ )
+ end
+
+ def get_followers_query(user), do: get_followers_query(user, nil)
+
+ def get_followers(user, page \\ nil) do
+ q = get_followers_query(user, page)
{:ok, Repo.all(q)}
end
- def get_friends_query(%User{id: id, following: following}) do
+ def get_friends_query(%User{id: id, following: following}, nil) do
from(
u in User,
where: u.follower_address in ^following,
)
end
- def get_friends(user) do
- q = get_friends_query(user)
+ def get_friends_query(user, page) do
+ from(
+ u in get_friends_query(user, nil),
+ limit: 20,
+ offset: ^((page - 1) * 20)
+ )
+ end
+
+ def get_friends_query(user), do: get_friends_query(user, nil)
+
+ def get_friends(user, page \\ nil) do
+ q = get_friends_query(user, page)
{:ok, Repo.all(q)}
end
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}
select_merge: %{
search_distance:
fragment(
- "? <-> (? || ?)",
+ "? <-> (? || coalesce(?, ''))",
^query,
u.nickname,
u.name
Pleroma.HTML.Scrubber.TwitterText
end
- def html_filter_policy(_), do: nil
+ @default_scrubbers Pleroma.Config.get([:markup, :scrub_policy])
+
+ def html_filter_policy(_), do: @default_scrubbers
def get_or_fetch_by_ap_id(ap_id) do
user = get_by_ap_id(ap_id)