[#1304] Moved remaining fields from User.Info to User.

Misc. fixes / improvements.
This commit is contained in:
Ivan Tashkinov 2019-10-20 13:42:42 +03:00
parent 10ff01acd9
commit e8843974cb
14 changed files with 355 additions and 205 deletions

View file

@ -160,7 +160,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
- Params: none - Params: none
- Response: - Response:
- On failure: `{"error": "…"}` - On failure: `{"error": "…"}`
- On success: JSON of the `user.info` - On success: JSON of the user
### Remove user from permission group ### Remove user from permission group
@ -168,7 +168,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
- Params: none - Params: none
- Response: - Response:
- On failure: `{"error": "…"}` - On failure: `{"error": "…"}`
- On success: JSON of the `user.info` - On success: JSON of the user
- Note: An admin cannot revoke their own admin status. - Note: An admin cannot revoke their own admin status.
## `/api/pleroma/admin/users/:nickname/activation_status` ## `/api/pleroma/admin/users/:nickname/activation_status`

View file

@ -5,6 +5,7 @@
defmodule Mix.Tasks.Pleroma.User do defmodule Mix.Tasks.Pleroma.User do
use Mix.Task use Mix.Task
import Mix.Pleroma import Mix.Pleroma
alias Ecto.Changeset
alias Pleroma.User alias Pleroma.User
alias Pleroma.UserInviteToken alias Pleroma.UserInviteToken
alias Pleroma.Web.OAuth alias Pleroma.Web.OAuth
@ -364,21 +365,30 @@ def run(["sign_out", nickname]) do
end end
defp set_moderator(user, value) do defp set_moderator(user, value) do
{:ok, user} = User.update_and_set_cache(user, %{is_moderator: value}) {:ok, user} =
user
|> Changeset.change(%{is_moderator: value})
|> User.update_and_set_cache()
shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}") shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}")
user user
end end
defp set_admin(user, value) do defp set_admin(user, value) do
{:ok, user} = User.update_and_set_cache(user, %{is_admin: value}) {:ok, user} =
user
|> Changeset.change(%{is_admin: value})
|> User.update_and_set_cache()
shell_info("Admin status of #{user.nickname}: #{user.is_admin}") shell_info("Admin status of #{user.nickname}: #{user.is_admin}")
user user
end end
defp set_locked(user, value) do defp set_locked(user, value) do
{:ok, user} = User.update_and_set_cache(user, %{locked: value}) {:ok, user} =
user
|> Changeset.change(%{locked: value})
|> User.update_and_set_cache()
shell_info("Locked status of #{user.nickname}: #{user.locked}") shell_info("Locked status of #{user.nickname}: #{user.locked}")
user user

View file

