diff --git a/config/config.exs b/config/config.exs index e084d1a88..4f4e2368a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -137,7 +137,8 @@ config :pleroma, :instance, "text/markdown" ], finmoji_enabled: true, - mrf_transparency: true + mrf_transparency: true, + autofollowed_nicknames: [] config :pleroma, :markup, # XXX - unfortunately, inline images must be enabled by default right now, because diff --git a/docs/config.md b/docs/config.md index f1bb8d86c..7eb2d5671 100644 --- a/docs/config.md +++ b/docs/config.md @@ -32,7 +32,7 @@ This filter replaces the filename (not the path) of an upload. For complete obfu ## Pleroma.Mailer * `adapter`: one of the mail adapters listed in [Swoosh readme](https://github.com/swoosh/swoosh#adapters), or `Swoosh.Adapters.Local` for in-memory mailbox. -* `api_key` / `password` and / or other adapter-specific settings, per the above documentation. +* `api_key` / `password` and / or other adapter-specific settings, per the above documentation. An example for Sendgrid adapter: @@ -94,6 +94,7 @@ config :pleroma, Pleroma.Mailer, * `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with older software for theses nicknames. * `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature. +* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow. ## :logger * `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 85d0f9fce..7c2849ce2 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -44,20 +44,28 @@ 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 remote_or_auth_active?(%User{} = user), do: !user.local || auth_active?(user) + def visible_for?(_, _), do: false - def visible_for?(%User{} = user, for_user \\ nil) do - User.remote_or_auth_active?(user) || (for_user && for_user.id == user.id) || - User.superuser?(for_user) - end - - def superuser?(nil), do: false - def superuser?(%User{} = user), do: user.info && User.Info.superuser?(user.info) + 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 @@ -229,10 +237,27 @@ defmodule Pleroma.User 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() + + autofollowed_users + |> Enum.reduce({:ok, user}, fn other_user, {:ok, user} -> + follow(user, other_user) + end) + 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 diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 8ac50540d..fb1791c20 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -42,8 +42,6 @@ defmodule Pleroma.User.Info do # subject _> Where is this used? end - def superuser?(info), do: info.is_admin || info.is_moderator - def set_activation_status(info, deactivated) do params = %{deactivated: deactivated} diff --git a/test/user_test.exs b/test/user_test.exs index 74accb7c8..541252539 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -142,6 +142,23 @@ defmodule Pleroma.UserTest do email: "email@example.com" } + test "it autofollows accounts that are set for it" do + user = insert(:user) + remote_user = insert(:user, %{local: false}) + + Pleroma.Config.put([:instance, :autofollowed_nicknames], [ + user.nickname, + remote_user.nickname + ]) + + cng = User.register_changeset(%User{}, @full_user_data) + + {:ok, registered_user} = User.register(cng) + + assert User.following?(registered_user, user) + refute User.following?(registered_user, remote_user) + end + test "it requires an email, name, nickname and password, bio is optional" do @full_user_data |> Map.keys() @@ -767,4 +784,83 @@ defmodule Pleroma.UserTest do |> Map.put(:search_distance, nil) end end + + test "auth_active?/1 works correctly" do + Pleroma.Config.put([:instance, :account_activation_required], true) + + local_user = insert(:user, local: true, info: %{confirmation_pending: true}) + confirmed_user = insert(:user, local: true, info: %{confirmation_pending: false}) + remote_user = insert(:user, local: false) + + refute User.auth_active?(local_user) + assert User.auth_active?(confirmed_user) + assert User.auth_active?(remote_user) + + Pleroma.Config.put([:instance, :account_activation_required], false) + end + + describe "superuser?/1" do + test "returns false for unprivileged users" do + user = insert(:user, local: true) + + refute User.superuser?(user) + end + + test "returns false for remote users" do + user = insert(:user, local: false) + remote_admin_user = insert(:user, local: false, info: %{is_admin: true}) + + refute User.superuser?(user) + refute User.superuser?(remote_admin_user) + end + + test "returns true for local moderators" do + user = insert(:user, local: true, info: %{is_moderator: true}) + + assert User.superuser?(user) + end + + test "returns true for local admins" do + user = insert(:user, local: true, info: %{is_admin: true}) + + assert User.superuser?(user) + end + end + + describe "visible_for?/2" do + test "returns true when the account is itself" do + user = insert(:user, local: true) + + assert User.visible_for?(user, user) + end + + test "returns false when the account is unauthenticated and auth is required" do + Pleroma.Config.put([:instance, :account_activation_required], true) + + user = insert(:user, local: true, info: %{confirmation_pending: true}) + other_user = insert(:user, local: true) + + refute User.visible_for?(user, other_user) + + Pleroma.Config.put([:instance, :account_activation_required], false) + end + + test "returns true when the account is unauthenticated and auth is not required" do + user = insert(:user, local: true, info: %{confirmation_pending: true}) + other_user = insert(:user, local: true) + + assert User.visible_for?(user, other_user) + end + + test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do + Pleroma.Config.put([:instance, :account_activation_required], true) + + user = insert(:user, local: true, info: %{confirmation_pending: true}) + other_user = insert(:user, local: true, info: %{is_admin: true}) + + assert User.visible_for?(user, other_user) + + Pleroma.Config.put([:instance, :account_activation_required], false) + end + end end