field(:raw_fields, {:array, :map}, default: [])
field(:discoverable, :boolean, default: false)
field(:invisible, :boolean, default: false)
+ field(:allow_following_move, :boolean, default: true)
field(:skip_thread_containment, :boolean, default: false)
+ field(:actor_type, :string, default: "Person")
+ field(:also_known_as, {:array, :string}, default: [])
- field(:notification_settings, :map,
- default: %{
- "followers" => true,
- "follows" => true,
- "non_follows" => true,
- "non_followers" => true
- }
+ embeds_one(
+ :notification_settings,
+ Pleroma.User.NotificationSetting,
+ on_replace: :update
)
has_many(:notifications, Notification)
has_many(incoming_relation_source, through: [incoming_relation, :source])
end
- field(:info, :map, default: %{})
-
# `:blocks` is deprecated (replaced with `blocked_users` relation)
field(:blocks, {:array, :string}, default: [])
# `:mutes` is deprecated (replaced with `muted_users` relation)
def ap_following(%User{following_address: fa}) when is_binary(fa), do: fa
def ap_following(%User{} = user), do: "#{ap_id(user)}/following"
- def user_info(%User{} = user, args \\ %{}) do
- following_count = Map.get(args, :following_count, user.following_count)
- follower_count = Map.get(args, :follower_count, user.follower_count)
-
- %{
- note_count: user.note_count,
- locked: user.locked,
- confirmation_pending: user.confirmation_pending,
- default_scope: user.default_scope,
- follower_count: follower_count,
- following_count: following_count
- }
- end
-
def follow_state(%User{} = user, %User{} = target) do
case Utils.fetch_latest_follow(user, target) do
%{data: %{"state" => state}} -> state
Cachex.put(:user_cache, "follow_state:#{user_ap_id}|#{target_ap_id}", state)
end
- def set_info_cache(user, args) do
- Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user, args))
- end
-
@spec restrict_deactivated(Ecto.Query.t()) :: Ecto.Query.t()
def restrict_deactivated(query) do
from(u in query, where: u.deactivated != ^true)
params =
params
- |> Map.put(:info, params[:info] || %{})
|> truncate_if_exists(:name, name_limit)
|> truncate_if_exists(:bio, bio_limit)
|> truncate_fields_param()
:fields,
:following_count,
:discoverable,
- :invisible
+ :invisible,
+ :actor_type,
+ :also_known_as
]
)
|> validate_required([:name, :ap_id])
:hide_followers_count,
:hide_follows_count,
:hide_favorites,
+ :allow_following_move,
:background,
:show_role,
:skip_thread_containment,
:fields,
:raw_fields,
:pleroma_settings_store,
- :discoverable
+ :discoverable,
+ :actor_type,
+ :also_known_as
]
)
|> unique_constraint(:nickname)
:hide_follows,
:fields,
:hide_followers,
+ :allow_following_move,
:discoverable,
:hide_followers_count,
- :hide_follows_count
+ :hide_follows_count,
+ :actor_type,
+ :also_known_as
]
)
|> unique_constraint(:nickname)
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))
{:ok, user}
end
def invalidate_cache(user) do
Cachex.del(:user_cache, "ap_id:#{user.ap_id}")
Cachex.del(:user_cache, "nickname:#{user.nickname}")
- Cachex.del(:user_cache, "user_info:#{user.id}")
end
def get_cached_by_ap_id(ap_id) do
get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email)
end
- def get_cached_user_info(user) do
- key = "user_info:#{user.id}"
- Cachex.fetch!(:user_cache, key, fn -> user_info(user) end)
- end
-
def fetch_by_nickname(nickname), do: ActivityPub.make_user_from_nickname(nickname)
def get_or_fetch_by_nickname(nickname) do
|> Repo.all()
end
+ def get_friends_ap_ids(user) do
+ user
+ |> get_friends_query(nil)
+ |> select([u], u.ap_id)
+ |> Repo.all()
+ end
+
def get_friends_ids(user, page \\ nil) do
user
|> get_friends_query(page)
def blocks?(nil, _), do: false
def blocks?(%User{} = user, %User{} = target) do
- blocks_user?(user, target) || blocks_domain?(user, target)
+ blocks_user?(user, target) ||
+ (!User.following?(user, target) && blocks_domain?(user, target))
end
def blocks_user?(%User{} = user, %User{} = target) do
end
def update_notification_settings(%User{} = user, settings) do
- settings =
- settings
- |> Enum.map(fn {k, v} -> {k, v in [true, "true", "True", "1"]} end)
- |> Map.new()
-
- notification_settings =
- user.notification_settings
- |> Map.merge(settings)
- |> Map.take(["followers", "follows", "non_follows", "non_followers"])
-
- params = %{notification_settings: notification_settings}
-
user
- |> cast(params, [:notification_settings])
+ |> cast(%{notification_settings: settings}, [])
+ |> cast_embed(:notification_settings)
|> validate_required([:notification_settings])
|> update_and_set_cache()
end
def external_users(opts \\ []) do
query =
external_users_query()
- |> select([u], struct(u, [:id, :ap_id, :info]))
+ |> select([u], struct(u, [:id, :ap_id]))
query =
if opts[:max_id],
end
def admin_api_update(user, params) do
- user
- |> cast(params, [
- :is_moderator,
- :is_admin,
- :show_role
- ])
- |> update_and_set_cache()
+ changeset =
+ cast(user, params, [
+ :is_moderator,
+ :is_admin,
+ :show_role
+ ])
+
+ with {:ok, updated_user} <- update_and_set_cache(changeset) do
+ if user.is_admin && !updated_user.is_admin do
+ # Tokens & authorizations containing any admin scopes must be revoked (revoking all).
+ # This is an extra safety measure (tokens' admin scopes won't be accepted for non-admins).
+ global_sign_out(user)
+ end
+
+ {:ok, updated_user}
+ end
+ end
+
+ @doc "Signs user out of all applications"
+ def global_sign_out(user) do
+ OAuth.Authorization.delete_user_authorizations(user)
+ OAuth.Token.delete_user_tokens(user)
end
def mascot_update(user, url) do