@ -58,11 +58,11 @@ def for_user_query(user, opts \\ []) do
if opts[:with_muted] do if opts[:with_muted] do
query query
else else
where(query, [n, a], a.actor not in ^user.info.muted_notifications) where(query, [n, a], a.actor not in ^user.muted_notifications)
|> where([n, a], a.actor not in ^user.info.blocks) |> where([n, a], a.actor not in ^user.blocks)
|> where( |> where(
[n, a], [n, a],
fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.domain_blocks
) )
|> join(:left, [n, a], tm in Pleroma.ThreadMute, |> join(:left, [n, a], tm in Pleroma.ThreadMute,
on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data)

View file

@ -122,7 +122,8 @@ defmodule Pleroma.User do
has_many(:notifications, Notification) has_many(:notifications, Notification)
has_many(:registrations, Registration) has_many(:registrations, Registration)
has_many(:deliveries, Delivery) has_many(:deliveries, Delivery)
embeds_one(:info, User.Info)
field(:info, :map, default: %{})
timestamps() timestamps()
end end
@ -304,14 +305,39 @@ def remote_user_creation(params) do
changeset = changeset =
%User{local: false} %User{local: false}
|> cast(params, [:bio, :name, :ap_id, :nickname, :avatar] ++ @info_fields) |> cast(
params,
[
:bio,
:name,
:ap_id,
:nickname,
:avatar,
:ap_enabled,
:source_data,
:banner,
:locked,
:magic_key,
:uri,
:hub,
:topic,
:salmon,
:hide_followers,
:hide_follows,
:hide_followers_count,
:hide_follows_count,
:follower_count,
:fields,
:following_count,
:discoverable
]
)
|> validate_required([:name, :ap_id]) |> validate_required([:name, :ap_id])
|> unique_constraint(:nickname) |> unique_constraint(:nickname)
|> validate_format(:nickname, @email_regex) |> validate_format(:nickname, @email_regex)
|> validate_length(:bio, max: bio_limit) |> validate_length(:bio, max: bio_limit)
|> validate_length(:name, max: name_limit) |> validate_length(:name, max: name_limit)
|> validate_fields(true) |> validate_fields(true)
|> change_info(& &1)
case params[:source_data] do case params[:source_data] do
%{"followers" => followers, "following" => following} -> %{"followers" => followers, "following" => following} ->
@ -330,7 +356,31 @@ def update_changeset(struct, params \\ %{}) do
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
struct struct
|> cast(params, [:bio, :name, :avatar, :following] ++ @info_fields) |> cast(
params,
[
:bio,
:name,
:avatar,
:following,
:locked,
:no_rich_text,
:default_scope,
:banner,
:hide_follows,
:hide_followers,
:hide_followers_count,
:hide_follows_count,
:hide_favorites,
:background,
:show_role,
:skip_thread_containment,
:fields,
:raw_fields,
:pleroma_settings_store,
:discoverable
]
)
|> unique_constraint(:nickname) |> unique_constraint(:nickname)
|> validate_format(:nickname, local_nickname_regex()) |> validate_format(:nickname, local_nickname_regex())
|> validate_length(:bio, max: bio_limit) |> validate_length(:bio, max: bio_limit)
@ -355,15 +405,27 @@ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do
:follower_address, :follower_address,
:following_address, :following_address,
:avatar, :avatar,
:last_refreshed_at :last_refreshed_at,
] ++ @info_fields :ap_enabled,
:source_data,
:banner,
:locked,
:magic_key,
:follower_count,
:following_count,
:hide_follows,
:fields,
:hide_followers,
:discoverable,
:hide_followers_count,
:hide_follows_count
]
) )
|> unique_constraint(:nickname) |> unique_constraint(:nickname)
|> validate_format(:nickname, local_nickname_regex()) |> validate_format(:nickname, local_nickname_regex())
|> validate_length(:bio, max: bio_limit) |> validate_length(:bio, max: bio_limit)
|> validate_length(:name, max: name_limit) |> validate_length(:name, max: name_limit)
|> validate_fields(remote?) |> validate_fields(remote?)
|> change_info(& &1)
end end
def password_update_changeset(struct, params) do def password_update_changeset(struct, params) do
@ -426,7 +488,6 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do
|> validate_format(:email, @email_regex) |> validate_format(:email, @email_regex)
|> validate_length(:bio, max: bio_limit) |> validate_length(:bio, max: bio_limit)
|> validate_length(:name, min: 1, max: name_limit) |> validate_length(:name, min: 1, max: name_limit)
|> change_info(& &1)
|> maybe_validate_required_email(opts[:external]) |> maybe_validate_required_email(opts[:external])
|> put_password_hash |> put_password_hash
|> put_ap_id() |> put_ap_id()
@ -884,7 +945,9 @@ def update_note_count(%User{} = user, note_count \\ nil) do
) )
|> Repo.one() |> Repo.one()
update_and_set_cache(user, %{note_count: note_count}) user
|> cast(%{note_count: note_count}, [:note_count])
|> update_and_set_cache()
end end
@spec maybe_fetch_follow_information(User.t()) :: User.t() @spec maybe_fetch_follow_information(User.t()) :: User.t()
@ -1023,11 +1086,11 @@ def get_recipients_from_activity(%Activity{recipients: to}) do
@spec mute(User.t(), User.t(), boolean()) :: {:ok, User.t()} | {:error, String.t()} @spec mute(User.t(), User.t(), boolean()) :: {:ok, User.t()} | {:error, String.t()}
def mute(muter, %User{ap_id: ap_id}, notifications? \\ true) do def mute(muter, %User{ap_id: ap_id}, notifications? \\ true) do
update_info(muter, &User.Info.add_to_mutes(&1, ap_id, notifications?)) add_to_mutes(muter, ap_id, notifications?)
end end
def unmute(muter, %{ap_id: ap_id}) do def unmute(muter, %{ap_id: ap_id}) do
update_info(muter, &User.Info.remove_from_mutes(&1, ap_id)) remove_from_mutes(muter, ap_id)
end end
def subscribe(subscriber, %{ap_id: ap_id}) do def subscribe(subscriber, %{ap_id: ap_id}) do
@ -1077,7 +1140,7 @@ def block(blocker, %User{ap_id: ap_id} = blocked) do
{:ok, blocker} = update_follower_count(blocker) {:ok, blocker} = update_follower_count(blocker)
update_info(blocker, &User.Info.add_to_block(&1, ap_id)) add_to_block(blocker, ap_id)
end end
# helper to handle the block given only an actor's AP id # helper to handle the block given only an actor's AP id
@ -1086,17 +1149,17 @@ def block(blocker, %{ap_id: ap_id}) do
end end
def unblock(blocker, %{ap_id: ap_id}) do def unblock(blocker, %{ap_id: ap_id}) do
update_info(blocker, &User.Info.remove_from_block(&1, ap_id)) remove_from_block(blocker, ap_id)
end end
def mutes?(nil, _), do: false def mutes?(nil, _), do: false
def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.info.mutes, ap_id) def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.mutes, ap_id)
@spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean() @spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean()
def muted_notifications?(nil, _), do: false def muted_notifications?(nil, _), do: false
def muted_notifications?(user, %{ap_id: ap_id}), def muted_notifications?(user, %{ap_id: ap_id}),
do: Enum.member?(user.info.muted_notifications, ap_id) do: Enum.member?(user.muted_notifications, ap_id)
def blocks?(%User{} = user, %User{} = target) do def blocks?(%User{} = user, %User{} = target) do
blocks_ap_id?(user, target) || blocks_domain?(user, target) blocks_ap_id?(user, target) || blocks_domain?(user, target)
@ -1105,13 +1168,13 @@ def blocks?(%User{} = user, %User{} = target) do
def blocks?(nil, _), do: false def blocks?(nil, _), do: false
def blocks_ap_id?(%User{} = user, %User{} = target) do def blocks_ap_id?(%User{} = user, %User{} = target) do
Enum.member?(user.info.blocks, target.ap_id) Enum.member?(user.blocks, target.ap_id)
end end
def blocks_ap_id?(_, _), do: false def blocks_ap_id?(_, _), do: false
def blocks_domain?(%User{} = user, %User{} = target) do def blocks_domain?(%User{} = user, %User{} = target) do
domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks)
%{host: host} = URI.parse(target.ap_id) %{host: host} = URI.parse(target.ap_id)
Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host)
end end
@ -1126,13 +1189,13 @@ def subscribed_to?(user, %{ap_id: ap_id}) do
@spec muted_users(User.t()) :: [User.t()] @spec muted_users(User.t()) :: [User.t()]
def muted_users(user) do def muted_users(user) do
User.Query.build(%{ap_id: user.info.mutes, deactivated: false}) User.Query.build(%{ap_id: user.mutes, deactivated: false})
|> Repo.all() |> Repo.all()
end end
@spec blocked_users(User.t()) :: [User.t()] @spec blocked_users(User.t()) :: [User.t()]
def blocked_users(user) do def blocked_users(user) do
User.Query.build(%{ap_id: user.info.blocks, deactivated: false}) User.Query.build(%{ap_id: user.blocks, deactivated: false})
|> Repo.all() |> Repo.all()
end end
@ -1142,14 +1205,6 @@ def subscribers(user) do
|> Repo.all() |> Repo.all()
end end
def block_domain(user, domain) do
update_info(user, &User.Info.add_to_domain_block(&1, domain))
end
def unblock_domain(user, domain) do
update_info(user, &User.Info.remove_from_domain_block(&1, domain))
end
def deactivate_async(user, status \\ true) do def deactivate_async(user, status \\ true) do
BackgroundWorker.enqueue("deactivate_user", %{"user_id" => user.id, "status" => status}) BackgroundWorker.enqueue("deactivate_user", %{"user_id" => user.id, "status" => status})
end end
@ -1385,7 +1440,7 @@ def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do
else else
_ -> _ ->
{:ok, user} = {:ok, user} =
%User{info: %User.Info{}} %User{}
|> cast(%{}, [:ap_id, :nickname, :local]) |> cast(%{}, [:ap_id, :nickname, :local])
|> put_change(:ap_id, uri) |> put_change(:ap_id, uri)
|> put_change(:nickname, nickname) |> put_change(:nickname, nickname)
@ -1549,7 +1604,6 @@ def error_user(ap_id) do
%User{ %User{
name: ap_id, name: ap_id,
ap_id: ap_id, ap_id: ap_id,
info: %User.Info{},
nickname: "erroruser@example.com", nickname: "erroruser@example.com",
inserted_at: NaiveDateTime.utc_now() inserted_at: NaiveDateTime.utc_now()
} }
@ -1562,7 +1616,7 @@ def all_superusers do
end end
def showing_reblogs?(%User{} = user, %User{} = target) do def showing_reblogs?(%User{} = user, %User{} = target) do
target.ap_id not in user.info.muted_reblogs target.ap_id not in user.muted_reblogs
end end
@doc """ @doc """
@ -1741,28 +1795,6 @@ def update_source_data(user, source_data) do
|> update_and_set_cache() |> update_and_set_cache()
end end
@doc """
Changes `user.info` and returns the user changeset.
`fun` is called with the `user.info`.
"""
def change_info(user, fun) do
changeset = change(user)
info = get_field(changeset, :info) || %User.Info{}
put_embed(changeset, :info, fun.(info))
end
@doc """
Updates `user.info` and sets cache.
`fun` is called with the `user.info`.
"""
def update_info(user, fun) do
user
|> change_info(fun)
|> update_and_set_cache()
end
def roles(%{is_moderator: is_moderator, is_admin: is_admin}) do def roles(%{is_moderator: is_moderator, is_admin: is_admin}) do
%{ %{
admin: is_admin, admin: is_admin,
@ -1918,4 +1950,96 @@ def add_to_subscribers(user, subscribed) do
def remove_from_subscribers(user, subscribed) do def remove_from_subscribers(user, subscribed) do
set_subscribers(user, List.delete(user.subscribers, subscribed)) set_subscribers(user, List.delete(user.subscribers, subscribed))
end end
defp set_domain_blocks(user, domain_blocks) do
params = %{domain_blocks: domain_blocks}
user
|> cast(params, [:domain_blocks])
|> validate_required([:domain_blocks])
|> update_and_set_cache()
end
def block_domain(user, domain_blocked) do
set_domain_blocks(user, Enum.uniq([domain_blocked | user.domain_blocks]))
end
def unblock_domain(user, domain_blocked) do
set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked))
end
defp set_blocks(user, blocks) do
params = %{blocks: blocks}
user
|> cast(params, [:blocks])
|> validate_required([:blocks])
|> update_and_set_cache()
end
def add_to_block(user, blocked) do
set_blocks(user, Enum.uniq([blocked | user.blocks]))
end
def remove_from_block(user, blocked) do
set_blocks(user, List.delete(user.blocks, blocked))
end
defp set_mutes(user, mutes) do
params = %{mutes: mutes}
user
|> cast(params, [:mutes])
|> validate_required([:mutes])
|> update_and_set_cache()
end
def add_to_mutes(user, muted, notifications?) do
with {:ok, user} <- set_mutes(user, Enum.uniq([muted | user.mutes])) do
set_notification_mutes(
user,
Enum.uniq([muted | user.muted_notifications]),
notifications?
)
end
end
def remove_from_mutes(user, muted) do
with {:ok, user} <- set_mutes(user, List.delete(user.mutes, muted)) do
set_notification_mutes(
user,
List.delete(user.muted_notifications, muted),
true
)
end
end
defp set_notification_mutes(user, _muted_notifications, _notifications? = false) do
{:ok, user}
end
defp set_notification_mutes(user, muted_notifications, _notifications? = true) do
params = %{muted_notifications: muted_notifications}
user
|> cast(params, [:muted_notifications])
|> validate_required([:muted_notifications])
|> update_and_set_cache()
end
def add_reblog_mute(user, ap_id) do
params = %{muted_reblogs: user.muted_reblogs ++ [ap_id]}
user
|> cast(params, [:muted_reblogs])
|> update_and_set_cache()
end
def remove_reblog_mute(user, ap_id) do
params = %{muted_reblogs: List.delete(user.muted_reblogs, ap_id)}
user
|> cast(params, [:muted_reblogs])
|> update_and_set_cache()
end
end end

