X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser.ex;h=a3f6add28cb13f033ecba47fc604733a75155771;hb=6a79bb12c38bce6287b29c79c1ad3b7f9b967b69;hp=034c414bf66aa8da24dca176c9a7b368b56d55b0;hpb=182f7bbb1170c44eac4ab4a9efa4ff0bff991c98;p=akkoma diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 034c414bf..a3f6add28 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -52,6 +52,7 @@ defmodule Pleroma.User do field(:avatar, :map) field(:local, :boolean, default: true) field(:follower_address, :string) + field(:following_address, :string) field(:search_rank, :float, virtual: true) field(:search_type, :integer, virtual: true) field(:tags, {:array, :string}, default: []) @@ -107,6 +108,10 @@ defmodule Pleroma.User do def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers" + @spec ap_following(User.t()) :: Sring.t() + 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 = if args[:following_count], do: args[:following_count], else: following_count(user) @@ -128,6 +133,7 @@ defmodule Pleroma.User 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: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) @@ -162,9 +168,10 @@ defmodule Pleroma.User do if changes.valid? do case info_cng.changes[:source_data] do - %{"followers" => followers} -> + %{"followers" => followers, "following" => following} -> changes |> put_change(:follower_address, followers) + |> put_change(:following_address, following) _ -> followers = User.ap_followers(%User{nickname: changes.changes[:nickname]}) @@ -196,7 +203,14 @@ defmodule Pleroma.User do |> User.Info.user_upgrade(params[:info]) struct - |> cast(params, [:bio, :name, :follower_address, :avatar, :last_refreshed_at]) + |> cast(params, [ + :bio, + :name, + :follower_address, + :following_address, + :avatar, + :last_refreshed_at + ]) |> unique_constraint(:nickname) |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: 5000) @@ -735,10 +749,13 @@ defmodule Pleroma.User do |> Repo.all() end - def mute(muter, %User{ap_id: ap_id}) do + @spec mute(User.t(), User.t(), boolean()) :: {:ok, User.t()} | {:error, String.t()} + def mute(muter, %User{ap_id: ap_id}, notifications? \\ true) do + info = muter.info + info_cng = - muter.info - |> User.Info.add_to_mutes(ap_id) + User.Info.add_to_mutes(info, ap_id) + |> User.Info.add_to_muted_notifications(info, ap_id, notifications?) cng = change(muter) @@ -748,9 +765,11 @@ defmodule Pleroma.User do end def unmute(muter, %{ap_id: ap_id}) do + info = muter.info + info_cng = - muter.info - |> User.Info.remove_from_mutes(ap_id) + User.Info.remove_from_mutes(info, ap_id) + |> User.Info.remove_from_muted_notifications(info, ap_id) cng = change(muter) @@ -846,12 +865,21 @@ defmodule Pleroma.User do def mutes?(nil, _), do: false def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.info.mutes, ap_id) + @spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean() + def muted_notifications?(nil, _), do: false + + def muted_notifications?(user, %{ap_id: ap_id}), + do: Enum.member?(user.info.muted_notifications, ap_id) + def blocks?(%User{info: info} = _user, %{ap_id: ap_id}) do blocks = info.blocks - domain_blocks = info.domain_blocks + + domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(info.domain_blocks) + %{host: host} = URI.parse(ap_id) - Enum.member?(blocks, ap_id) || Enum.any?(domain_blocks, &(&1 == host)) + Enum.member?(blocks, ap_id) || + Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) end def subscribed_to?(user, %{ap_id: ap_id}) do @@ -1012,42 +1040,20 @@ defmodule Pleroma.User do ) end - @spec sync_follow_counter() :: :ok - def sync_follow_counter, - do: PleromaJobQueue.enqueue(:background, __MODULE__, [:sync_follow_counters]) - - @spec perform(:sync_follow_counters) :: :ok - def perform(:sync_follow_counters) do - {:ok, _pid} = Agent.start_link(fn -> %{} end, name: :domain_errors) - config = Pleroma.Config.get([:instance, :external_user_synchronization]) - - :ok = sync_follow_counters(config) - Agent.stop(:domain_errors) - end - - @spec sync_follow_counters(keyword()) :: :ok - def sync_follow_counters(opts \\ []) do - users = external_users(opts) - - if length(users) > 0 do - errors = Agent.get(:domain_errors, fn state -> state end) - {last, updated_errors} = User.Synchronization.call(users, errors, opts) - Agent.update(:domain_errors, fn _state -> updated_errors end) - sync_follow_counters(max_id: last.id, limit: opts[:limit]) - else - :ok - end + @spec external_users_query() :: Ecto.Query.t() + def external_users_query do + User.Query.build(%{ + external: true, + active: true, + order_by: :id + }) end @spec external_users(keyword()) :: [User.t()] def external_users(opts \\ []) do query = - User.Query.build(%{ - external: true, - active: true, - order_by: :id, - select: [:id, :ap_id, :info] - }) + external_users_query() + |> select([u], struct(u, [:id, :ap_id, :info])) query = if opts[:max_id], @@ -1154,19 +1160,18 @@ defmodule Pleroma.User do end end - def get_or_create_instance_user do - relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay" - - if user = get_cached_by_ap_id(relay_uri) do + @doc "Creates an internal service actor by URI if missing. Optionally takes nickname for addressing." + def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do + if user = get_cached_by_ap_id(uri) do user else changes = %User{info: %User.Info{}} |> cast(%{}, [:ap_id, :nickname, :local]) - |> put_change(:ap_id, relay_uri) - |> put_change(:nickname, nil) + |> put_change(:ap_id, uri) + |> put_change(:nickname, nickname) |> put_change(:local, true) - |> put_change(:follower_address, relay_uri <> "/followers") + |> put_change(:follower_address, uri <> "/followers") {:ok, user} = Repo.insert(changes) user @@ -1187,10 +1192,12 @@ defmodule Pleroma.User do end # OStatus Magic Key - def public_key_from_info(%{magic_key: magic_key}) do + def public_key_from_info(%{magic_key: magic_key}) when not is_nil(magic_key) do {:ok, Pleroma.Web.Salmon.decode_key(magic_key)} end + def public_key_from_info(_), do: {:error, "not found key"} + def get_public_key_for_ap_id(ap_id) do with {:ok, %User{} = user} <- get_or_fetch_by_ap_id(ap_id), {:ok, public_key} <- public_key_from_info(user.info) do @@ -1207,7 +1214,7 @@ defmodule Pleroma.User do data |> Map.put(:name, blank?(data[:name]) || data[:nickname]) |> remote_user_creation() - |> Repo.insert(on_conflict: :replace_all, conflict_target: :nickname) + |> Repo.insert(on_conflict: :replace_all_except_primary_key, conflict_target: :nickname) |> set_cache() end @@ -1376,23 +1383,16 @@ defmodule Pleroma.User do } end - def ensure_keys_present(user) do - info = user.info - + def ensure_keys_present(%User{info: info} = user) do if info.keys do {:ok, user} else {:ok, pem} = Keys.generate_rsa_pem() - info_cng = - info - |> User.Info.set_keys(pem) - - cng = - Ecto.Changeset.change(user) - |> Ecto.Changeset.put_embed(:info, info_cng) - - update_and_set_cache(cng) + user + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:info, User.Info.set_keys(info, pem)) + |> update_and_set_cache() end end @@ -1413,4 +1413,8 @@ defmodule Pleroma.User do end defp put_password_hash(changeset), do: changeset + + def is_internal_user?(%User{nickname: nil}), do: true + def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true + def is_internal_user?(_), do: false end