View file

@ -1,107 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.Info do
use Ecto.Schema
import Ecto.Changeset
alias Pleroma.User.Info
@type t :: %__MODULE__{}
embedded_schema do
field(:blocks, {:array, :string}, default: [])
field(:domain_blocks, {:array, :string}, default: [])
field(:mutes, {:array, :string}, default: [])
field(:muted_reblogs, {:array, :string}, default: [])
field(:muted_notifications, {:array, :string}, default: [])
# Found in the wild
# ap_id -> Where is this used?
# bio -> Where is this used?
# avatar -> Where is this used?
# fqn -> Where is this used?
# host -> Where is this used?
# subject _> Where is this used?
end
def set_mutes(info, mutes) do
params = %{mutes: mutes}
info
|> cast(params, [:mutes])
|> validate_required([:mutes])
end
@spec set_notification_mutes(Changeset.t(), [String.t()], boolean()) :: Changeset.t()
def set_notification_mutes(changeset, muted_notifications, notifications?) do
if notifications? do
put_change(changeset, :muted_notifications, muted_notifications)
|> validate_required([:muted_notifications])
else
changeset
end
end
def set_blocks(info, blocks) do
params = %{blocks: blocks}
info
|> cast(params, [:blocks])
|> validate_required([:blocks])
end
@spec add_to_mutes(Info.t(), String.t(), boolean()) :: Changeset.t()
def add_to_mutes(info, muted, notifications?) do
info
|> set_mutes(Enum.uniq([muted | info.mutes]))
|> set_notification_mutes(
Enum.uniq([muted | info.muted_notifications]),
notifications?
)
end
@spec remove_from_mutes(Info.t(), String.t()) :: Changeset.t()
def remove_from_mutes(info, muted) do
info
|> set_mutes(List.delete(info.mutes, muted))
|> set_notification_mutes(List.delete(info.muted_notifications, muted), true)
end
def add_to_block(info, blocked) do
set_blocks(info, Enum.uniq([blocked | info.blocks]))
end
def remove_from_block(info, blocked) do
set_blocks(info, List.delete(info.blocks, blocked))
end
def set_domain_blocks(info, domain_blocks) do
params = %{domain_blocks: domain_blocks}
info
|> cast(params, [:domain_blocks])
|> validate_required([:domain_blocks])
end
def add_to_domain_block(info, domain_blocked) do
set_domain_blocks(info, Enum.uniq([domain_blocked | info.domain_blocks]))
end
def remove_from_domain_block(info, domain_blocked) do
set_domain_blocks(info, List.delete(info.domain_blocks, domain_blocked))
end
def add_reblog_mute(info, ap_id) do
params = %{muted_reblogs: info.muted_reblogs ++ [ap_id]}
cast(info, params, [:muted_reblogs])
end
def remove_reblog_mute(info, ap_id) do
params = %{muted_reblogs: List.delete(info.muted_reblogs, ap_id)}
cast(info, params, [:muted_reblogs])
end
end

View file

@ -68,14 +68,14 @@ defp search_query(query_string, for_user, following) do
defp base_query(_user, false), do: User defp base_query(_user, false), do: User
defp base_query(user, true), do: User.get_followers_query(user) defp base_query(user, true), do: User.get_followers_query(user)
defp filter_blocked_user(query, %User{info: %{blocks: blocks}}) defp filter_blocked_user(query, %User{blocks: blocks})
when length(blocks) > 0 do when length(blocks) > 0 do
from(q in query, where: not (q.ap_id in ^blocks)) from(q in query, where: not (q.ap_id in ^blocks))
end end
defp filter_blocked_user(query, _), do: query defp filter_blocked_user(query, _), do: query
defp filter_blocked_domains(query, %User{info: %{domain_blocks: domain_blocks}}) defp filter_blocked_domains(query, %User{domain_blocks: domain_blocks})
when length(domain_blocks) > 0 do when length(domain_blocks) > 0 do
domains = Enum.join(domain_blocks, ",") domains = Enum.join(domain_blocks, ",")

View file

@ -235,8 +235,6 @@ def create(%{to: to, actor: actor, context: context, object: object} = params, f
{:fake, false, activity} <- {:fake, fake, activity}, {:fake, false, activity} <- {:fake, fake, activity},
_ <- increase_replies_count_if_reply(create_data), _ <- increase_replies_count_if_reply(create_data),
_ <- increase_poll_votes_if_vote(create_data), _ <- increase_poll_votes_if_vote(create_data),
# Changing note count prior to enqueuing federation task in order to avoid
# race conditions on updating user.info
{:ok, _actor} <- increase_note_count_if_public(actor, activity), {:ok, _actor} <- increase_note_count_if_public(actor, activity),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity} {:ok, activity}
@ -429,8 +427,6 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, options \\ [
{:ok, activity} <- insert(data, local, false), {:ok, activity} <- insert(data, local, false),
stream_out_participations(object, user), stream_out_participations(object, user),
_ <- decrease_replies_count_if_reply(object), _ <- decrease_replies_count_if_reply(object),
# Changing note count prior to enqueuing federation task in order to avoid
# race conditions on updating user.info
{:ok, _actor} <- decrease_note_count_if_public(user, object), {:ok, _actor} <- decrease_note_count_if_public(user, object),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity} {:ok, activity}
@ -800,8 +796,8 @@ defp restrict_reblogs(query, _), do: query
defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query
defp restrict_muted(query, %{"muting_user" => %User{info: info}} = opts) do defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do
mutes = info.mutes mutes = user.mutes
query = query =
from([activity] in query, from([activity] in query,
@ -818,9 +814,9 @@ defp restrict_muted(query, %{"muting_user" => %User{info: info}} = opts) do
defp restrict_muted(query, _), do: query defp restrict_muted(query, _), do: query
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do
blocks = info.blocks || [] blocks = user.blocks || []
domain_blocks = info.domain_blocks || [] domain_blocks = user.domain_blocks || []
query = query =
if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query) if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query)
@ -861,8 +857,8 @@ defp restrict_pinned(query, %{"pinned" => "true", "pinned_activity_ids" => ids})
defp restrict_pinned(query, _), do: query defp restrict_pinned(query, _), do: query
defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user}) do
muted_reblogs = info.muted_reblogs || [] muted_reblogs = user.muted_reblogs || []
from( from(
activity in query, activity in query,

View file

@ -392,14 +392,14 @@ defp set_visibility(activity, %{"visibility" => visibility}) do
defp set_visibility(activity, _), do: {:ok, activity} defp set_visibility(activity, _), do: {:ok, activity}
def hide_reblogs(user, %{ap_id: ap_id} = _muted) do def hide_reblogs(user, %{ap_id: ap_id} = _muted) do
if ap_id not in user.info.muted_reblogs do if ap_id not in user.muted_reblogs do
User.update_info(user, &User.Info.add_reblog_mute(&1, ap_id)) User.add_reblog_mute(user, ap_id)
end end
end end
def show_reblogs(user, %{ap_id: ap_id} = _muted) do def show_reblogs(user, %{ap_id: ap_id} = _muted) do
if ap_id in user.info.muted_reblogs do if ap_id in user.muted_reblogs do
User.update_info(user, &User.Info.remove_reblog_mute(&1, ap_id)) User.remove_reblog_mute(user, ap_id)
end end
end end
end end

View file

@ -197,11 +197,7 @@ def update_credentials(%{assigns: %{user: original_user}} = conn, params) do
|> Enum.dedup() |> Enum.dedup()
user_params = Map.put(user_params, :emoji, user_emojis) user_params = Map.put(user_params, :emoji, user_emojis)
changeset = User.update_changeset(user, user_params)
changeset =
user
|> User.update_changeset(user_params)
|> User.change_info(& &1)
with {:ok, user} <- User.update_and_set_cache(changeset) do with {:ok, user} <- User.update_and_set_cache(changeset) do
if original_user != user, do: CommonAPI.update(user) if original_user != user, do: CommonAPI.update(user)

View file

@ -21,8 +21,8 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
@doc "GET /api/v1/domain_blocks" @doc "GET /api/v1/domain_blocks"
def index(%{assigns: %{user: %{info: info}}} = conn, _) do def index(%{assigns: %{user: user}} = conn, _) do
json(conn, Map.get(info, :domain_blocks, [])) json(conn, Map.get(user, :domain_blocks, []))
end end
@doc "POST /api/v1/domain_blocks" @doc "POST /api/v1/domain_blocks"

View file

@ -129,12 +129,12 @@ defp do_stream(%{topic: topic, item: item}) do
end end
defp should_send?(%User{} = user, %Activity{} = item) do defp should_send?(%User{} = user, %Activity{} = item) do
blocks = user.info.blocks || [] blocks = user.blocks || []
mutes = user.info.mutes || [] mutes = user.mutes || []
reblog_mutes = user.info.muted_reblogs || [] reblog_mutes = user.muted_reblogs || []
recipient_blocks = MapSet.new(blocks ++ mutes) recipient_blocks = MapSet.new(blocks ++ mutes)
recipients = MapSet.new(item.recipients) recipients = MapSet.new(item.recipients)
domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks)
with parent when not is_nil(parent) <- Object.normalize(item), with parent when not is_nil(parent) <- Object.normalize(item),
true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)),

View file

@ -23,7 +23,9 @@ def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
with %User{} = user <- User.get_cached_by_id(uid), with %User{} = user <- User.get_cached_by_id(uid),
true <- user.local and user.confirmation_pending and user.confirmation_token == token, true <- user.local and user.confirmation_pending and user.confirmation_token == token,
{:ok, _} <- {:ok, _} <-
User.update_and_set_cache(User.confirmation_changeset(user, need_confirmation: false)) do user
|> User.confirmation_changeset(need_confirmation: false)
|> User.update_and_set_cache() do
redirect(conn, to: "/") redirect(conn, to: "/")
end end
end end

View file

@ -1,6 +1,98 @@
defmodule Pleroma.Repo.Migrations.CopyUsersInfoaddsToUsers do defmodule Pleroma.Repo.Migrations.CopyUsersInfoaddsToUsers do
use Ecto.Migration use Ecto.Migration
@info_fields [
:banner,
:background,
:source_data,
:note_count,
:follower_count,
:following_count,
:locked,
:confirmation_pending,
:password_reset_pending,
:confirmation_token,
:default_scope,
:blocks,
:domain_blocks,
:mutes,
:muted_reblogs,
:muted_notifications,
:subscribers,
:deactivated,
:no_rich_text,
:ap_enabled,
:is_moderator,
:is_admin,
:show_role,
:settings,
:magic_key,
:uri,
:topic,
:hub,
:salmon,
:hide_followers_count,
:hide_follows_count,
:hide_followers,
:hide_follows,
:hide_favorites,
:unread_conversation_count,
:pinned_activities,
:email_notifications,
:mascot,
:emoji,
:pleroma_settings_store,
:fields,
:raw_fields,
:discoverable,
:skip_thread_containment,
:notification_settings
]
@jsonb_fields [
:banner,
:background,
:source_data,
:settings,
:email_notifications,
:mascot,
:pleroma_settings_store,
:notification_settings
]
@array_jsonb_fields [:emoji, :fields, :raw_fields]
@int_fields [:note_count, :follower_count, :following_count, :unread_conversation_count]
@boolean_fields [
:locked,
:confirmation_pending,
:password_reset_pending,
:deactivated,
:no_rich_text,
:ap_enabled,
:is_moderator,
:is_admin,
:show_role,
:hide_followers_count,
:hide_follows_count,
:hide_followers,
:hide_follows,
:hide_favorites,
:discoverable,
:skip_thread_containment
]
@array_text_fields [
:blocks,
:domain_blocks,
:mutes,
:muted_reblogs,
:muted_notifications,
:subscribers,
:pinned_activities
]
def change do def change do
alter table(:users) do alter table(:users) do
add(:banner, :map, default: %{}) add(:banner, :map, default: %{})
@ -8,11 +100,10 @@ def change do
add(:source_data, :map, default: %{}) add(:source_data, :map, default: %{})
add(:note_count, :integer, default: 0) add(:note_count, :integer, default: 0)
add(:follower_count, :integer, default: 0) add(:follower_count, :integer, default: 0)
# Should be filled in only for remote users
add(:following_count, :integer, default: nil) add(:following_count, :integer, default: nil)
add(:locked, :boolean, default: false) add(:locked, :boolean, default: false, null: false)
add(:confirmation_pending, :boolean, default: false) add(:confirmation_pending, :boolean, default: false, null: false)
add(:password_reset_pending, :boolean, default: false) add(:password_reset_pending, :boolean, default: false, null: false)
add(:confirmation_token, :text, default: nil) add(:confirmation_token, :text, default: nil)
add(:default_scope, :string, default: "public") add(:default_scope, :string, default: "public")
add(:blocks, {:array, :text}, default: []) add(:blocks, {:array, :text}, default: [])
@ -50,5 +141,45 @@ def change do
add(:notification_settings, :map, default: %{}) add(:notification_settings, :map, default: %{})
add(:skip_thread_containment, :boolean, default: false, null: false) add(:skip_thread_containment, :boolean, default: false, null: false)
end end
if direction == :up do
for f <- @info_fields do
set_field = "update users set #{f} ="
cond do
f in @jsonb_fields ->
execute("#{set_field} info->'#{f}'")
f in @array_jsonb_fields ->
execute("#{set_field} ARRAY(SELECT jsonb_array_elements(info->'#{f}'))")
f in @int_fields ->
execute("#{set_field} (info->>'#{f}')::int")
f in @boolean_fields ->
execute("#{set_field} coalesce((info->>'#{f}')::boolean, false)")
f in @array_text_fields ->
execute("#{set_field} ARRAY(SELECT jsonb_array_elements_text(info->'#{f}'))")
true ->
execute("#{set_field} info->>'#{f}'")
end
end
for index_name <- [
:users_deactivated_index,
:users_is_moderator_index,
:users_is_admin_index,
:users_subscribers_index
] do
drop_if_exists(index(:users, [], name: index_name))
end
end
create_if_not_exists(index(:users, [:deactivated]))
create_if_not_exists(index(:users, [:is_moderator]))
create_if_not_exists(index(:users, [:is_admin]))
create_if_not_exists(index(:users, [:subscribers]))
end end
end end

View file

@ -1133,11 +1133,9 @@ test "with overly long fields" do
ap_id: user.ap_id, ap_id: user.ap_id,
name: user.name, name: user.name,
nickname: user.nickname, nickname: user.nickname,
info: %{ fields: [
fields: [ %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)}
%{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)} ]
]
}
} }
assert {:ok, %User{}} = User.insert_or_update_user(data) assert {:ok, %User{}} = User.insert_or_update_user(data)