From 10ff01acd95d42314b4eb923e5b7a7191356b73e Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 16 Oct 2019 21:59:21 +0300 Subject: [PATCH 01/28] [#1304] Moved all non-mutes / non-blocks fields from User.Info to User. WIP. --- CHANGELOG.md | 1 + lib/mix/tasks/pleroma/user.ex | 18 +- lib/pleroma/daemons/digest_email_daemon.ex | 2 +- lib/pleroma/emails/user_email.ex | 2 +- lib/pleroma/formatter.ex | 2 +- lib/pleroma/notification.ex | 10 +- .../plugs/admin_secret_authentication_plug.ex | 2 +- lib/pleroma/plugs/oauth_plug.ex | 2 +- lib/pleroma/plugs/user_enabled_plug.ex | 2 +- lib/pleroma/plugs/user_is_admin_plug.ex | 2 +- lib/pleroma/stats.ex | 7 +- lib/pleroma/user.ex | 554 +++++++++++++----- lib/pleroma/user/info.ex | 371 ------------ lib/pleroma/user/query.ex | 21 +- lib/pleroma/web/activity_pub/activity_pub.ex | 20 +- .../activity_pub/activity_pub_controller.ex | 6 +- .../activity_pub/mrf/anti_link_spam_policy.ex | 2 +- lib/pleroma/web/activity_pub/publisher.ex | 8 +- .../web/activity_pub/transmogrifier.ex | 12 +- .../web/activity_pub/views/user_view.ex | 28 +- .../web/admin_api/admin_api_controller.ex | 22 +- .../web/admin_api/views/account_view.ex | 5 +- lib/pleroma/web/common_api/common_api.ex | 12 +- lib/pleroma/web/masto_fe_controller.ex | 2 +- .../controllers/account_controller.ex | 64 +- .../web/mastodon_api/views/account_view.ex | 68 +-- .../web/mastodon_api/views/status_view.ex | 2 +- lib/pleroma/web/oauth/oauth_controller.ex | 4 +- .../web/ostatus/handlers/follow_handler.ex | 2 +- lib/pleroma/web/ostatus/ostatus.ex | 9 +- .../controllers/account_controller.ex | 16 +- .../controllers/mascot_controller.ex | 4 +- lib/pleroma/web/salmon/salmon.ex | 8 +- lib/pleroma/web/streamer/worker.ex | 2 +- .../web/twitter_api/twitter_api_controller.ex | 9 +- lib/pleroma/web/views/masto_fe_view.ex | 8 +- lib/pleroma/web/websub/websub.ex | 4 +- ...add_following_address_from_source_data.exs | 6 +- ...2024_copy_muted_to_muted_notifications.exs | 1 - ...154608_copy_users_info_fields_to_users.exs | 54 ++ test/daemons/digest_email_daemon_test.exs | 2 +- test/emails/user_email_test.exs | 2 +- test/formatter_test.exs | 6 +- test/moderation_log_test.exs | 4 +- test/notification_test.exs | 8 +- .../admin_secret_authentication_plug_test.exs | 2 +- test/plugs/user_enabled_plug_test.exs | 2 +- test/plugs/user_is_admin_plug_test.exs | 2 +- test/signature_test.exs | 4 +- test/tasks/count_statuses_test.exs | 16 +- test/tasks/database_test.exs | 11 +- test/tasks/user_test.exs | 38 +- test/user_info_test.exs | 24 - test/user_test.exs | 160 +++-- .../activity_pub_controller_test.exs | 12 +- test/web/activity_pub/activity_pub_test.exs | 24 +- .../mrf/anti_link_spam_policy_test.exs | 22 +- test/web/activity_pub/publisher_test.exs | 50 +- .../transmogrifier/follow_handling_test.exs | 2 +- test/web/activity_pub/transmogrifier_test.exs | 36 +- test/web/activity_pub/utils_test.exs | 4 +- .../web/activity_pub/views/user_view_test.exs | 20 +- .../admin_api/admin_api_controller_test.exs | 130 ++-- test/web/admin_api/search_test.exs | 12 +- test/web/admin_api/views/report_view_test.exs | 2 + test/web/common_api/common_api_test.exs | 12 +- test/web/federator_test.exs | 10 +- test/web/masto_fe_controller_test.exs | 2 +- .../update_credentials_test.exs | 2 +- .../controllers/account_controller_test.exs | 16 +- .../conversation_controller_test.exs | 12 +- .../follow_request_controller_test.exs | 6 +- .../controllers/instance_controller_test.exs | 9 +- .../controllers/status_controller_test.exs | 4 +- test/web/mastodon_api/mastodon_api_test.exs | 6 +- .../mastodon_api/views/account_view_test.exs | 57 +- test/web/node_info_test.exs | 4 +- test/web/oauth/oauth_controller_test.exs | 8 +- test/web/ostatus/ostatus_controller_test.exs | 5 +- test/web/ostatus/ostatus_test.exs | 62 +- .../controllers/account_controller_test.exs | 21 +- .../controllers/emoji_api_controller_test.exs | 12 +- test/web/salmon/salmon_test.exs | 4 +- test/web/streamer/streamer_test.exs | 2 +- .../twitter_api/password_controller_test.exs | 4 +- test/web/twitter_api/twitter_api_test.exs | 2 +- test/web/twitter_api/util_controller_test.exs | 8 +- test/web/websub/websub_test.exs | 2 +- 88 files changed, 1069 insertions(+), 1170 deletions(-) create mode 100644 priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs delete mode 100644 test/user_info_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index bd06ec866..4ce9fa4b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MRF (Simple Policy): Also use `:accept`/`:reject` on the actors rather than only their activities - OStatus: Extract RSS functionality - Mastodon API: Add `pleroma.direct_conversation_id` to the status endpoint (`GET /api/v1/statuses/:id`) +- Deprecated `User.Info` embedded schema (fields moved to `User`) ### Fixed - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 134b5bccc..265c5f1a7 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -109,10 +109,10 @@ def run(["toggle_activated", nickname]) do start_pleroma() with %User{} = user <- User.get_cached_by_nickname(nickname) do - {:ok, user} = User.deactivate(user, !user.info.deactivated) + {:ok, user} = User.deactivate(user, !user.deactivated) shell_info( - "Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated" + "Activation status of #{nickname}: #{if(user.deactivated, do: "de", else: "")}activated" ) else _ -> @@ -340,7 +340,7 @@ def run(["toggle_confirmed", nickname]) do with %User{} = user <- User.get_cached_by_nickname(nickname) do {:ok, user} = User.toggle_confirmation(user) - message = if user.info.confirmation_pending, do: "needs", else: "doesn't need" + message = if user.confirmation_pending, do: "needs", else: "doesn't need" shell_info("#{nickname} #{message} confirmation.") else @@ -364,23 +364,23 @@ def run(["sign_out", nickname]) do end defp set_moderator(user, value) do - {:ok, user} = User.update_info(user, &User.Info.admin_api_update(&1, %{is_moderator: value})) + {:ok, user} = User.update_and_set_cache(user, %{is_moderator: value}) - shell_info("Moderator status of #{user.nickname}: #{user.info.is_moderator}") + shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}") user end defp set_admin(user, value) do - {:ok, user} = User.update_info(user, &User.Info.admin_api_update(&1, %{is_admin: value})) + {:ok, user} = User.update_and_set_cache(user, %{is_admin: value}) - shell_info("Admin status of #{user.nickname}: #{user.info.is_admin}") + shell_info("Admin status of #{user.nickname}: #{user.is_admin}") user end defp set_locked(user, value) do - {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: value})) + {:ok, user} = User.update_and_set_cache(user, %{locked: value}) - shell_info("Locked status of #{user.nickname}: #{user.info.locked}") + shell_info("Locked status of #{user.nickname}: #{user.locked}") user end end diff --git a/lib/pleroma/daemons/digest_email_daemon.ex b/lib/pleroma/daemons/digest_email_daemon.ex index 462ad2c55..b4c8eaad9 100644 --- a/lib/pleroma/daemons/digest_email_daemon.ex +++ b/lib/pleroma/daemons/digest_email_daemon.ex @@ -17,7 +17,7 @@ def perform do now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) from(u in inactive_users_query, - where: fragment(~s(? #> '{"email_notifications","digest"}' @> 'true'), u.info), + where: fragment(~s(? ->'digest' @> 'true'), u.email_notifications), where: u.last_digest_emailed_at < datetime_add(^now, ^negative_interval, "day"), select: u ) diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 40b67ff56..a10f88f93 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -72,7 +72,7 @@ def account_confirmation_email(user) do Endpoint, :confirm_email, user.id, - to_string(user.info.confirmation_token) + to_string(user.confirmation_token) ) html_body = """ diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 931b9af2b..19b9af46c 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -127,7 +127,7 @@ def truncate(text, max_length \\ 200, omission \\ "...") do end end - defp get_ap_id(%User{info: %{source_data: %{"url" => url}}}) when is_binary(url), do: url + defp get_ap_id(%User{source_data: %{"url" => url}}) when is_binary(url), do: url defp get_ap_id(%User{ap_id: ap_id}), do: ap_id defp get_nickname_text(nickname, %{mentions_format: :full}), do: User.full_nickname(nickname) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index d94ae5971..19d22370f 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -40,7 +40,7 @@ def for_user_query(user, opts \\ []) do |> where( [n, a], fragment( - "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", + "? not in (SELECT ap_id FROM users WHERE deactivated = 'true')", a.actor ) ) @@ -259,7 +259,7 @@ def skip?(:self, activity, user) do def skip?( :followers, activity, - %{info: %{notification_settings: %{"followers" => false}}} = user + %{notification_settings: %{"followers" => false}} = user ) do actor = activity.data["actor"] follower = User.get_cached_by_ap_id(actor) @@ -269,14 +269,14 @@ def skip?( def skip?( :non_followers, activity, - %{info: %{notification_settings: %{"non_followers" => false}}} = user + %{notification_settings: %{"non_followers" => false}} = user ) do actor = activity.data["actor"] follower = User.get_cached_by_ap_id(actor) !User.following?(follower, user) end - def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do + def skip?(:follows, activity, %{notification_settings: %{"follows" => false}} = user) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) User.following?(user, followed) @@ -285,7 +285,7 @@ def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => fa def skip?( :non_follows, activity, - %{info: %{notification_settings: %{"non_follows" => false}}} = user + %{notification_settings: %{"non_follows" => false}} = user ) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) diff --git a/lib/pleroma/plugs/admin_secret_authentication_plug.ex b/lib/pleroma/plugs/admin_secret_authentication_plug.ex index 5baf8a691..fdadd476e 100644 --- a/lib/pleroma/plugs/admin_secret_authentication_plug.ex +++ b/lib/pleroma/plugs/admin_secret_authentication_plug.ex @@ -19,7 +19,7 @@ def call(%{assigns: %{user: %User{}}} = conn, _), do: conn def call(%{params: %{"admin_token" => admin_token}} = conn, _) do if secret_token() && admin_token == secret_token() do conn - |> assign(:user, %User{info: %{is_admin: true}}) + |> assign(:user, %User{is_admin: true}) else conn end diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex index 86bc4aa3a..fd004fcd2 100644 --- a/lib/pleroma/plugs/oauth_plug.ex +++ b/lib/pleroma/plugs/oauth_plug.ex @@ -71,7 +71,7 @@ defp fetch_user_and_token(token) do ) # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength - with %Token{user: %{info: %{deactivated: false} = _} = user} = token_record <- Repo.one(query) do + with %Token{user: %{deactivated: false} = user} = token_record <- Repo.one(query) do {:ok, user, token_record} end end diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex index da892c28b..fbb4bf115 100644 --- a/lib/pleroma/plugs/user_enabled_plug.ex +++ b/lib/pleroma/plugs/user_enabled_plug.ex @@ -10,7 +10,7 @@ def init(options) do options end - def call(%{assigns: %{user: %User{info: %{deactivated: true}}}} = conn, _) do + def call(%{assigns: %{user: %User{deactivated: true}}} = conn, _) do conn |> assign(:user, nil) end diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 4c4b3d610..ee808f31f 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -11,7 +11,7 @@ def init(options) do options end - def call(%{assigns: %{user: %User{info: %{is_admin: true}}}} = conn, _) do + def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _) do conn end diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index df80fbaa4..8154a09b7 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -68,12 +68,7 @@ defp get_stat_data do domain_count = Enum.count(peers) - status_query = - from(u in User.Query.build(%{local: true}), - select: fragment("sum((?->>'note_count')::int)", u.info) - ) - - status_count = Repo.one(status_query) + status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count) user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 2cfb13a8c..165342011 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -63,6 +63,62 @@ defmodule Pleroma.User do field(:tags, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime_usec) field(:last_digest_emailed_at, :naive_datetime) + + field(:banner, :map, default: %{}) + field(:background, :map, default: %{}) + field(:source_data, :map, default: %{}) + field(:note_count, :integer, default: 0) + field(:follower_count, :integer, default: 0) + # Should be filled in only for remote users + field(:following_count, :integer, default: nil) + field(:locked, :boolean, default: false) + field(:confirmation_pending, :boolean, default: false) + field(:password_reset_pending, :boolean, default: false) + field(:confirmation_token, :string, default: nil) + field(:default_scope, :string, default: "public") + 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: []) + field(:subscribers, {:array, :string}, default: []) + field(:deactivated, :boolean, default: false) + field(:no_rich_text, :boolean, default: false) + field(:ap_enabled, :boolean, default: false) + field(:is_moderator, :boolean, default: false) + field(:is_admin, :boolean, default: false) + field(:show_role, :boolean, default: true) + field(:settings, :map, default: nil) + field(:magic_key, :string, default: nil) + field(:uri, :string, default: nil) + field(:topic, :string, default: nil) + field(:hub, :string, default: nil) + field(:salmon, :string, default: nil) + field(:hide_followers_count, :boolean, default: false) + field(:hide_follows_count, :boolean, default: false) + field(:hide_followers, :boolean, default: false) + field(:hide_follows, :boolean, default: false) + field(:hide_favorites, :boolean, default: true) + field(:unread_conversation_count, :integer, default: 0) + field(:pinned_activities, {:array, :string}, default: []) + field(:email_notifications, :map, default: %{"digest" => false}) + field(:mascot, :map, default: nil) + field(:emoji, {:array, :map}, default: []) + field(:pleroma_settings_store, :map, default: %{}) + field(:fields, {:array, :map}, default: nil) + field(:raw_fields, {:array, :map}, default: []) + field(:discoverable, :boolean, default: false) + field(:skip_thread_containment, :boolean, default: false) + + field(:notification_settings, :map, + default: %{ + "followers" => true, + "follows" => true, + "non_follows" => true, + "non_followers" => true + } + ) + has_many(:notifications, Notification) has_many(:registrations, Registration) has_many(:deliveries, Delivery) @@ -71,7 +127,7 @@ defmodule Pleroma.User do timestamps() end - def auth_active?(%User{info: %User.Info{confirmation_pending: true}}), + def auth_active?(%User{confirmation_pending: true}), do: !Pleroma.Config.get([:instance, :account_activation_required]) def auth_active?(%User{}), do: true @@ -86,8 +142,8 @@ def visible_for?(%User{} = user, for_user) do 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?(%User{local: true, is_admin: true}), do: true + def superuser?(%User{local: true, is_moderator: true}), do: true def superuser?(_), do: false def avatar_url(user, options \\ []) do @@ -98,13 +154,13 @@ def avatar_url(user, options \\ []) do end def banner_url(user, options \\ []) do - case user.info.banner do + case user.banner do %{"url" => [%{"href" => href} | _]} -> href _ -> !options[:no_default] && "#{Web.base_url()}/images/banner.png" end end - def profile_url(%User{info: %{source_data: %{"url" => url}}}), do: url + def profile_url(%User{source_data: %{"url" => url}}), do: url def profile_url(%User{ap_id: ap_id}), do: ap_id def profile_url(_), do: nil @@ -119,15 +175,15 @@ 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.info.following_count || following_count(user)) + Map.get(args, :following_count, user.following_count || following_count(user)) - follower_count = Map.get(args, :follower_count, user.info.follower_count) + follower_count = Map.get(args, :follower_count, user.follower_count) %{ - note_count: user.info.note_count, - locked: user.info.locked, - confirmation_pending: user.info.confirmation_pending, - default_scope: user.info.default_scope + note_count: user.note_count, + locked: user.locked, + confirmation_pending: user.confirmation_pending, + default_scope: user.default_scope } |> Map.put(:following_count, following_count) |> Map.put(:follower_count, follower_count) @@ -157,9 +213,7 @@ def set_info_cache(user, args) do @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) - ) + from(u in query, where: u.deactivated != ^true) end def following_count(%User{following: []}), do: 0 @@ -170,6 +224,64 @@ def following_count(%User{} = user) do |> Repo.aggregate(:count, :id) end + @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 + ] + + def info_fields, do: @info_fields + + defp truncate_fields_param(params) do + if Map.has_key?(params, :fields) do + Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1)) + else + params + end + end + defp truncate_if_exists(params, key, max_length) do if Map.has_key?(params, key) and is_binary(params[key]) do {value, _chopped} = String.split_at(params[key], max_length) @@ -188,18 +300,20 @@ def remote_user_creation(params) do |> Map.put(:info, params[:info] || %{}) |> truncate_if_exists(:name, name_limit) |> truncate_if_exists(:bio, bio_limit) + |> truncate_fields_param() changeset = %User{local: false} - |> cast(params, [:bio, :name, :ap_id, :nickname, :avatar]) + |> cast(params, [:bio, :name, :ap_id, :nickname, :avatar] ++ @info_fields) |> validate_required([:name, :ap_id]) |> unique_constraint(:nickname) |> validate_format(:nickname, @email_regex) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) - |> change_info(&User.Info.remote_user_creation(&1, params[:info])) + |> validate_fields(true) + |> change_info(& &1) - case params[:info][:source_data] do + case params[:source_data] do %{"followers" => followers, "following" => following} -> changeset |> put_change(:follower_address, followers) @@ -216,11 +330,12 @@ def update_changeset(struct, params \\ %{}) do name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) struct - |> cast(params, [:bio, :name, :avatar, :following]) + |> cast(params, [:bio, :name, :avatar, :following] ++ @info_fields) |> unique_constraint(:nickname) |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, min: 1, max: name_limit) + |> validate_fields(false) end def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do @@ -229,20 +344,26 @@ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now()) + params = if remote?, do: truncate_fields_param(params), else: params + struct - |> cast(params, [ - :bio, - :name, - :follower_address, - :following_address, - :avatar, - :last_refreshed_at - ]) + |> cast( + params, + [ + :bio, + :name, + :follower_address, + :following_address, + :avatar, + :last_refreshed_at + ] ++ @info_fields + ) |> unique_constraint(:nickname) |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) - |> change_info(&User.Info.user_upgrade(&1, params[:info], remote?)) + |> validate_fields(remote?) + |> change_info(& &1) end def password_update_changeset(struct, params) do @@ -250,8 +371,8 @@ def password_update_changeset(struct, params) do |> cast(params, [:password, :password_confirmation]) |> validate_required([:password, :password_confirmation]) |> validate_confirmation(:password) - |> put_password_hash - |> put_embed(:info, User.Info.set_password_reset_pending(struct.info, false)) + |> put_password_hash() + |> put_change(:password_reset_pending, false) end @spec reset_password(User.t(), map) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()} @@ -268,19 +389,19 @@ def reset_password(%User{id: user_id} = user, data) do end end + def update_password_reset_pending(user, value) do + user + |> change() + |> put_change(:password_reset_pending, value) + |> update_and_set_cache() + end + def force_password_reset_async(user) do BackgroundWorker.enqueue("force_password_reset", %{"user_id" => user.id}) end @spec force_password_reset(User.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()} - def force_password_reset(user) do - info_cng = User.Info.set_password_reset_pending(user.info, true) - - user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache() - end + def force_password_reset(user), do: update_password_reset_pending(user, true) def register_changeset(struct, params \\ %{}, opts \\ []) do bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) @@ -294,6 +415,7 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do end struct + |> confirmation_changeset(need_confirmation: need_confirmation?) |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation]) |> validate_required([:name, :nickname, :password, :password_confirmation]) |> validate_confirmation(:password) @@ -304,7 +426,7 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do |> validate_format(:email, @email_regex) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, min: 1, max: name_limit) - |> change_info(&User.Info.confirmation_changeset(&1, need_confirmation: need_confirmation?)) + |> change_info(& &1) |> maybe_validate_required_email(opts[:external]) |> put_password_hash |> put_ap_id() @@ -355,7 +477,7 @@ def post_register_action(%User{} = user) do end def try_send_confirmation_email(%User{} = user) do - if user.info.confirmation_pending && + if user.confirmation_pending && Pleroma.Config.get([:instance, :account_activation_required]) do user |> Pleroma.Emails.UserEmail.account_confirmation_email() @@ -378,7 +500,7 @@ def needs_update?(%User{local: false} = user) do def needs_update?(_), do: true @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()} - def maybe_direct_follow(%User{} = follower, %User{local: true, info: %{locked: true}}) do + def maybe_direct_follow(%User{} = follower, %User{local: true, locked: true}) do {:ok, follower} end @@ -425,13 +547,13 @@ def follow_all(follower, followeds) do set_cache(follower) end - def follow(%User{} = follower, %User{info: info} = followed) do + def follow(%User{} = follower, %User{} = followed) do deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) ap_followers = followed.follower_address cond do - info.deactivated -> - {:error, "Could not follow user: You are deactivated."} + followed.deactivated -> + {:error, "Could not follow user: #{followed.nickname} is deactivated."} deny_follow_blocked and blocks?(followed, follower) -> {:error, "Could not follow user: #{followed.nickname} blocked you."} @@ -489,7 +611,7 @@ def following?(%User{} = follower, %User{} = followed) do end def locked?(%User{} = user) do - user.info.locked || false + user.locked || false end def get_by_id(id) do @@ -532,6 +654,12 @@ def set_cache(%User{} = user) do {:ok, user} end + def update_and_set_cache(struct, params) do + struct + |> update_changeset(params) + |> update_and_set_cache() + end + def update_and_set_cache(changeset) do with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do set_cache(user) @@ -721,16 +849,7 @@ def get_follow_requests(%User{} = user) do def increase_note_count(%User{} = user) do User |> where(id: ^user.id) - |> update([u], - set: [ - info: - fragment( - "jsonb_set(?, '{note_count}', ((?->>'note_count')::int + 1)::varchar::jsonb, true)", - u.info, - u.info - ) - ] - ) + |> update([u], inc: [note_count: 1]) |> select([u], u) |> Repo.update_all([]) |> case do @@ -744,12 +863,7 @@ def decrease_note_count(%User{} = user) do |> where(id: ^user.id) |> update([u], set: [ - info: - fragment( - "jsonb_set(?, '{note_count}', (greatest(0, (?->>'note_count')::int - 1))::varchar::jsonb, true)", - u.info, - u.info - ) + note_count: fragment("greatest(0, note_count - 1)") ] ) |> select([u], u) @@ -760,29 +874,17 @@ def decrease_note_count(%User{} = user) do end end - def update_note_count(%User{} = user) do + def update_note_count(%User{} = user, note_count \\ nil) do note_count = - from( - a in Object, - where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data), - select: count(a.id) - ) - |> Repo.one() + note_count || + from( + a in Object, + where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data), + select: count(a.id) + ) + |> Repo.one() - update_info(user, &User.Info.set_note_count(&1, note_count)) - end - - def update_mascot(user, url) do - info_changeset = - User.Info.mascot_update( - user.info, - url - ) - - user - |> change() - |> put_embed(:info, info_changeset) - |> update_and_set_cache() + update_and_set_cache(user, %{note_count: note_count}) end @spec maybe_fetch_follow_information(User.t()) :: User.t() @@ -799,10 +901,24 @@ def maybe_fetch_follow_information(user) do def fetch_follow_information(user) do with {:ok, info} <- ActivityPub.fetch_follow_information_for_user(user) do - update_info(user, &User.Info.follow_information_update(&1, info)) + user + |> follow_information_changeset(info) + |> update_and_set_cache() end end + defp follow_information_changeset(user, params) do + user + |> cast(params, [ + :hide_followers, + :hide_follows, + :follower_count, + :following_count, + :hide_followers_count, + :hide_follows_count + ]) + end + def update_follower_count(%User{} = user) do if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do follower_count_query = @@ -813,14 +929,7 @@ def update_follower_count(%User{} = user) do |> where(id: ^user.id) |> join(:inner, [u], s in subquery(follower_count_query)) |> update([u, s], - set: [ - info: - fragment( - "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)", - u.info, - s.count - ) - ] + set: [follower_count: s.count] ) |> select([u], u) |> Repo.update_all([]) @@ -850,14 +959,7 @@ def set_unread_conversation_count(%User{local: true} = user) do User |> join(:inner, [u], p in subquery(unread_query)) |> update([u, p], - set: [ - info: - fragment( - "jsonb_set(?, '{unread_conversation_count}', ?::varchar::jsonb, true)", - u.info, - p.count - ) - ] + set: [unread_conversation_count: p.count] ) |> where([u], u.id == ^user.id) |> select([u], u) @@ -878,14 +980,7 @@ def increment_unread_conversation_count(conversation, %User{local: true} = user) User |> join(:inner, [u], p in subquery(unread_query)) |> update([u, p], - set: [ - info: - fragment( - "jsonb_set(?, '{unread_conversation_count}', (coalesce((?->>'unread_conversation_count')::int, 0) + 1)::varchar::jsonb, true)", - u.info, - u.info - ) - ] + inc: [unread_conversation_count: 1] ) |> where([u], u.id == ^user.id) |> where([u, p], p.count == 0) @@ -942,14 +1037,14 @@ def subscribe(subscriber, %{ap_id: ap_id}) do if blocks?(subscribed, subscriber) and deny_follow_blocked do {:error, "Could not subscribe: #{subscribed.nickname} is blocking you"} else - update_info(subscribed, &User.Info.add_to_subscribers(&1, subscriber.ap_id)) + User.add_to_subscribers(subscribed, subscriber.ap_id) end end end def unsubscribe(unsubscriber, %{ap_id: ap_id}) do with %User{} = user <- get_cached_by_ap_id(ap_id) do - update_info(user, &User.Info.remove_from_subscribers(&1, unsubscriber.ap_id)) + User.remove_from_subscribers(user, unsubscriber.ap_id) end end @@ -1025,7 +1120,7 @@ def blocks_domain?(_, _), do: false def subscribed_to?(user, %{ap_id: ap_id}) do with %User{} = target <- get_cached_by_ap_id(ap_id) do - Enum.member?(target.info.subscribers, user.ap_id) + Enum.member?(target.subscribers, user.ap_id) end end @@ -1043,7 +1138,7 @@ def blocked_users(user) do @spec subscribers(User.t()) :: [User.t()] def subscribers(user) do - User.Query.build(%{ap_id: user.info.subscribers, deactivated: false}) + User.Query.build(%{ap_id: user.subscribers, deactivated: false}) |> Repo.all() end @@ -1060,7 +1155,7 @@ def deactivate_async(user, status \\ true) do end def deactivate(%User{} = user, status \\ true) do - with {:ok, user} <- update_info(user, &User.Info.set_activation_status(&1, status)) do + with {:ok, user} <- set_activation_status(user, status) do Enum.each(get_followers(user), &invalidate_cache/1) Enum.each(get_friends(user), &update_follower_count/1) @@ -1068,8 +1163,23 @@ def deactivate(%User{} = user, status \\ true) do end end - def update_notification_settings(%User{} = user, settings \\ %{}) do - update_info(user, &User.Info.update_notification_settings(&1, settings)) + 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]) + |> validate_required([:notification_settings]) + |> update_and_set_cache() end def delete(%User{} = user) do @@ -1107,7 +1217,7 @@ def perform(:fetch_initial_posts, %User{} = user) do pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) # Insert all the posts in reverse order, so they're in the right order on the timeline - user.info.source_data["outbox"] + user.source_data["outbox"] |> Utils.fetch_ordered_collection(pages) |> Enum.reverse() |> Enum.each(&Pleroma.Web.Federator.incoming_ap_doc/1) @@ -1228,7 +1338,7 @@ defp delete_activity(%{data: %{"type" => "Announce"}} = activity) do defp delete_activity(_activity), do: "Doing nothing" - def html_filter_policy(%User{info: %{no_rich_text: true}}) do + def html_filter_policy(%User{no_rich_text: true}) do Pleroma.HTML.Scrubber.TwitterText end @@ -1288,9 +1398,7 @@ def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do end # AP style - def public_key_from_info(%{ - source_data: %{"publicKey" => %{"publicKeyPem" => public_key_pem}} - }) do + def public_key(%{source_data: %{"publicKey" => %{"publicKeyPem" => public_key_pem}}}) do key = public_key_pem |> :public_key.pem_decode() @@ -1301,15 +1409,15 @@ def public_key_from_info(%{ end # OStatus Magic Key - def public_key_from_info(%{magic_key: magic_key}) when not is_nil(magic_key) do + def public_key(%{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 public_key(_), 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 + {:ok, public_key} <- public_key(user) do {:ok, public_key} else _ -> :error @@ -1328,7 +1436,7 @@ def insert_or_update_user(data) do end def ap_enabled?(%User{local: true}), do: true - def ap_enabled?(%User{info: info}), do: info.ap_enabled + def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled def ap_enabled?(_), do: false @doc "Gets or fetch a user by uri or nickname." @@ -1486,7 +1594,7 @@ def list_inactive_users_query(inactivity_threshold \\ 7) do left_join: a in Pleroma.Activity, on: u.ap_id == a.actor, where: not is_nil(u.nickname), - where: fragment("not (?->'deactivated' @> 'true')", u.info), + where: u.deactivated != ^true, where: u.id not in ^has_read_notifications, group_by: u.id, having: @@ -1500,16 +1608,16 @@ def list_inactive_users_query(inactivity_threshold \\ 7) do ## Examples - iex> Pleroma.User.switch_email_notifications(Pleroma.User{info: %{email_notifications: %{"digest" => false}}}, "digest", true) - Pleroma.User{info: %{email_notifications: %{"digest" => true}}} + iex> Pleroma.User.switch_email_notifications(Pleroma.User{email_notifications: %{"digest" => false}}, "digest", true) + Pleroma.User{email_notifications: %{"digest" => true}} - iex> Pleroma.User.switch_email_notifications(Pleroma.User{info: %{email_notifications: %{"digest" => true}}}, "digest", false) - Pleroma.User{info: %{email_notifications: %{"digest" => false}}} + iex> Pleroma.User.switch_email_notifications(Pleroma.User{email_notifications: %{"digest" => true}}, "digest", false) + Pleroma.User{email_notifications: %{"digest" => false}} """ @spec switch_email_notifications(t(), String.t(), boolean()) :: {:ok, t()} | {:error, Ecto.Changeset.t()} def switch_email_notifications(user, type, status) do - update_info(user, &User.Info.update_email_notifications(&1, %{type => status})) + User.update_email_notifications(user, %{type => status}) end @doc """ @@ -1529,17 +1637,16 @@ def touch_last_digest_emailed_at(user) do @spec toggle_confirmation(User.t()) :: {:ok, User.t()} | {:error, Changeset.t()} def toggle_confirmation(%User{} = user) do - need_confirmation? = !user.info.confirmation_pending - user - |> update_info(&User.Info.confirmation_changeset(&1, need_confirmation: need_confirmation?)) + |> confirmation_changeset(need_confirmation: !user.confirmation_pending) + |> update_and_set_cache() end - def get_mascot(%{info: %{mascot: %{} = mascot}}) when not is_nil(mascot) do + def get_mascot(%{mascot: %{} = mascot}) when not is_nil(mascot) do mascot end - def get_mascot(%{info: %{mascot: mascot}}) when is_nil(mascot) do + def get_mascot(%{mascot: mascot}) when is_nil(mascot) do # use instance-default config = Pleroma.Config.get([:assets, :mascots]) default_mascot = Pleroma.Config.get([:assets, :default_mascot]) @@ -1609,6 +1716,31 @@ def change_email(user, email) do |> update_and_set_cache() end + # Internal function; public one is `deactivate/2` + defp set_activation_status(user, deactivated) do + user + |> cast(%{deactivated: deactivated}, [:deactivated]) + |> update_and_set_cache() + end + + def update_banner(user, banner) do + user + |> cast(%{banner: banner}, [:banner]) + |> update_and_set_cache() + end + + def update_background(user, background) do + user + |> cast(%{background: background}, [:background]) + |> update_and_set_cache() + end + + def update_source_data(user, source_data) do + user + |> cast(%{source_data: source_data}, [:source_data]) + |> update_and_set_cache() + end + @doc """ Changes `user.info` and returns the user changeset. @@ -1630,4 +1762,160 @@ def update_info(user, fun) do |> change_info(fun) |> update_and_set_cache() end + + def roles(%{is_moderator: is_moderator, is_admin: is_admin}) do + %{ + admin: is_admin, + moderator: is_moderator + } + end + + # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. + # For example: [{"name": "Pronoun", "value": "she/her"}, …] + def fields(%{fields: nil, source_data: %{"attachment" => attachment}}) do + limit = Pleroma.Config.get([:instance, :max_remote_account_fields], 0) + + attachment + |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) + |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + |> Enum.take(limit) + end + + def fields(%{fields: nil}), do: [] + + def fields(%{fields: fields}), do: fields + + def validate_fields(changeset, remote? \\ false) do + limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields + limit = Pleroma.Config.get([:instance, limit_name], 0) + + changeset + |> validate_length(:fields, max: limit) + |> validate_change(:fields, fn :fields, fields -> + if Enum.all?(fields, &valid_field?/1) do + [] + else + [fields: "invalid"] + end + end) + end + + defp valid_field?(%{"name" => name, "value" => value}) do + name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) + value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) + + is_binary(name) && is_binary(value) && String.length(name) <= name_limit && + String.length(value) <= value_limit + end + + defp valid_field?(_), do: false + + defp truncate_field(%{"name" => name, "value" => value}) do + {name, _chopped} = + String.split_at(name, Pleroma.Config.get([:instance, :account_field_name_length], 255)) + + {value, _chopped} = + String.split_at(value, Pleroma.Config.get([:instance, :account_field_value_length], 255)) + + %{"name" => name, "value" => value} + end + + def admin_api_update(user, params) do + user + |> cast(params, [ + :is_moderator, + :is_admin, + :show_role + ]) + |> update_and_set_cache() + end + + def mascot_update(user, url) do + user + |> cast(%{mascot: url}, [:mascot]) + |> validate_required([:mascot]) + |> update_and_set_cache() + end + + def mastodon_settings_update(user, settings) do + user + |> cast(%{settings: settings}, [:settings]) + |> validate_required([:settings]) + |> update_and_set_cache() + end + + @spec confirmation_changeset(User.t(), keyword()) :: Changeset.t() + def confirmation_changeset(user, need_confirmation: need_confirmation?) do + params = + if need_confirmation? do + %{ + confirmation_pending: true, + confirmation_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64() + } + else + %{ + confirmation_pending: false, + confirmation_token: nil + } + end + + cast(user, params, [:confirmation_pending, :confirmation_token]) + end + + def add_pinnned_activity(user, %Pleroma.Activity{id: id}) do + if id not in user.pinned_activities do + max_pinned_statuses = Pleroma.Config.get([:instance, :max_pinned_statuses], 0) + params = %{pinned_activities: user.pinned_activities ++ [id]} + + user + |> cast(params, [:pinned_activities]) + |> validate_length(:pinned_activities, + max: max_pinned_statuses, + message: "You have already pinned the maximum number of statuses" + ) + else + change(user) + end + |> update_and_set_cache() + end + + def remove_pinnned_activity(user, %Pleroma.Activity{id: id}) do + params = %{pinned_activities: List.delete(user.pinned_activities, id)} + + user + |> cast(params, [:pinned_activities]) + |> update_and_set_cache() + end + + def update_email_notifications(user, settings) do + email_notifications = + user.email_notifications + |> Map.merge(settings) + |> Map.take(["digest"]) + + params = %{email_notifications: email_notifications} + fields = [:email_notifications] + + user + |> cast(params, fields) + |> validate_required(fields) + |> update_and_set_cache() + end + + defp set_subscribers(user, subscribers) do + params = %{subscribers: subscribers} + + user + |> cast(params, [:subscribers]) + |> validate_required([:subscribers]) + |> update_and_set_cache() + end + + def add_to_subscribers(user, subscribed) do + set_subscribers(user, Enum.uniq([subscribed | user.subscribers])) + end + + def remove_from_subscribers(user, subscribed) do + set_subscribers(user, List.delete(user.subscribers, subscribed)) + end end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 4b5b43d7f..fe59ddeab 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -11,62 +11,11 @@ defmodule Pleroma.User.Info do @type t :: %__MODULE__{} embedded_schema do - field(:banner, :map, default: %{}) - field(:background, :map, default: %{}) - field(:source_data, :map, default: %{}) - field(:note_count, :integer, default: 0) - field(:follower_count, :integer, default: 0) - # Should be filled in only for remote users - field(:following_count, :integer, default: nil) - field(:locked, :boolean, default: false) - field(:confirmation_pending, :boolean, default: false) - field(:password_reset_pending, :boolean, default: false) - field(:confirmation_token, :string, default: nil) - field(:default_scope, :string, default: "public") 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: []) - field(:subscribers, {:array, :string}, default: []) - field(:deactivated, :boolean, default: false) - field(:no_rich_text, :boolean, default: false) - field(:ap_enabled, :boolean, default: false) - field(:is_moderator, :boolean, default: false) - field(:is_admin, :boolean, default: false) - field(:show_role, :boolean, default: true) - field(:keys, :string, default: nil) - field(:settings, :map, default: nil) - field(:magic_key, :string, default: nil) - field(:uri, :string, default: nil) - field(:topic, :string, default: nil) - field(:hub, :string, default: nil) - field(:salmon, :string, default: nil) - field(:hide_followers_count, :boolean, default: false) - field(:hide_follows_count, :boolean, default: false) - field(:hide_followers, :boolean, default: false) - field(:hide_follows, :boolean, default: false) - field(:hide_favorites, :boolean, default: true) - field(:unread_conversation_count, :integer, default: 0) - field(:pinned_activities, {:array, :string}, default: []) - field(:email_notifications, :map, default: %{"digest" => false}) - field(:mascot, :map, default: nil) - field(:emoji, {:array, :map}, default: []) - field(:pleroma_settings_store, :map, default: %{}) - field(:fields, {:array, :map}, default: nil) - field(:raw_fields, {:array, :map}, default: []) - field(:discoverable, :boolean, default: false) - - field(:notification_settings, :map, - default: %{ - "followers" => true, - "follows" => true, - "non_follows" => true, - "non_followers" => true - } - ) - - field(:skip_thread_containment, :boolean, default: false) # Found in the wild # ap_id -> Where is this used? @@ -77,84 +26,6 @@ defmodule Pleroma.User.Info do # subject _> Where is this used? end - def set_activation_status(info, deactivated) do - params = %{deactivated: deactivated} - - info - |> cast(params, [:deactivated]) - |> validate_required([:deactivated]) - end - - def set_password_reset_pending(info, pending) do - params = %{password_reset_pending: pending} - - info - |> cast(params, [:password_reset_pending]) - |> validate_required([:password_reset_pending]) - end - - def update_notification_settings(info, settings) do - settings = - settings - |> Enum.map(fn {k, v} -> {k, v in [true, "true", "True", "1"]} end) - |> Map.new() - - notification_settings = - info.notification_settings - |> Map.merge(settings) - |> Map.take(["followers", "follows", "non_follows", "non_followers"]) - - params = %{notification_settings: notification_settings} - - info - |> cast(params, [:notification_settings]) - |> validate_required([:notification_settings]) - end - - @doc """ - Update email notifications in the given User.Info struct. - - Examples: - - iex> update_email_notifications(%Pleroma.User.Info{email_notifications: %{"digest" => false}}, %{"digest" => true}) - %Pleroma.User.Info{email_notifications: %{"digest" => true}} - - """ - @spec update_email_notifications(t(), map()) :: Ecto.Changeset.t() - def update_email_notifications(info, settings) do - email_notifications = - info.email_notifications - |> Map.merge(settings) - |> Map.take(["digest"]) - - params = %{email_notifications: email_notifications} - fields = [:email_notifications] - - info - |> cast(params, fields) - |> validate_required(fields) - end - - def add_to_note_count(info, number) do - set_note_count(info, info.note_count + number) - end - - def set_note_count(info, number) do - params = %{note_count: Enum.max([0, number])} - - info - |> cast(params, [:note_count]) - |> validate_required([:note_count]) - end - - def set_follower_count(info, number) do - params = %{follower_count: Enum.max([0, number])} - - info - |> cast(params, [:follower_count]) - |> validate_required([:follower_count]) - end - def set_mutes(info, mutes) do params = %{mutes: mutes} @@ -181,14 +52,6 @@ def set_blocks(info, blocks) do |> validate_required([:blocks]) end - def set_subscribers(info, subscribers) do - params = %{subscribers: subscribers} - - info - |> cast(params, [:subscribers]) - |> validate_required([:subscribers]) - end - @spec add_to_mutes(Info.t(), String.t(), boolean()) :: Changeset.t() def add_to_mutes(info, muted, notifications?) do info @@ -214,14 +77,6 @@ def remove_from_block(info, blocked) do set_blocks(info, List.delete(info.blocks, blocked)) end - def add_to_subscribers(info, subscribed) do - set_subscribers(info, Enum.uniq([subscribed | info.subscribers])) - end - - def remove_from_subscribers(info, subscribed) do - set_subscribers(info, List.delete(info.subscribers, subscribed)) - end - def set_domain_blocks(info, domain_blocks) do params = %{domain_blocks: domain_blocks} @@ -238,205 +93,6 @@ def remove_from_domain_block(info, domain_blocked) do set_domain_blocks(info, List.delete(info.domain_blocks, domain_blocked)) end - def set_keys(info, keys) do - params = %{keys: keys} - - info - |> cast(params, [:keys]) - |> validate_required([:keys]) - end - - def remote_user_creation(info, params) do - params = - if Map.has_key?(params, :fields) do - Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1)) - else - params - end - - info - |> cast(params, [ - :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_fields(true) - end - - def user_upgrade(info, params, remote? \\ false) do - info - |> cast(params, [ - :ap_enabled, - :source_data, - :banner, - :locked, - :magic_key, - :follower_count, - :following_count, - :hide_follows, - :fields, - :hide_followers, - :discoverable, - :hide_followers_count, - :hide_follows_count - ]) - |> validate_fields(remote?) - end - - def profile_update(info, params) do - info - |> cast(params, [ - :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 - ]) - |> validate_fields() - end - - def validate_fields(changeset, remote? \\ false) do - limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields - limit = Pleroma.Config.get([:instance, limit_name], 0) - - changeset - |> validate_length(:fields, max: limit) - |> validate_change(:fields, fn :fields, fields -> - if Enum.all?(fields, &valid_field?/1) do - [] - else - [fields: "invalid"] - end - end) - end - - defp valid_field?(%{"name" => name, "value" => value}) do - name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) - value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) - - is_binary(name) && is_binary(value) && String.length(name) <= name_limit && - String.length(value) <= value_limit - end - - defp valid_field?(_), do: false - - defp truncate_field(%{"name" => name, "value" => value}) do - {name, _chopped} = - String.split_at(name, Pleroma.Config.get([:instance, :account_field_name_length], 255)) - - {value, _chopped} = - String.split_at(value, Pleroma.Config.get([:instance, :account_field_value_length], 255)) - - %{"name" => name, "value" => value} - end - - @spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t() - def confirmation_changeset(info, opts) do - need_confirmation? = Keyword.get(opts, :need_confirmation) - - params = - if need_confirmation? do - %{ - confirmation_pending: true, - confirmation_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64() - } - else - %{ - confirmation_pending: false, - confirmation_token: nil - } - end - - cast(info, params, [:confirmation_pending, :confirmation_token]) - end - - def mastodon_settings_update(info, settings) do - params = %{settings: settings} - - info - |> cast(params, [:settings]) - |> validate_required([:settings]) - end - - def mascot_update(info, url) do - params = %{mascot: url} - - info - |> cast(params, [:mascot]) - |> validate_required([:mascot]) - end - - def set_source_data(info, source_data) do - params = %{source_data: source_data} - - info - |> cast(params, [:source_data]) - |> validate_required([:source_data]) - end - - def admin_api_update(info, params) do - info - |> cast(params, [ - :is_moderator, - :is_admin, - :show_role - ]) - end - - def add_pinnned_activity(info, %Pleroma.Activity{id: id}) do - if id not in info.pinned_activities do - max_pinned_statuses = Pleroma.Config.get([:instance, :max_pinned_statuses], 0) - params = %{pinned_activities: info.pinned_activities ++ [id]} - - info - |> cast(params, [:pinned_activities]) - |> validate_length(:pinned_activities, - max: max_pinned_statuses, - message: "You have already pinned the maximum number of statuses" - ) - else - change(info) - end - end - - def remove_pinnned_activity(info, %Pleroma.Activity{id: id}) do - params = %{pinned_activities: List.delete(info.pinned_activities, id)} - - cast(info, params, [:pinned_activities]) - end - - def roles(%Info{is_moderator: is_moderator, is_admin: is_admin}) do - %{ - admin: is_admin, - moderator: is_moderator - } - end - def add_reblog_mute(info, ap_id) do params = %{muted_reblogs: info.muted_reblogs ++ [ap_id]} @@ -448,31 +104,4 @@ def remove_reblog_mute(info, ap_id) do cast(info, params, [:muted_reblogs]) end - - # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. - # For example: [{"name": "Pronoun", "value": "she/her"}, …] - def fields(%{fields: nil, source_data: %{"attachment" => attachment}}) do - limit = Pleroma.Config.get([:instance, :max_remote_account_fields], 0) - - attachment - |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) - |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) - |> Enum.take(limit) - end - - def fields(%{fields: nil}), do: [] - - def fields(%{fields: fields}), do: fields - - def follow_information_update(info, params) do - info - |> cast(params, [ - :hide_followers, - :hide_follows, - :follower_count, - :following_count, - :hide_followers_count, - :hide_follows_count - ]) - end end diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index 2baf016cf..7f5273c4e 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -56,7 +56,6 @@ defmodule Pleroma.User.Query do @ilike_criteria [:nickname, :name, :query] @equal_criteria [:email] - @role_criteria [:is_admin, :is_moderator] @contains_criteria [:ap_id, :nickname] @spec build(criteria()) :: Query.t() @@ -100,15 +99,19 @@ defp compose_query({:tags, tags}, query) when is_list(tags) and length(tags) > 0 Enum.reduce(tags, query, &prepare_tag_criteria/2) end - defp compose_query({key, _}, query) when key in @role_criteria do - where(query, [u], fragment("(?->? @> 'true')", u.info, ^to_string(key))) + defp compose_query({:is_admin, _}, query) do + where(query, [u], u.is_admin) + end + + defp compose_query({:is_moderator, _}, query) do + where(query, [u], u.is_moderator) end defp compose_query({:super_users, _}, query) do where( query, [u], - fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info) + u.is_admin or u.is_moderator ) end @@ -117,7 +120,13 @@ defp compose_query({:local, _}, query), do: location_query(query, true) defp compose_query({:external, _}, query), do: location_query(query, false) defp compose_query({:active, _}, query) do - where(query, [u], fragment("not (?->'deactivated' @> 'true')", u.info)) + User.restrict_deactivated(query) + |> where([u], not is_nil(u.nickname)) + end + + defp compose_query({:legacy_active, _}, query) do + query + |> where([u], fragment("not (?->'deactivated' @> 'true')", u.info)) |> where([u], not is_nil(u.nickname)) end @@ -126,7 +135,7 @@ defp compose_query({:deactivated, false}, query) do end defp compose_query({:deactivated, true}, query) do - where(query, [u], fragment("?->'deactivated' @> 'true'", u.info)) + where(query, [u], u.deactivated == ^true) |> where([u], not is_nil(u.nickname)) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 364452b5d..78efaae2a 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -68,7 +68,7 @@ defp get_recipients(data) do defp check_actor_is_active(actor) do if not is_nil(actor) do with user <- User.get_cached_by_ap_id(actor), - false <- user.info.deactivated do + false <- user.deactivated do true else _e -> false @@ -601,7 +601,7 @@ defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), defp restrict_thread_visibility( query, - %{"user" => %User{info: %{skip_thread_containment: true}}}, + %{"user" => %User{skip_thread_containment: true}}, _ ), do: query @@ -639,7 +639,7 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do |> Map.put("user", reading_user) |> Map.put("actor_id", user.ap_id) |> Map.put("whole_db", true) - |> Map.put("pinned_activity_ids", user.info.pinned_activities) + |> Map.put("pinned_activity_ids", user.pinned_activities) recipients = user_activities_recipients(%{ @@ -1049,14 +1049,12 @@ defp object_to_user_data(data) do user_data = %{ ap_id: data["id"], - info: %{ - ap_enabled: true, - source_data: data, - banner: banner, - fields: fields, - locked: locked, - discoverable: discoverable - }, + banner: banner, + discoverable: discoverable, + source_data: data, + fields: fields, + locked: locked, + ap_enabled: true, avatar: avatar, name: data["name"], follower_address: data["followers"], diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 080030eb5..568623318 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -137,7 +137,7 @@ def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "p with %User{} = user <- User.get_cached_by_nickname(nickname), {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user), {:show_follows, true} <- - {:show_follows, (for_user && for_user == user) || !user.info.hide_follows} do + {:show_follows, (for_user && for_user == user) || !user.hide_follows} do {page, _} = Integer.parse(page) conn @@ -174,7 +174,7 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "p with %User{} = user <- User.get_cached_by_nickname(nickname), {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user), {:show_followers, true} <- - {:show_followers, (for_user && for_user == user) || !user.info.hide_followers} do + {:show_followers, (for_user && for_user == user) || !user.hide_followers} do {page, _} = Integer.parse(page) conn @@ -387,7 +387,7 @@ def handle_user_activity(user, %{"type" => "Create"} = params) do def handle_user_activity(user, %{"type" => "Delete"} = params) do with %Object{} = object <- Object.normalize(params["object"]), - true <- user.info.is_moderator || user.ap_id == object.data["actor"], + true <- user.is_moderator || user.ap_id == object.data["actor"], {:ok, delete} <- ActivityPub.delete(object) do {:ok, delete} else diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex index b90193ca0..8abe18e29 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -11,7 +11,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do # has the user successfully posted before? defp old_user?(%User{} = u) do - u.info.note_count > 0 || u.info.follower_count > 0 + u.note_count > 0 || u.follower_count > 0 end # does the post contain links? diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 3866dacee..ebbc1e970 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -140,7 +140,7 @@ defp get_cc_ap_ids(ap_id, recipients) do |> Enum.map(& &1.ap_id) end - defp maybe_use_sharedinbox(%User{info: %{source_data: data}}), + defp maybe_use_sharedinbox(%User{source_data: data}), do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"] @doc """ @@ -156,7 +156,7 @@ defp maybe_use_sharedinbox(%User{info: %{source_data: data}}), """ def determine_inbox( %Activity{data: activity_data}, - %User{info: %{source_data: data}} = user + %User{source_data: data} = user ) do to = activity_data["to"] || [] cc = activity_data["cc"] || [] @@ -190,12 +190,12 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity) recipients |> Enum.filter(&User.ap_enabled?/1) - |> Enum.map(fn %{info: %{source_data: data}} -> data["inbox"] end) + |> Enum.map(fn %{source_data: data} -> data["inbox"] end) |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) |> Instances.filter_reachable() |> Enum.each(fn {inbox, unreachable_since} -> %User{ap_id: ap_id} = - Enum.find(recipients, fn %{info: %{source_data: data}} -> data["inbox"] == inbox end) + Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end) # Get all the recipients on the same host and add them to cc. Otherwise, a remote # instance would only accept a first message for the first recipient and ignore the rest. diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b56343beb..d0ad270c2 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -600,9 +600,8 @@ def handle_incoming( with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) - banner = new_user_data[:info][:banner] - locked = new_user_data[:info][:locked] || false - attachment = get_in(new_user_data, [:info, :source_data, "attachment"]) || [] + locked = new_user_data[:locked] || false + attachment = get_in(new_user_data, [:source_data, "attachment"]) || [] fields = attachment @@ -611,8 +610,9 @@ def handle_incoming( update_data = new_user_data - |> Map.take([:name, :bio, :avatar]) - |> Map.put(:info, %{banner: banner, locked: locked, fields: fields}) + |> Map.take([:avatar, :banner, :bio, :name]) + |> Map.put(:fields, fields) + |> Map.put(:locked, locked) actor |> User.upgrade_changeset(update_data, true) @@ -979,7 +979,7 @@ defp build_mention_tag(%{ap_id: ap_id, nickname: nickname} = _) do %{"type" => "Mention", "href" => ap_id, "name" => "@#{nickname}"} end - def take_emoji_tags(%User{info: %{emoji: emoji} = _user_info} = _user) do + def take_emoji_tags(%User{emoji: emoji}) do emoji |> Enum.flat_map(&Map.to_list/1) |> Enum.map(&build_emoji_tag/1) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 9b39d1629..82879a486 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -78,8 +78,8 @@ def render("user.json", %{user: user}) do emoji_tags = Transmogrifier.take_emoji_tags(user) fields = - user.info - |> User.Info.fields() + user + |> User.fields() |> Enum.map(fn %{"name" => name, "value" => value} -> %{ "name" => Pleroma.HTML.strip_tags(name), @@ -99,7 +99,7 @@ def render("user.json", %{user: user}) do "name" => user.name, "summary" => user.bio, "url" => user.ap_id, - "manuallyApprovesFollowers" => user.info.locked, + "manuallyApprovesFollowers" => user.locked, "publicKey" => %{ "id" => "#{user.ap_id}#main-key", "owner" => user.ap_id, @@ -107,8 +107,8 @@ def render("user.json", %{user: user}) do }, "endpoints" => endpoints, "attachment" => fields, - "tag" => (user.info.source_data["tag"] || []) ++ emoji_tags, - "discoverable" => user.info.discoverable + "tag" => (user.source_data["tag"] || []) ++ emoji_tags, + "discoverable" => user.discoverable } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) @@ -116,8 +116,8 @@ def render("user.json", %{user: user}) do end def render("following.json", %{user: user, page: page} = opts) do - showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_follows - showing_count = showing_items || !user.info.hide_follows_count + showing_items = (opts[:for] && opts[:for] == user) || !user.hide_follows + showing_count = showing_items || !user.hide_follows_count query = User.get_friends_query(user) query = from(user in query, select: [:ap_id]) @@ -135,8 +135,8 @@ def render("following.json", %{user: user, page: page} = opts) do end def render("following.json", %{user: user} = opts) do - showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_follows - showing_count = showing_items || !user.info.hide_follows_count + showing_items = (opts[:for] && opts[:for] == user) || !user.hide_follows + showing_count = showing_items || !user.hide_follows_count query = User.get_friends_query(user) query = from(user in query, select: [:ap_id]) @@ -155,7 +155,7 @@ def render("following.json", %{user: user} = opts) do "totalItems" => total, "first" => if showing_items do - collection(following, "#{user.ap_id}/following", 1, !user.info.hide_follows) + collection(following, "#{user.ap_id}/following", 1, !user.hide_follows) else "#{user.ap_id}/following?page=1" end @@ -164,8 +164,8 @@ def render("following.json", %{user: user} = opts) do end def render("followers.json", %{user: user, page: page} = opts) do - showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_followers - showing_count = showing_items || !user.info.hide_followers_count + showing_items = (opts[:for] && opts[:for] == user) || !user.hide_followers + showing_count = showing_items || !user.hide_followers_count query = User.get_followers_query(user) query = from(user in query, select: [:ap_id]) @@ -183,8 +183,8 @@ def render("followers.json", %{user: user, page: page} = opts) do end def render("followers.json", %{user: user} = opts) do - showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_followers - showing_count = showing_items || !user.info.hide_followers_count + showing_items = (opts[:for] && opts[:for] == user) || !user.hide_followers + showing_count = showing_items || !user.hide_followers_count query = User.get_followers_query(user) query = from(user in query, select: [:ap_id]) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 513bae800..3894b3742 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -234,9 +234,9 @@ def list_user_statuses(conn, %{"nickname" => nickname} = params) do def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do user = User.get_cached_by_nickname(nickname) - {:ok, updated_user} = User.deactivate(user, !user.info.deactivated) + {:ok, updated_user} = User.deactivate(user, !user.deactivated) - action = if user.info.deactivated, do: "activate", else: "deactivate" + action = if user.deactivated, do: "activate", else: "deactivate" ModerationLog.insert_log(%{ actor: admin, @@ -318,12 +318,12 @@ def right_add(%{assigns: %{user: admin}} = conn, %{ "nickname" => nickname }) when permission_group in ["moderator", "admin"] do - info = Map.put(%{}, "is_" <> permission_group, true) + fields = %{:"is_#{permission_group}" => true} {:ok, user} = nickname |> User.get_cached_by_nickname() - |> User.update_info(&User.Info.admin_api_update(&1, info)) + |> User.admin_api_update(fields) ModerationLog.insert_log(%{ action: "grant", @@ -332,7 +332,7 @@ def right_add(%{assigns: %{user: admin}} = conn, %{ permission: permission_group }) - json(conn, info) + json(conn, fields) end def right_add(conn, _) do @@ -344,8 +344,8 @@ def right_get(conn, %{"nickname" => nickname}) do conn |> json(%{ - is_moderator: user.info.is_moderator, - is_admin: user.info.is_admin + is_moderator: user.is_moderator, + is_admin: user.is_admin }) end @@ -361,12 +361,12 @@ def right_delete( } ) when permission_group in ["moderator", "admin"] do - info = Map.put(%{}, "is_" <> permission_group, false) + fields = %{:"is_#{permission_group}" => false} {:ok, user} = nickname |> User.get_cached_by_nickname() - |> User.update_info(&User.Info.admin_api_update(&1, info)) + |> User.admin_api_update(fields) ModerationLog.insert_log(%{ action: "revoke", @@ -375,7 +375,7 @@ def right_delete( permission: permission_group }) - json(conn, info) + json(conn, fields) end def right_delete(conn, _) do @@ -389,7 +389,7 @@ def set_activation_status(%{assigns: %{user: admin}} = conn, %{ with {:ok, status} <- Ecto.Type.cast(:boolean, status), %User{} = user <- User.get_cached_by_nickname(nickname), {:ok, _} <- User.deactivate(user, !status) do - action = if(user.info.deactivated, do: "activate", else: "deactivate") + action = if(user.deactivated, do: "activate", else: "deactivate") ModerationLog.insert_log(%{ actor: admin, diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index a96affd40..eed1b9fa7 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -7,7 +7,6 @@ defmodule Pleroma.Web.AdminAPI.AccountView do alias Pleroma.HTML alias Pleroma.User - alias Pleroma.User.Info alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.MediaProxy @@ -28,9 +27,9 @@ def render("show.json", %{user: user}) do "avatar" => avatar, "nickname" => user.nickname, "display_name" => display_name, - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "local" => user.local, - "roles" => Info.roles(user.info), + "roles" => User.roles(user), "tags" => user.tags || [] } end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 386408d51..ef738a870 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -263,10 +263,10 @@ defp maybe_create_activity_expiration(result, _), do: result # Updates the emojis for a user based on their profile def update(user) do emoji = emoji_from_profile(user) - source_data = user.info |> Map.get(:source_data, %{}) |> Map.put("tag", emoji) + source_data = Map.put(user.source_data, "tag", emoji) user = - case User.update_info(user, &User.Info.set_source_data(&1, source_data)) do + case User.update_source_data(user, source_data) do {:ok, user} -> user _ -> user end @@ -287,20 +287,20 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do object: %Object{data: %{"type" => "Note"}} } = activity <- get_by_id_or_ap_id(id_or_ap_id), true <- Visibility.is_public?(activity), - {:ok, _user} <- User.update_info(user, &User.Info.add_pinnned_activity(&1, activity)) do + {:ok, _user} <- User.add_pinnned_activity(user, activity) do {:ok, activity} else - {:error, %{changes: %{info: %{errors: [pinned_activities: {err, _}]}}}} -> {:error, err} + {:error, %{errors: [pinned_activities: {err, _}]}} -> {:error, err} _ -> {:error, dgettext("errors", "Could not pin")} end end def unpin(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), - {:ok, _user} <- User.update_info(user, &User.Info.remove_pinnned_activity(&1, activity)) do + {:ok, _user} <- User.remove_pinnned_activity(user, activity) do {:ok, activity} else - %{errors: [pinned_activities: {err, _}]} -> {:error, err} + {:error, %{errors: [pinned_activities: {err, _}]}} -> {:error, err} _ -> {:error, dgettext("errors", "Could not unpin")} end end diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex index 87860f1d5..cf0fe91ce 100644 --- a/lib/pleroma/web/masto_fe_controller.ex +++ b/lib/pleroma/web/masto_fe_controller.ex @@ -36,7 +36,7 @@ def index(%{assigns: %{user: user}} = conn, _params) do @doc "PUT /api/web/settings" def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do - with {:ok, _} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do + with {:ok, _} <- User.mastodon_settings_update(user, settings) do json(conn, %{}) else e -> diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 9ef7fd48d..7ba2f9ff1 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -130,25 +130,6 @@ def verify_credentials(%{assigns: %{user: user}} = conn, _) do def update_credentials(%{assigns: %{user: original_user}} = conn, params) do user = original_user - user_params = - %{} - |> add_if_present(params, "display_name", :name) - |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end) - |> add_if_present(params, "avatar", :avatar, fn value -> - with %Plug.Upload{} <- value, - {:ok, object} <- ActivityPub.upload(value, type: :avatar) do - {:ok, object.data} - end - end) - - emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "") - - user_info_emojis = - user.info - |> Map.get(:emoji, []) - |> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text)) - |> Enum.dedup() - params = if Map.has_key?(params, "fields_attributes") do Map.update!(params, "fields_attributes", fn fields -> @@ -160,7 +141,7 @@ def update_credentials(%{assigns: %{user: original_user}} = conn, params) do params end - info_params = + user_params = [ :no_rich_text, :locked, @@ -176,15 +157,13 @@ def update_credentials(%{assigns: %{user: original_user}} = conn, params) do |> Enum.reduce(%{}, fn key, acc -> add_if_present(acc, params, to_string(key), key, &{:ok, truthy_param?(&1)}) end) - |> add_if_present(params, "default_scope", :default_scope) - |> add_if_present(params, "fields_attributes", :fields, fn fields -> - fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) - - {:ok, fields} - end) - |> add_if_present(params, "fields_attributes", :raw_fields) - |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value -> - {:ok, Map.merge(user.info.pleroma_settings_store, value)} + |> add_if_present(params, "display_name", :name) + |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end) + |> add_if_present(params, "avatar", :avatar, fn value -> + with %Plug.Upload{} <- value, + {:ok, object} <- ActivityPub.upload(value, type: :avatar) do + {:ok, object.data} + end end) |> add_if_present(params, "header", :banner, fn value -> with %Plug.Upload{} <- value, @@ -198,12 +177,31 @@ def update_credentials(%{assigns: %{user: original_user}} = conn, params) do {:ok, object.data} end end) - |> Map.put(:emoji, user_info_emojis) + |> add_if_present(params, "fields_attributes", :fields, fn fields -> + fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) + + {:ok, fields} + end) + |> add_if_present(params, "fields_attributes", :raw_fields) + |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value -> + {:ok, Map.merge(user.pleroma_settings_store, value)} + end) + |> add_if_present(params, "default_scope", :default_scope) + + emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "") + + user_emojis = + user + |> Map.get(:emoji, []) + |> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text)) + |> Enum.dedup() + + user_params = Map.put(user_params, :emoji, user_emojis) changeset = user |> User.update_changeset(user_params) - |> User.change_info(&User.Info.profile_update(&1, info_params)) + |> User.change_info(& &1) with {:ok, user} <- User.update_and_set_cache(changeset) do if original_user != user, do: CommonAPI.update(user) @@ -269,7 +267,7 @@ def followers(%{assigns: %{user: for_user, account: user}} = conn, params) do followers = cond do for_user && user.id == for_user.id -> MastodonAPI.get_followers(user, params) - user.info.hide_followers -> [] + user.hide_followers -> [] true -> MastodonAPI.get_followers(user, params) end @@ -283,7 +281,7 @@ def following(%{assigns: %{user: for_user, account: user}} = conn, params) do followers = cond do for_user && user.id == for_user.id -> MastodonAPI.get_friends(user, params) - user.info.hide_follows -> [] + user.hide_follows -> [] true -> MastodonAPI.get_friends(user, params) end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 2d4976891..e30fed610 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -74,23 +74,23 @@ defp do_render("show.json", %{user: user} = opts) do user_info = User.get_cached_user_info(user) following_count = - if !user.info.hide_follows_count or !user.info.hide_follows or opts[:for] == user do + if !user.hide_follows_count or !user.hide_follows or opts[:for] == user do user_info.following_count else 0 end followers_count = - if !user.info.hide_followers_count or !user.info.hide_followers or opts[:for] == user do + if !user.hide_followers_count or !user.hide_followers or opts[:for] == user do user_info.follower_count else 0 end - bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"] + bot = (user.source_data["type"] || "Person") in ["Application", "Service"] emojis = - (user.info.source_data["tag"] || []) + (user.source_data["tag"] || []) |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> %{ @@ -102,8 +102,8 @@ defp do_render("show.json", %{user: user} = opts) do end) fields = - user.info - |> User.Info.fields() + user + |> User.fields() |> Enum.map(fn %{"name" => name, "value" => value} -> %{ "name" => Pleroma.HTML.strip_tags(name), @@ -111,23 +111,19 @@ defp do_render("show.json", %{user: user} = opts) do } end) - raw_fields = Map.get(user.info, :raw_fields, []) - bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for])) relationship = render("relationship.json", %{user: opts[:for], target: user}) - discoverable = user.info.discoverable - %{ id: to_string(user.id), username: username_from_nickname(user.nickname), acct: user.nickname, display_name: display_name, - locked: user_info.locked, + locked: user.locked, created_at: Utils.to_masto_date(user.inserted_at), followers_count: followers_count, following_count: following_count, - statuses_count: user_info.note_count, + statuses_count: user.note_count, note: bio || "", url: User.profile_url(user), avatar: image, @@ -140,9 +136,9 @@ defp do_render("show.json", %{user: user} = opts) do source: %{ note: HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), sensitive: false, - fields: raw_fields, + fields: user.raw_fields, pleroma: %{ - discoverable: discoverable + discoverable: user.discoverable } }, @@ -150,14 +146,14 @@ defp do_render("show.json", %{user: user} = opts) do pleroma: %{ confirmation_pending: user_info.confirmation_pending, tags: user.tags, - hide_followers_count: user.info.hide_followers_count, - hide_follows_count: user.info.hide_follows_count, - hide_followers: user.info.hide_followers, - hide_follows: user.info.hide_follows, - hide_favorites: user.info.hide_favorites, + hide_followers_count: user.hide_followers_count, + hide_follows_count: user.hide_follows_count, + hide_followers: user.hide_followers, + hide_follows: user.hide_follows, + hide_favorites: user.hide_favorites, relationship: relationship, - skip_thread_containment: user.info.skip_thread_containment, - background_image: image_url(user.info.background) |> MediaProxy.url() + skip_thread_containment: user.skip_thread_containment, + background_image: image_url(user.background) |> MediaProxy.url() } } |> maybe_put_role(user, opts[:for]) @@ -195,21 +191,21 @@ defp maybe_put_settings( data, %User{id: user_id} = user, %User{id: user_id}, - user_info + _user_info ) do data - |> Kernel.put_in([:source, :privacy], user_info.default_scope) - |> Kernel.put_in([:source, :pleroma, :show_role], user.info.show_role) - |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.info.no_rich_text) + |> Kernel.put_in([:source, :privacy], user.default_scope) + |> Kernel.put_in([:source, :pleroma, :show_role], user.show_role) + |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text) end defp maybe_put_settings(data, _, _, _), do: data - defp maybe_put_settings_store(data, %User{info: info, id: id}, %User{id: id}, %{ + defp maybe_put_settings_store(data, %User{} = user, %User{}, %{ with_pleroma_settings: true }) do data - |> Kernel.put_in([:pleroma, :settings_store], info.pleroma_settings_store) + |> Kernel.put_in([:pleroma, :settings_store], user.pleroma_settings_store) end defp maybe_put_settings_store(data, _, _, _), do: data @@ -223,28 +219,28 @@ defp maybe_put_chat_token(data, %User{id: id}, %User{id: id}, %{ defp maybe_put_chat_token(data, _, _, _), do: data - defp maybe_put_role(data, %User{info: %{show_role: true}} = user, _) do + defp maybe_put_role(data, %User{show_role: true} = user, _) do data - |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin) - |> Kernel.put_in([:pleroma, :is_moderator], user.info.is_moderator) + |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) + |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) end defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do data - |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin) - |> Kernel.put_in([:pleroma, :is_moderator], user.info.is_moderator) + |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) + |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) end defp maybe_put_role(data, _, _), do: data defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do - Kernel.put_in(data, [:pleroma, :notification_settings], user.info.notification_settings) + Kernel.put_in(data, [:pleroma, :notification_settings], user.notification_settings) end defp maybe_put_notification_settings(data, _, _), do: data - defp maybe_put_activation_status(data, user, %User{info: %{is_admin: true}}) do - Kernel.put_in(data, [:pleroma, :deactivated], user.info.deactivated) + defp maybe_put_activation_status(data, user, %User{is_admin: true}) do + Kernel.put_in(data, [:pleroma, :deactivated], user.deactivated) end defp maybe_put_activation_status(data, _, _), do: data @@ -253,7 +249,7 @@ defp maybe_put_unread_conversation_count(data, %User{id: user_id} = user, %User{ data |> Kernel.put_in( [:pleroma, :unread_conversation_count], - user.info.unread_conversation_count + user.unread_conversation_count ) end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 9b8dd3086..b785ca9d4 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -498,6 +498,6 @@ defp present?(nil), do: false defp present?(false), do: false defp present?(_), do: true - defp pinned?(%Activity{id: id}, %User{info: %{pinned_activities: pinned_activities}}), + defp pinned?(%Activity{id: id}, %User{pinned_activities: pinned_activities}), do: id in pinned_activities end diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 03c9a5027..fe71aca8c 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -202,9 +202,9 @@ def token_exchange( with {:ok, %User{} = user} <- Authenticator.get_user(conn), {:ok, app} <- Token.Utils.fetch_app(conn), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, - {:user_active, true} <- {:user_active, !user.info.deactivated}, + {:user_active, true} <- {:user_active, !user.deactivated}, {:password_reset_pending, false} <- - {:password_reset_pending, user.info.password_reset_pending}, + {:password_reset_pending, user.password_reset_pending}, {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do diff --git a/lib/pleroma/web/ostatus/handlers/follow_handler.ex b/lib/pleroma/web/ostatus/handlers/follow_handler.ex index 24513972e..483099d34 100644 --- a/lib/pleroma/web/ostatus/handlers/follow_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/follow_handler.ex @@ -14,7 +14,7 @@ def handle(entry, doc) do followed_uri when not is_nil(followed_uri) <- XML.string_from_xpath("/entry/activity:object/id", entry), {:ok, followed} <- OStatus.find_or_make_user(followed_uri), - {:locked, false} <- {:locked, followed.info.locked}, + {:locked, false} <- {:locked, followed.locked}, {:ok, activity} <- ActivityPub.follow(actor, followed, id, false) do User.follow(actor, followed) {:ok, activity} diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 5de1ceef3..a11cacacc 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -287,14 +287,19 @@ def make_user(uri, update \\ false) do end defp build_user_data(info) do - %{ + info_fields = Enum.map(User.info_fields(), &to_string/1) + + info + |> Map.take(info_fields) + |> Map.new(fn {k, v} -> {String.to_atom(k), v} end) + |> Map.merge(%{ name: info["name"], nickname: info["nickname"] <> "@" <> info["host"], ap_id: info["uri"], info: info, avatar: info["avatar"], bio: info["bio"] - } + }) end # TODO: Just takes the first one for now. diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 9012e2175..ee40bbf33 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -80,9 +80,7 @@ def update_avatar(%{assigns: %{user: user}} = conn, params) do @doc "PATCH /api/v1/pleroma/accounts/update_banner" def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do - new_info = %{"banner" => %{}} - - with {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do + with {:ok, user} <- User.update_banner(user, %{}) do CommonAPI.update(user) json(conn, %{url: nil}) end @@ -90,8 +88,7 @@ def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do def update_banner(%{assigns: %{user: user}} = conn, params) do with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner), - new_info <- %{"banner" => object.data}, - {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do + {:ok, user} <- User.update_banner(user, object.data) do CommonAPI.update(user) %{"url" => [%{"href" => href} | _]} = object.data @@ -101,17 +98,14 @@ def update_banner(%{assigns: %{user: user}} = conn, params) do @doc "PATCH /api/v1/pleroma/accounts/update_background" def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do - new_info = %{"background" => %{}} - - with {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do + with {:ok, _user} <- User.update_background(user, %{}) do json(conn, %{url: nil}) end end def update_background(%{assigns: %{user: user}} = conn, params) do with {:ok, object} <- ActivityPub.upload(params, type: :background), - new_info <- %{"background" => object.data}, - {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do + {:ok, _user} <- User.update_background(user, object.data) do %{"url" => [%{"href" => href} | _]} = object.data json(conn, %{url: href}) @@ -119,7 +113,7 @@ def update_background(%{assigns: %{user: user}} = conn, params) do end @doc "GET /api/v1/pleroma/accounts/:id/favourites" - def favourites(%{assigns: %{account: %{info: %{hide_favorites: true}}}} = conn, _params) do + def favourites(%{assigns: %{account: %{hide_favorites: true}}} = conn, _params) do render_error(conn, :forbidden, "Can't get favorites") end diff --git a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex index d71d72dd5..8cf552b7e 100644 --- a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex @@ -24,9 +24,7 @@ def update(%{assigns: %{user: user}} = conn, %{"file" => file}) do with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), # Reject if not an image %{type: "image"} = attachment <- render_attachment(object) do - # Sure! - # Save to the user's info - {:ok, _user} = User.update_info(user, &User.Info.mascot_update(&1, attachment)) + {:ok, _user} = User.mascot_update(user, attachment) json(conn, attachment) else diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 0ffe903cd..0361c18da 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -147,7 +147,7 @@ def remote_users(%User{id: user_id}, %{data: %{"to" => to} = data}) do end @doc "Pushes an activity to remote account." - def publish_one(%{recipient: %{info: %{salmon: salmon}}} = params), + def publish_one(%{recipient: %{salmon: salmon}} = params), do: publish_one(Map.put(params, :recipient, salmon)) def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do @@ -217,19 +217,19 @@ def publish(%{keys: keys} = user, %{data: %{"type" => type}} = activity) remote_users = remote_users(user, activity) - salmon_urls = Enum.map(remote_users, & &1.info.salmon) + salmon_urls = Enum.map(remote_users, & &1.salmon) reachable_urls_metadata = Instances.filter_reachable(salmon_urls) reachable_urls = Map.keys(reachable_urls_metadata) remote_users - |> Enum.filter(&(&1.info.salmon in reachable_urls)) + |> Enum.filter(&(&1.salmon in reachable_urls)) |> Enum.each(fn remote_user -> Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end) Publisher.enqueue_one(__MODULE__, %{ recipient_id: remote_user.id, feed: feed, - unreachable_since: reachable_urls_metadata[remote_user.info.salmon] + unreachable_since: reachable_urls_metadata[remote_user.salmon] }) end) end diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex index 0ea224874..9910c3484 100644 --- a/lib/pleroma/web/streamer/worker.ex +++ b/lib/pleroma/web/streamer/worker.ex @@ -212,7 +212,7 @@ def push_to_socket(topics, topic, item) do end @spec thread_containment(Activity.t(), User.t()) :: boolean() - defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + defp thread_containment(_activity, %User{skip_thread_containment: true}), do: true defp thread_containment(activity, user) do if Config.get([:instance, :skip_thread_containment]) do diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index bf5a6ae42..5eafc01de 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -20,11 +20,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do action_fallback(:errors) def confirm_email(conn, %{"user_id" => uid, "token" => token}) do - new_info = [need_confirmation: false] - - with %User{info: info} = user <- User.get_cached_by_id(uid), - true <- user.local and info.confirmation_pending and info.confirmation_token == token, - {:ok, _} <- User.update_info(user, &User.Info.confirmation_changeset(&1, new_info)) do + with %User{} = user <- User.get_cached_by_id(uid), + true <- user.local and user.confirmation_pending and user.confirmation_token == token, + {:ok, _} <- + User.update_and_set_cache(User.confirmation_changeset(user, need_confirmation: false)) do redirect(conn, to: "/") end end diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex index 21b086d4c..10cba9b3b 100644 --- a/lib/pleroma/web/views/masto_fe_view.ex +++ b/lib/pleroma/web/views/masto_fe_view.ex @@ -61,12 +61,12 @@ def initial_state(token, user, custom_emojis) do }, poll_limits: Config.get([:instance, :poll_limits]), rights: %{ - delete_others_notice: present?(user.info.is_moderator), - admin: present?(user.info.is_admin) + delete_others_notice: present?(user.is_moderator), + admin: present?(user.is_admin) }, compose: %{ me: "#{user.id}", - default_privacy: user.info.default_scope, + default_privacy: user.default_scope, default_sensitive: false, allow_content_types: Config.get([:instance, :allowed_post_formats]) }, @@ -86,7 +86,7 @@ def initial_state(token, user, custom_emojis) do "video\/mp4" ] }, - settings: user.info.settings || @default_settings, + settings: user.settings || @default_settings, push_subscription: nil, accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)}, custom_emojis: render(CustomEmojiView, "index.json", custom_emojis: custom_emojis), diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index b61f388b8..0f98ec4fd 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -181,7 +181,7 @@ defp valid_topic(%{"hub.topic" => topic}, user) do end def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do - topic = subscribed.info.topic + topic = subscribed.topic # FIXME: Race condition, use transactions {:ok, subscription} = with subscription when not is_nil(subscription) <- @@ -193,7 +193,7 @@ def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do _e -> subscription = %WebsubClientSubscription{ topic: topic, - hub: subscribed.info.hub, + hub: subscribed.hub, subscribers: [subscriber.ap_id], state: "requested", secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64(), diff --git a/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs b/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs index 779aa382e..a5170d521 100644 --- a/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs +++ b/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs @@ -5,7 +5,11 @@ defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do def change do query = - User.external_users_query() + User.Query.build(%{ + external: true, + legacy_active: true, + order_by: :id + }) |> select([u], struct(u, [:id, :ap_id, :info])) Pleroma.Repo.stream(query) diff --git a/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs b/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs index bc4e828cc..dbddac516 100644 --- a/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs +++ b/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs @@ -1,6 +1,5 @@ defmodule Pleroma.Repo.Migrations.CopyMutedToMutedNotifications do use Ecto.Migration - alias Pleroma.User def change do execute( diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs new file mode 100644 index 000000000..b26b122eb --- /dev/null +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -0,0 +1,54 @@ +defmodule Pleroma.Repo.Migrations.CopyUsersInfoaddsToUsers do + use Ecto.Migration + + def change do + alter table(:users) do + add(:banner, :map, default: %{}) + add(:background, :map, default: %{}) + add(:source_data, :map, default: %{}) + add(:note_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(:locked, :boolean, default: false) + add(:confirmation_pending, :boolean, default: false) + add(:password_reset_pending, :boolean, default: false) + add(:confirmation_token, :text, default: nil) + add(:default_scope, :string, default: "public") + add(:blocks, {:array, :text}, default: []) + add(:domain_blocks, {:array, :text}, default: []) + add(:mutes, {:array, :text}, default: []) + add(:muted_reblogs, {:array, :text}, default: []) + add(:muted_notifications, {:array, :text}, default: []) + add(:subscribers, {:array, :text}, default: []) + add(:deactivated, :boolean, default: false, null: false) + add(:no_rich_text, :boolean, default: false, null: false) + add(:ap_enabled, :boolean, default: false, null: false) + add(:is_moderator, :boolean, default: false, null: false) + add(:is_admin, :boolean, default: false, null: false) + add(:show_role, :boolean, default: true, null: false) + add(:settings, :map, default: nil) + add(:magic_key, :text, default: nil) + add(:uri, :text, default: nil) + add(:topic, :text, default: nil) + add(:hub, :text, default: nil) + add(:salmon, :text, default: nil) + add(:hide_followers_count, :boolean, default: false, null: false) + add(:hide_follows_count, :boolean, default: false, null: false) + add(:hide_followers, :boolean, default: false, null: false) + add(:hide_follows, :boolean, default: false, null: false) + add(:hide_favorites, :boolean, default: true, null: false) + add(:unread_conversation_count, :integer, default: 0) + add(:pinned_activities, {:array, :text}, default: []) + add(:email_notifications, :map, default: %{"digest" => false}) + add(:mascot, :map, default: nil) + add(:emoji, {:array, :map}, default: []) + add(:pleroma_settings_store, :map, default: %{}) + add(:fields, {:array, :map}, default: nil) + add(:raw_fields, {:array, :map}, default: []) + add(:discoverable, :boolean, default: false, null: false) + add(:notification_settings, :map, default: %{}) + add(:skip_thread_containment, :boolean, default: false, null: false) + end + end +end diff --git a/test/daemons/digest_email_daemon_test.exs b/test/daemons/digest_email_daemon_test.exs index 3168f3b9a..faf592d5f 100644 --- a/test/daemons/digest_email_daemon_test.exs +++ b/test/daemons/digest_email_daemon_test.exs @@ -20,7 +20,7 @@ test "it sends digest emails" do |> Timex.to_naive_datetime() user2 = insert(:user, last_digest_emailed_at: date) - User.switch_email_notifications(user2, "digest", true) + {:ok, _} = User.switch_email_notifications(user2, "digest", true) CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}!"}) DigestEmailDaemon.perform() diff --git a/test/emails/user_email_test.exs b/test/emails/user_email_test.exs index 963565f7c..9e145977e 100644 --- a/test/emails/user_email_test.exs +++ b/test/emails/user_email_test.exs @@ -36,7 +36,7 @@ test "build user invitation email" do test "build account confirmation email" do config = Pleroma.Config.get(:instance) - user = insert(:user, info: %Pleroma.User.Info{confirmation_token: "conf-token"}) + user = insert(:user, confirmation_token: "conf-token") email = UserEmail.account_confirmation_email(user) assert email.from == {config[:name], config[:notify_email]} assert email.to == [{user.name, user.email}] diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 3bff51527..087bdbcc2 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -125,10 +125,10 @@ test "gives a replacement for user links, using local nicknames in user links te gsimg = insert(:user, %{nickname: "gsimg"}) archaeme = - insert(:user, %{ + insert(:user, nickname: "archa_eme_", - info: %User.Info{source_data: %{"url" => "https://archeme/@archa_eme_"}} - }) + source_data: %{"url" => "https://archeme/@archa_eme_"} + ) archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) diff --git a/test/moderation_log_test.exs b/test/moderation_log_test.exs index a39a00e02..6363db5aa 100644 --- a/test/moderation_log_test.exs +++ b/test/moderation_log_test.exs @@ -12,8 +12,8 @@ defmodule Pleroma.ModerationLogTest do describe "user moderation" do setup do - admin = insert(:user, info: %{is_admin: true}) - moderator = insert(:user, info: %{is_moderator: true}) + admin = insert(:user, is_admin: true) + moderator = insert(:user, is_moderator: true) subject1 = insert(:user) subject2 = insert(:user) diff --git a/test/notification_test.exs b/test/notification_test.exs index 54c0f9877..ddd7ae307 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -136,7 +136,7 @@ test "it creates a notification for an activity from a muted thread" do test "it disables notifications from followers" do follower = insert(:user) - followed = insert(:user, info: %{notification_settings: %{"followers" => false}}) + followed = insert(:user, notification_settings: %{"followers" => false}) User.follow(follower, followed) {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"}) refute Notification.create_notification(activity, followed) @@ -144,13 +144,13 @@ test "it disables notifications from followers" do test "it disables notifications from non-followers" do follower = insert(:user) - followed = insert(:user, info: %{notification_settings: %{"non_followers" => false}}) + followed = insert(:user, notification_settings: %{"non_followers" => false}) {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"}) refute Notification.create_notification(activity, followed) end test "it disables notifications from people the user follows" do - follower = insert(:user, info: %{notification_settings: %{"follows" => false}}) + follower = insert(:user, notification_settings: %{"follows" => false}) followed = insert(:user) User.follow(follower, followed) follower = Repo.get(User, follower.id) @@ -159,7 +159,7 @@ test "it disables notifications from people the user follows" do end test "it disables notifications from people the user does not follow" do - follower = insert(:user, info: %{notification_settings: %{"non_follows" => false}}) + follower = insert(:user, notification_settings: %{"non_follows" => false}) followed = insert(:user) {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"}) refute Notification.create_notification(activity, follower) diff --git a/test/plugs/admin_secret_authentication_plug_test.exs b/test/plugs/admin_secret_authentication_plug_test.exs index e1d4b391f..c94a62c10 100644 --- a/test/plugs/admin_secret_authentication_plug_test.exs +++ b/test/plugs/admin_secret_authentication_plug_test.exs @@ -37,6 +37,6 @@ test "with secret set and given in the 'admin_token' parameter, it assigns an ad %{conn | params: %{"admin_token" => "password123"}} |> AdminSecretAuthenticationPlug.call(%{}) - assert conn.assigns[:user].info.is_admin + assert conn.assigns[:user].is_admin end end diff --git a/test/plugs/user_enabled_plug_test.exs b/test/plugs/user_enabled_plug_test.exs index c0fafcab1..996a7d77b 100644 --- a/test/plugs/user_enabled_plug_test.exs +++ b/test/plugs/user_enabled_plug_test.exs @@ -17,7 +17,7 @@ test "doesn't do anything if the user isn't set", %{conn: conn} do end test "with a user that is deactivated, it removes that user", %{conn: conn} do - user = insert(:user, info: %{deactivated: true}) + user = insert(:user, deactivated: true) conn = conn diff --git a/test/plugs/user_is_admin_plug_test.exs b/test/plugs/user_is_admin_plug_test.exs index 9e05fff18..136dcc54e 100644 --- a/test/plugs/user_is_admin_plug_test.exs +++ b/test/plugs/user_is_admin_plug_test.exs @@ -9,7 +9,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlugTest do import Pleroma.Factory test "accepts a user that is admin" do - user = insert(:user, info: %{is_admin: true}) + user = insert(:user, is_admin: true) conn = build_conn() diff --git a/test/signature_test.exs b/test/signature_test.exs index 96c8ba07a..ada1b1054 100644 --- a/test/signature_test.exs +++ b/test/signature_test.exs @@ -42,7 +42,7 @@ defp make_fake_conn(key_id), test "it returns key" do expected_result = {:ok, @rsa_public_key} - user = insert(:user, %{info: %{source_data: %{"publicKey" => @public_key}}}) + user = insert(:user, source_data: %{"publicKey" => @public_key}) assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == expected_result end @@ -54,7 +54,7 @@ test "it returns error when not found user" do end test "it returns error if public key is empty" do - user = insert(:user, %{info: %{source_data: %{"publicKey" => %{}}}}) + user = insert(:user, source_data: %{"publicKey" => %{}}) assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == {:error, :error} end diff --git a/test/tasks/count_statuses_test.exs b/test/tasks/count_statuses_test.exs index 6035da3c3..bb5dc88f8 100644 --- a/test/tasks/count_statuses_test.exs +++ b/test/tasks/count_statuses_test.exs @@ -22,18 +22,18 @@ test "counts statuses" do user = refresh_record(user) user2 = refresh_record(user2) - assert %{info: %{note_count: 2}} = user - assert %{info: %{note_count: 1}} = user2 + assert %{note_count: 2} = user + assert %{note_count: 1} = user2 - {:ok, user} = User.update_info(user, &User.Info.set_note_count(&1, 0)) - {:ok, user2} = User.update_info(user2, &User.Info.set_note_count(&1, 0)) + {:ok, user} = User.update_note_count(user, 0) + {:ok, user2} = User.update_note_count(user2, 0) - assert %{info: %{note_count: 0}} = user - assert %{info: %{note_count: 0}} = user2 + assert %{note_count: 0} = user + assert %{note_count: 0} = user2 assert capture_io(fn -> Mix.Tasks.Pleroma.CountStatuses.run([]) end) == "Done\n" - assert %{info: %{note_count: 2}} = refresh_record(user) - assert %{info: %{note_count: 1}} = refresh_record(user2) + assert %{note_count: 2} = refresh_record(user) + assert %{note_count: 1} = refresh_record(user2) end end diff --git a/test/tasks/database_test.exs b/test/tasks/database_test.exs index b63dcac00..b66324e5e 100644 --- a/test/tasks/database_test.exs +++ b/test/tasks/database_test.exs @@ -72,26 +72,25 @@ test "it prunes old objects from the database" do describe "running update_users_following_followers_counts" do test "following and followers count are updated" do [user, user2] = insert_pair(:user) - {:ok, %User{following: following, info: info} = user} = User.follow(user, user2) + {:ok, %User{following: following} = user} = User.follow(user, user2) assert length(following) == 2 - assert info.follower_count == 0 + assert user.follower_count == 0 {:ok, user} = user - |> Ecto.Changeset.change(%{following: following ++ following}) - |> User.change_info(&Ecto.Changeset.change(&1, %{follower_count: 3})) + |> Ecto.Changeset.change(%{following: following ++ following, follower_count: 3}) |> Repo.update() assert length(user.following) == 4 - assert user.info.follower_count == 3 + assert user.follower_count == 3 assert :ok == Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"]) user = User.get_by_id(user.id) assert length(user.following) == 2 - assert user.info.follower_count == 0 + assert user.follower_count == 0 end end diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs index cf12d9ed6..f024f92ae 100644 --- a/test/tasks/user_test.exs +++ b/test/tasks/user_test.exs @@ -58,8 +58,8 @@ test "user is created" do assert user.name == unsaved.name assert user.email == unsaved.email assert user.bio == unsaved.bio - assert user.info.is_moderator - assert user.info.is_admin + assert user.is_moderator + assert user.is_admin end test "user is not created" do @@ -113,11 +113,11 @@ test "user is deactivated" do assert message =~ " deactivated" user = User.get_cached_by_nickname(user.nickname) - assert user.info.deactivated + assert user.deactivated end test "user is activated" do - user = insert(:user, info: %{deactivated: true}) + user = insert(:user, deactivated: true) Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname]) @@ -125,7 +125,7 @@ test "user is activated" do assert message =~ " activated" user = User.get_cached_by_nickname(user.nickname) - refute user.info.deactivated + refute user.deactivated end test "no user to toggle" do @@ -155,7 +155,7 @@ test "user is unsubscribed" do user = User.get_cached_by_nickname(user.nickname) assert Enum.empty?(user.following) - assert user.info.deactivated + assert user.deactivated end test "no user to unsubscribe" do @@ -182,13 +182,13 @@ test "All statuses set" do assert message =~ ~r/Admin status .* true/ user = User.get_cached_by_nickname(user.nickname) - assert user.info.is_moderator - assert user.info.locked - assert user.info.is_admin + assert user.is_moderator + assert user.locked + assert user.is_admin end test "All statuses unset" do - user = insert(:user, info: %{is_moderator: true, locked: true, is_admin: true}) + user = insert(:user, locked: true, is_moderator: true, is_admin: true) Mix.Tasks.Pleroma.User.run([ "set", @@ -208,9 +208,9 @@ test "All statuses unset" do assert message =~ ~r/Admin status .* false/ user = User.get_cached_by_nickname(user.nickname) - refute user.info.is_moderator - refute user.info.locked - refute user.info.is_admin + refute user.is_moderator + refute user.locked + refute user.is_admin end test "no user to set status" do @@ -358,28 +358,28 @@ test "it prints an error message when user is not exist" do describe "running toggle_confirmed" do test "user is confirmed" do - %{id: id, nickname: nickname} = insert(:user, info: %{confirmation_pending: false}) + %{id: id, nickname: nickname} = insert(:user, confirmation_pending: false) assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) assert_received {:mix_shell, :info, [message]} assert message == "#{nickname} needs confirmation." user = Repo.get(User, id) - assert user.info.confirmation_pending - assert user.info.confirmation_token + assert user.confirmation_pending + assert user.confirmation_token end test "user is not confirmed" do %{id: id, nickname: nickname} = - insert(:user, info: %{confirmation_pending: true, confirmation_token: "some token"}) + insert(:user, confirmation_pending: true, confirmation_token: "some token") assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) assert_received {:mix_shell, :info, [message]} assert message == "#{nickname} doesn't need confirmation." user = Repo.get(User, id) - refute user.info.confirmation_pending - refute user.info.confirmation_token + refute user.confirmation_pending + refute user.confirmation_token end test "it prints an error message when user is not exist" do diff --git a/test/user_info_test.exs b/test/user_info_test.exs deleted file mode 100644 index 2d795594e..000000000 --- a/test/user_info_test.exs +++ /dev/null @@ -1,24 +0,0 @@ -defmodule Pleroma.UserInfoTest do - alias Pleroma.Repo - alias Pleroma.User.Info - - use Pleroma.DataCase - - import Pleroma.Factory - - describe "update_email_notifications/2" do - setup do - user = insert(:user, %{info: %{email_notifications: %{"digest" => true}}}) - - {:ok, user: user} - end - - test "Notifications are updated", %{user: user} do - true = user.info.email_notifications["digest"] - changeset = Info.update_email_notifications(user.info, %{"digest" => false}) - assert changeset.valid? - {:ok, result} = Ecto.Changeset.apply_action(changeset, :insert) - assert result.email_notifications["digest"] == false - end - end -end diff --git a/test/user_test.exs b/test/user_test.exs index 019e7b400..381d8ea27 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -68,7 +68,7 @@ test "ap_following returns the following collection for the user" do test "returns all pending follow requests" do unlocked = insert(:user) - locked = insert(:user, %{info: %{locked: true}}) + locked = insert(:user, locked: true) follower = insert(:user) CommonAPI.follow(follower, unlocked) @@ -81,7 +81,7 @@ test "returns all pending follow requests" do end test "doesn't return already accepted or duplicate follow requests" do - locked = insert(:user, %{info: %{locked: true}}) + locked = insert(:user, locked: true) pending_follower = insert(:user) accepted_follower = insert(:user) @@ -95,7 +95,7 @@ test "doesn't return already accepted or duplicate follow requests" do end test "clears follow requests when requester is blocked" do - followed = insert(:user, %{info: %{locked: true}}) + followed = insert(:user, locked: true) follower = insert(:user) CommonAPI.follow(follower, followed) @@ -151,14 +151,14 @@ test "follow takes a user and another user" do user = User.get_cached_by_id(user.id) followed = User.get_cached_by_ap_id(followed.ap_id) - assert followed.info.follower_count == 1 + assert followed.follower_count == 1 assert User.ap_followers(followed) in user.following end test "can't follow a deactivated users" do user = insert(:user) - followed = insert(:user, info: %{deactivated: true}) + followed = insert(:user, %{deactivated: true}) {:error, _} = User.follow(user, followed) end @@ -182,8 +182,8 @@ test "can't subscribe to a user who blocked us" do end test "local users do not automatically follow local locked accounts" do - follower = insert(:user, info: %{locked: true}) - followed = insert(:user, info: %{locked: true}) + follower = insert(:user, locked: true) + followed = insert(:user, locked: true) {:ok, follower} = User.maybe_direct_follow(follower, followed) @@ -400,8 +400,8 @@ test "it creates unconfirmed user" do {:ok, user} = Repo.insert(changeset) - assert user.info.confirmation_pending - assert user.info.confirmation_token + assert user.confirmation_pending + assert user.confirmation_token end test "it creates confirmed user if :confirmed option is given" do @@ -410,8 +410,8 @@ test "it creates confirmed user if :confirmed option is given" do {:ok, user} = Repo.insert(changeset) - refute user.info.confirmation_pending - refute user.info.confirmation_token + refute user.confirmation_pending + refute user.confirmation_token end end @@ -505,7 +505,8 @@ test "updates an existing user, if stale" do assert orig_user.last_refreshed_at == a_week_ago {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin") - assert user.info.source_data["endpoints"] + + assert user.source_data["endpoints"] refute user.last_refreshed_at == orig_user.last_refreshed_at end @@ -611,63 +612,63 @@ test "gets all friends (followed users) for a given user" do end describe "updating note and follower count" do - test "it sets the info->note_count property" do + test "it sets the note_count property" do note = insert(:note) user = User.get_cached_by_ap_id(note.data["actor"]) - assert user.info.note_count == 0 + assert user.note_count == 0 {:ok, user} = User.update_note_count(user) - assert user.info.note_count == 1 + assert user.note_count == 1 end - test "it increases the info->note_count property" do + test "it increases the note_count property" do note = insert(:note) user = User.get_cached_by_ap_id(note.data["actor"]) - assert user.info.note_count == 0 + assert user.note_count == 0 {:ok, user} = User.increase_note_count(user) - assert user.info.note_count == 1 + assert user.note_count == 1 {:ok, user} = User.increase_note_count(user) - assert user.info.note_count == 2 + assert user.note_count == 2 end - test "it decreases the info->note_count property" do + test "it decreases the note_count property" do note = insert(:note) user = User.get_cached_by_ap_id(note.data["actor"]) - assert user.info.note_count == 0 + assert user.note_count == 0 {:ok, user} = User.increase_note_count(user) - assert user.info.note_count == 1 + assert user.note_count == 1 {:ok, user} = User.decrease_note_count(user) - assert user.info.note_count == 0 + assert user.note_count == 0 {:ok, user} = User.decrease_note_count(user) - assert user.info.note_count == 0 + assert user.note_count == 0 end - test "it sets the info->follower_count property" do + test "it sets the follower_count property" do user = insert(:user) follower = insert(:user) User.follow(follower, user) - assert user.info.follower_count == 0 + assert user.follower_count == 0 {:ok, user} = User.update_follower_count(user) - assert user.info.follower_count == 1 + assert user.follower_count == 1 end end @@ -958,14 +959,14 @@ test "get recipients from activity" do describe ".deactivate" do test "can de-activate then re-activate a user" do user = insert(:user) - assert false == user.info.deactivated + assert false == user.deactivated {:ok, user} = User.deactivate(user) - assert true == user.info.deactivated + assert true == user.deactivated {:ok, user} = User.deactivate(user, false) - assert false == user.info.deactivated + assert false == user.deactivated end - test "hide a user from followers " do + test "hide a user from followers" do user = insert(:user) user2 = insert(:user) @@ -1041,7 +1042,7 @@ test ".delete_user_activities deletes all create activities", %{user: user} do end test "it deletes deactivated user" do - {:ok, user} = insert(:user, info: %{deactivated: true}) |> User.set_cache() + {:ok, user} = insert(:user, deactivated: true) |> User.set_cache() {:ok, job} = User.delete(user) {:ok, _user} = ObanHelpers.perform(job) @@ -1180,7 +1181,7 @@ test "html_filter_policy returns default policies, when rich-text is enabled" do end test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do - user = insert(:user, %{info: %{no_rich_text: true}}) + user = insert(:user, no_rich_text: true) assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user) end @@ -1217,8 +1218,8 @@ test "User.delete() plugs any possible zombie objects" do 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}) + local_user = insert(:user, local: true, confirmation_pending: true) + confirmed_user = insert(:user, local: true, confirmation_pending: false) remote_user = insert(:user, local: false) refute User.auth_active?(local_user) @@ -1235,20 +1236,20 @@ test "returns false for unprivileged users" do test "returns false for remote users" do user = insert(:user, local: false) - remote_admin_user = insert(:user, local: false, info: %{is_admin: true}) + remote_admin_user = insert(:user, local: false, 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}) + user = insert(:user, local: true, is_moderator: true) assert User.superuser?(user) end test "returns true for local admins" do - user = insert(:user, local: true, info: %{is_admin: true}) + user = insert(:user, local: true, is_admin: true) assert User.superuser?(user) end @@ -1264,14 +1265,14 @@ test "returns true when the account is itself" do 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}) + user = insert(:user, local: true, confirmation_pending: true) other_user = insert(:user, local: true) refute User.visible_for?(user, other_user) end test "returns true when the account is unauthenticated and auth is not required" do - user = insert(:user, local: true, info: %{confirmation_pending: true}) + user = insert(:user, local: true, confirmation_pending: true) other_user = insert(:user, local: true) assert User.visible_for?(user, other_user) @@ -1280,8 +1281,8 @@ test "returns true when the account is unauthenticated and auth is not required" 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}) + user = insert(:user, local: true, confirmation_pending: true) + other_user = insert(:user, local: true, is_admin: true) assert User.visible_for?(user, other_user) end @@ -1347,7 +1348,7 @@ test "Users are inactive by default" do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false}) + insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) end) inactive_users_ids = @@ -1365,7 +1366,7 @@ test "Only includes users who has no recent activity" do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false}) + insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) end) {inactive, active} = Enum.split(users, trunc(total / 2)) @@ -1398,7 +1399,7 @@ test "Only includes users with no read notifications" do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false}) + insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) end) [sender | recipients] = users @@ -1438,19 +1439,19 @@ test "Only includes users with no read notifications" do describe "toggle_confirmation/1" do test "if user is confirmed" do - user = insert(:user, info: %{confirmation_pending: false}) + user = insert(:user, confirmation_pending: false) {:ok, user} = User.toggle_confirmation(user) - assert user.info.confirmation_pending - assert user.info.confirmation_token + assert user.confirmation_pending + assert user.confirmation_token end test "if user is unconfirmed" do - user = insert(:user, info: %{confirmation_pending: true, confirmation_token: "some token"}) + user = insert(:user, confirmation_pending: true, confirmation_token: "some token") {:ok, user} = User.toggle_confirmation(user) - refute user.info.confirmation_pending - refute user.info.confirmation_token + refute user.confirmation_pending + refute user.confirmation_token end end @@ -1486,7 +1487,7 @@ test "it returns a list of AP ids for a given set of nicknames" do user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed") user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2") insert(:user, local: true) - insert(:user, local: false, info: %{deactivated: true}) + insert(:user, local: false, deactivated: true) {:ok, user1: user1, user2: user2} end @@ -1605,7 +1606,7 @@ test "updates the counters normally on following/getting a follow when disabled" local: false, follower_address: "http://localhost:4001/users/masto_closed/followers", following_address: "http://localhost:4001/users/masto_closed/following", - info: %{ap_enabled: true} + ap_enabled: true ) assert User.user_info(other_user).following_count == 0 @@ -1628,7 +1629,7 @@ test "syncronizes the counters with the remote instance for the followed when en local: false, follower_address: "http://localhost:4001/users/masto_closed/followers", following_address: "http://localhost:4001/users/masto_closed/following", - info: %{ap_enabled: true} + ap_enabled: true ) assert User.user_info(other_user).following_count == 0 @@ -1651,7 +1652,7 @@ test "syncronizes the counters with the remote instance for the follower when en local: false, follower_address: "http://localhost:4001/users/masto_closed/followers", following_address: "http://localhost:4001/users/masto_closed/following", - info: %{ap_enabled: true} + ap_enabled: true ) assert User.user_info(other_user).following_count == 0 @@ -1691,41 +1692,6 @@ test "changes email", %{user: user} do end end - describe "set_password_reset_pending/2" do - setup do - [user: insert(:user)] - end - - test "sets password_reset_pending to true", %{user: user} do - %{password_reset_pending: password_reset_pending} = user.info - - refute password_reset_pending - - {:ok, %{info: %{password_reset_pending: password_reset_pending}}} = - User.force_password_reset(user) - - assert password_reset_pending - end - end - - test "change_info/2" do - user = insert(:user) - assert user.info.hide_follows == false - - changeset = User.change_info(user, &User.Info.profile_update(&1, %{hide_follows: true})) - assert changeset.changes.info.changes.hide_follows == true - end - - test "update_info/2" do - user = insert(:user) - assert user.info.hide_follows == false - - assert {:ok, _} = User.update_info(user, &User.Info.profile_update(&1, %{hide_follows: true})) - - assert %{info: %{hide_follows: true}} = Repo.get(User, user.id) - assert {:ok, %{info: %{hide_follows: true}}} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") - end - describe "get_cached_by_nickname_or_id" do setup do limit_to_local_content = Pleroma.Config.get([:instance, :limit_to_local_content]) @@ -1782,4 +1748,18 @@ test "allows getting local users by nickname no matter what :limit_to_local_cont assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) end end + + describe "update_email_notifications/2" do + setup do + user = insert(:user, email_notifications: %{"digest" => true}) + + {:ok, user: user} + end + + test "Notifications are updated", %{user: user} do + true = user.email_notifications["digest"] + assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false}) + assert result.email_notifications["digest"] == false + end + end end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 6a3e48b5e..4c666a0f2 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -683,7 +683,7 @@ test "it returns the followers in a collection", %{conn: conn} do test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do user = insert(:user) - user_two = insert(:user, %{info: %{hide_followers: true}}) + user_two = insert(:user, hide_followers: true) User.follow(user, user_two) result = @@ -696,7 +696,7 @@ test "it returns returns a uri if the user has 'hide_followers' set", %{conn: co test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated", %{conn: conn} do - user = insert(:user, %{info: %{hide_followers: true}}) + user = insert(:user, hide_followers: true) result = conn @@ -708,7 +708,7 @@ test "it returns a 403 error on pages, if the user has 'hide_followers' set and test "it renders the page, if the user has 'hide_followers' set and the request is authenticated with the same user", %{conn: conn} do - user = insert(:user, %{info: %{hide_followers: true}}) + user = insert(:user, hide_followers: true) other_user = insert(:user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) @@ -764,7 +764,7 @@ test "it returns the following in a collection", %{conn: conn} do end test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do - user = insert(:user, %{info: %{hide_follows: true}}) + user = insert(:user, hide_follows: true) user_two = insert(:user) User.follow(user, user_two) @@ -778,7 +778,7 @@ test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated", %{conn: conn} do - user = insert(:user, %{info: %{hide_follows: true}}) + user = insert(:user, hide_follows: true) result = conn @@ -790,7 +790,7 @@ test "it returns a 403 error on pages, if the user has 'hide_follows' set and th test "it renders the page, if the user has 'hide_follows' set and the request is authenticated with the same user", %{conn: conn} do - user = insert(:user, %{info: %{hide_follows: true}}) + user = insert(:user, hide_follows: true) other_user = insert(:user) {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index c9f2a92e7..44f66f40b 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -93,8 +93,8 @@ test "it returns a user" do {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) assert user.ap_id == user_id assert user.nickname == "admin@mastodon.example.org" - assert user.info.source_data - assert user.info.ap_enabled + assert user.source_data + assert user.ap_enabled assert user.follower_address == "http://mastodon.example.org/users/admin/followers" end @@ -279,7 +279,7 @@ test "does not increase user note count" do assert activity.actor == user.ap_id user = User.get_cached_by_id(user.id) - assert user.info.note_count == 0 + assert user.note_count == 0 end test "can be fetched into a timeline" do @@ -342,7 +342,7 @@ test "increases user note count only for public activities" do }) user = User.get_cached_by_id(user.id) - assert user.info.note_count == 2 + assert user.note_count == 2 end test "increases replies count" do @@ -1009,7 +1009,7 @@ test "it creates a delete activity and deletes the original object" do end test "decrements user note count only for public activities" do - user = insert(:user, info: %{note_count: 10}) + user = insert(:user, note_count: 10) {:ok, a1} = CommonAPI.post(User.get_cached_by_id(user.id), %{ @@ -1041,7 +1041,7 @@ test "decrements user note count only for public activities" do {:ok, _} = Object.normalize(a4) |> ActivityPub.delete() user = User.get_cached_by_id(user.id) - assert user.info.note_count == 10 + assert user.note_count == 10 end test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do @@ -1305,9 +1305,9 @@ test "detects hidden followers" do following_address: "http://localhost:4001/users/masto_closed/following" ) - {:ok, info} = ActivityPub.fetch_follow_information_for_user(user) - assert info.hide_followers == true - assert info.hide_follows == false + {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) + assert follow_info.hide_followers == true + assert follow_info.hide_follows == false end test "detects hidden follows" do @@ -1328,9 +1328,9 @@ test "detects hidden follows" do following_address: "http://localhost:4001/users/masto_closed/following" ) - {:ok, info} = ActivityPub.fetch_follow_information_for_user(user) - assert info.hide_followers == false - assert info.hide_follows == true + {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) + assert follow_info.hide_followers == false + assert follow_info.hide_follows == true end end end diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs index 03dc299ec..b524fdd23 100644 --- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs +++ b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs @@ -35,7 +35,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do test "it allows posts without links" do user = insert(:user) - assert user.info.note_count == 0 + assert user.note_count == 0 message = @linkless_message @@ -47,7 +47,7 @@ test "it allows posts without links" do test "it disallows posts with links" do user = insert(:user) - assert user.info.note_count == 0 + assert user.note_count == 0 message = @linkful_message @@ -59,9 +59,9 @@ test "it disallows posts with links" do describe "with old user" do test "it allows posts without links" do - user = insert(:user, info: %{note_count: 1}) + user = insert(:user, note_count: 1) - assert user.info.note_count == 1 + assert user.note_count == 1 message = @linkless_message @@ -71,9 +71,9 @@ test "it allows posts without links" do end test "it allows posts with links" do - user = insert(:user, info: %{note_count: 1}) + user = insert(:user, note_count: 1) - assert user.info.note_count == 1 + assert user.note_count == 1 message = @linkful_message @@ -85,9 +85,9 @@ test "it allows posts with links" do describe "with followed new user" do test "it allows posts without links" do - user = insert(:user, info: %{follower_count: 1}) + user = insert(:user, follower_count: 1) - assert user.info.follower_count == 1 + assert user.follower_count == 1 message = @linkless_message @@ -97,9 +97,9 @@ test "it allows posts without links" do end test "it allows posts with links" do - user = insert(:user, info: %{follower_count: 1}) + user = insert(:user, follower_count: 1) - assert user.info.follower_count == 1 + assert user.follower_count == 1 message = @linkful_message @@ -133,7 +133,7 @@ test "it rejects posts with links" do describe "with contentless-objects" do test "it does not reject them or error out" do - user = insert(:user, info: %{note_count: 1}) + user = insert(:user, note_count: 1) message = @response_message diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index df03b4008..e885e5a5a 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -27,7 +27,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do test "it returns sharedInbox for messages involving as:Public in to" do user = insert(:user, %{ - info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}} + source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}} }) activity = %Activity{ @@ -40,7 +40,7 @@ test "it returns sharedInbox for messages involving as:Public in to" do test "it returns sharedInbox for messages involving as:Public in cc" do user = insert(:user, %{ - info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}} + source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}} }) activity = %Activity{ @@ -53,7 +53,7 @@ test "it returns sharedInbox for messages involving as:Public in cc" do test "it returns sharedInbox for messages involving multiple recipients in to" do user = insert(:user, %{ - info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}} + source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}} }) user_two = insert(:user) @@ -69,7 +69,7 @@ test "it returns sharedInbox for messages involving multiple recipients in to" d test "it returns sharedInbox for messages involving multiple recipients in cc" do user = insert(:user, %{ - info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}} + source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}} }) user_two = insert(:user) @@ -84,14 +84,12 @@ test "it returns sharedInbox for messages involving multiple recipients in cc" d test "it returns sharedInbox for messages involving multiple recipients in total" do user = - insert(:user, %{ - info: %{ - source_data: %{ - "inbox" => "http://example.com/personal-inbox", - "endpoints" => %{"sharedInbox" => "http://example.com/inbox"} - } + insert(:user, + source_data: %{ + "inbox" => "http://example.com/personal-inbox", + "endpoints" => %{"sharedInbox" => "http://example.com/inbox"} } - }) + ) user_two = insert(:user) @@ -104,14 +102,12 @@ test "it returns sharedInbox for messages involving multiple recipients in total test "it returns inbox for messages involving single recipients in total" do user = - insert(:user, %{ - info: %{ - source_data: %{ - "inbox" => "http://example.com/personal-inbox", - "endpoints" => %{"sharedInbox" => "http://example.com/inbox"} - } + insert(:user, + source_data: %{ + "inbox" => "http://example.com/personal-inbox", + "endpoints" => %{"sharedInbox" => "http://example.com/inbox"} } - }) + ) activity = %Activity{ data: %{"to" => [user.ap_id], "cc" => []} @@ -241,10 +237,8 @@ test "it returns inbox for messages involving single recipients in total" do follower = insert(:user, local: false, - info: %{ - ap_enabled: true, - source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"} - } + source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"}, + ap_enabled: true ) actor = insert(:user, follower_address: follower.ap_id) @@ -278,19 +272,15 @@ test "it returns inbox for messages involving single recipients in total" do fetcher = insert(:user, local: false, - info: %{ - ap_enabled: true, - source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"} - } + source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"}, + ap_enabled: true ) another_fetcher = insert(:user, local: false, - info: %{ - ap_enabled: true, - source_data: %{"inbox" => "https://domain2.com/users/nick1/inbox"} - } + source_data: %{"inbox" => "https://domain2.com/users/nick1/inbox"}, + ap_enabled: true ) actor = insert(:user) diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index 99ab573c5..75cfbea2e 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -58,7 +58,7 @@ test "it works for incoming follow requests" do end test "with locked accounts, it does not create a follow or an accept" do - user = insert(:user, info: %{locked: true}) + user = insert(:user, locked: true) data = File.read!("test/fixtures/mastodon-follow-activity.json") diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 6c35a6f4d..0e36a18f5 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -148,7 +148,7 @@ test "it works for incoming notices" do user = User.get_cached_by_ap_id(object_data["actor"]) - assert user.info.note_count == 1 + assert user.note_count == 1 end test "it works for incoming notices with hashtags" do @@ -585,7 +585,7 @@ test "it works for incoming update activities" do } ] - assert user.info.banner["url"] == [ + assert user.banner["url"] == [ %{ "href" => "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" @@ -604,7 +604,7 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(activity.actor) - assert User.Info.fields(user.info) == [ + assert User.fields(user) == [ %{"name" => "foo", "value" => "bar"}, %{"name" => "foo1", "value" => "bar1"} ] @@ -625,7 +625,7 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(user.ap_id) - assert User.Info.fields(user.info) == [ + assert User.fields(user) == [ %{"name" => "foo", "value" => "updated"}, %{"name" => "foo1", "value" => "updated"} ] @@ -643,7 +643,7 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(user.ap_id) - assert User.Info.fields(user.info) == [ + assert User.fields(user) == [ %{"name" => "foo", "value" => "updated"}, %{"name" => "foo1", "value" => "updated"} ] @@ -654,7 +654,7 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(user.ap_id) - assert User.Info.fields(user.info) == [] + assert User.fields(user) == [] end test "it works for incoming update activities which lock the account" do @@ -677,7 +677,7 @@ test "it works for incoming update activities which lock the account" do {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) user = User.get_cached_by_ap_id(data["actor"]) - assert user.info.locked == true + assert user.locked == true end test "it works for incoming deletes" do @@ -918,7 +918,7 @@ test "it works for incoming accepts which were pre-accepted" do test "it works for incoming accepts which were orphaned" do follower = insert(:user) - followed = insert(:user, %{info: %User.Info{locked: true}}) + followed = insert(:user, locked: true) {:ok, follow_activity} = ActivityPub.follow(follower, followed) @@ -940,7 +940,7 @@ test "it works for incoming accepts which were orphaned" do test "it works for incoming accepts which are referenced by IRI only" do follower = insert(:user) - followed = insert(:user, %{info: %User.Info{locked: true}}) + followed = insert(:user, locked: true) {:ok, follow_activity} = ActivityPub.follow(follower, followed) @@ -960,7 +960,7 @@ test "it works for incoming accepts which are referenced by IRI only" do test "it fails for incoming accepts which cannot be correlated" do follower = insert(:user) - followed = insert(:user, %{info: %User.Info{locked: true}}) + followed = insert(:user, locked: true) accept_data = File.read!("test/fixtures/mastodon-accept-activity.json") @@ -979,7 +979,7 @@ test "it fails for incoming accepts which cannot be correlated" do test "it fails for incoming rejects which cannot be correlated" do follower = insert(:user) - followed = insert(:user, %{info: %User.Info{locked: true}}) + followed = insert(:user, locked: true) accept_data = File.read!("test/fixtures/mastodon-reject-activity.json") @@ -998,7 +998,7 @@ test "it fails for incoming rejects which cannot be correlated" do test "it works for incoming rejects which are orphaned" do follower = insert(:user) - followed = insert(:user, %{info: %User.Info{locked: true}}) + followed = insert(:user, locked: true) {:ok, follower} = User.follow(follower, followed) {:ok, _follow_activity} = ActivityPub.follow(follower, followed) @@ -1024,7 +1024,7 @@ test "it works for incoming rejects which are orphaned" do test "it works for incoming rejects which are referenced by IRI only" do follower = insert(:user) - followed = insert(:user, %{info: %User.Info{locked: true}}) + followed = insert(:user, locked: true) {:ok, follower} = User.follow(follower, followed) {:ok, follow_activity} = ActivityPub.follow(follower, followed) @@ -1326,18 +1326,18 @@ test "it upgrades a user to activitypub" do assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients user = User.get_cached_by_id(user.id) - assert user.info.note_count == 1 + assert user.note_count == 1 {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") ObanHelpers.perform_all() - assert user.info.ap_enabled - assert user.info.note_count == 1 + assert user.ap_enabled + assert user.note_count == 1 assert user.follower_address == "https://niu.moe/users/rye/followers" assert user.following_address == "https://niu.moe/users/rye/following" user = User.get_cached_by_id(user.id) - assert user.info.note_count == 1 + assert user.note_count == 1 activity = Activity.get_by_id(activity.id) assert user.follower_address in activity.recipients @@ -1358,7 +1358,7 @@ test "it upgrades a user to activitypub" do "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" } ] - } = user.info.banner + } = user.banner refute "..." in activity.recipients diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index c57ea7eb9..c1b000fac 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -297,7 +297,7 @@ test "fetches only Create activities" do describe "update_follow_state_for_all/2" do test "updates the state of all Follow activities with the same actor and object" do - user = insert(:user, info: %{locked: true}) + user = insert(:user, locked: true) follower = insert(:user) {:ok, follow_activity} = ActivityPub.follow(follower, user) @@ -321,7 +321,7 @@ test "updates the state of all Follow activities with the same actor and object" describe "update_follow_state/2" do test "updates the state of the given follow activity" do - user = insert(:user, info: %{locked: true}) + user = insert(:user, locked: true) follower = insert(:user) {:ok, follow_activity} = ActivityPub.follow(follower, user) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 3155749aa..42918cf2f 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -29,7 +29,7 @@ test "Renders profile fields" do {:ok, user} = insert(:user) - |> User.upgrade_changeset(%{info: %{fields: fields}}) + |> User.upgrade_changeset(%{fields: fields}) |> User.update_and_set_cache() assert %{ @@ -38,7 +38,7 @@ test "Renders profile fields" do end test "Renders with emoji tags" do - user = insert(:user, %{info: %{emoji: [%{"bib" => "/test"}]}}) + user = insert(:user, emoji: [%{"bib" => "/test"}]) assert %{ "tag" => [ @@ -64,9 +64,7 @@ test "Does not add an avatar image if the user hasn't set one" do user = insert(:user, avatar: %{"url" => [%{"href" => "https://someurl"}]}, - info: %{ - banner: %{"url" => [%{"href" => "https://somebanner"}]} - } + banner: %{"url" => [%{"href" => "https://somebanner"}]} ) {:ok, user} = User.ensure_keys_present(user) @@ -121,8 +119,7 @@ test "sets totalItems to zero when followers are hidden" do other_user = insert(:user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) - info = Map.merge(user.info, %{hide_followers_count: true, hide_followers: true}) - user = Map.put(user, :info, info) + user = Map.merge(user, %{hide_followers_count: true, hide_followers: true}) assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user}) end @@ -131,8 +128,7 @@ test "sets correct totalItems when followers are hidden but the follower counter other_user = insert(:user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) - info = Map.merge(user.info, %{hide_followers_count: false, hide_followers: true}) - user = Map.put(user, :info, info) + user = Map.merge(user, %{hide_followers_count: false, hide_followers: true}) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) end end @@ -143,8 +139,7 @@ test "sets totalItems to zero when follows are hidden" do other_user = insert(:user) {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) - info = Map.merge(user.info, %{hide_follows_count: true, hide_follows: true}) - user = Map.put(user, :info, info) + user = Map.merge(user, %{hide_follows_count: true, hide_follows: true}) assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user}) end @@ -153,8 +148,7 @@ test "sets correct totalItems when follows are hidden but the follow counter is other_user = insert(:user) {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) - info = Map.merge(user.info, %{hide_follows_count: false, hide_follows: true}) - user = Map.put(user, :info, info) + user = Map.merge(user, %{hide_follows_count: false, hide_follows: true}) assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) end end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index b5c355e66..a1027e2e2 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -19,7 +19,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do describe "/api/pleroma/admin/users" do test "Delete" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -40,7 +40,7 @@ test "Delete" do end test "Create" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -70,7 +70,7 @@ test "Create" do end test "Cannot create user with exisiting email" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -101,7 +101,7 @@ test "Cannot create user with exisiting email" do end test "Cannot create user with exisiting nickname" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -132,7 +132,7 @@ test "Cannot create user with exisiting nickname" do end test "Multiple user creation works in transaction" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -181,7 +181,7 @@ test "Multiple user creation works in transaction" do describe "/api/pleroma/admin/users/:nickname" do test "Show", %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -204,7 +204,7 @@ test "Show", %{conn: conn} do end test "when the user doesn't exist", %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = build(:user) conn = @@ -218,7 +218,7 @@ test "when the user doesn't exist", %{conn: conn} do describe "/api/pleroma/admin/users/follow" do test "allows to force-follow another user" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) follower = insert(:user) @@ -244,7 +244,7 @@ test "allows to force-follow another user" do describe "/api/pleroma/admin/users/unfollow" do test "allows to force-unfollow another user" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) follower = insert(:user) @@ -272,7 +272,7 @@ test "allows to force-unfollow another user" do describe "PUT /api/pleroma/admin/users/tag" do setup do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y"]}) user3 = insert(:user, %{tags: ["unchanged"]}) @@ -321,7 +321,7 @@ test "it does not modify tags of not specified users", %{conn: conn, user3: user describe "DELETE /api/pleroma/admin/users/tag" do setup do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y", "z"]}) user3 = insert(:user, %{tags: ["unchanged"]}) @@ -370,7 +370,7 @@ test "it does not modify tags of not specified users", %{conn: conn, user3: user describe "/api/pleroma/admin/users/:nickname/permission_group" do test "GET is giving user_info" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -385,7 +385,7 @@ test "GET is giving user_info" do end test "/:right POST, can add to a permission group" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -405,8 +405,8 @@ test "/:right POST, can add to a permission group" do end test "/:right DELETE, can remove from a permission group" do - admin = insert(:user, info: %{is_admin: true}) - user = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) + user = insert(:user, is_admin: true) conn = build_conn() @@ -427,7 +427,7 @@ test "/:right DELETE, can remove from a permission group" do describe "PUT /api/pleroma/admin/users/:nickname/activation_status" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = conn @@ -445,7 +445,7 @@ test "deactivates the user", %{conn: conn, admin: admin} do |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: false}) user = User.get_cached_by_id(user.id) - assert user.info.deactivated == true + assert user.deactivated == true assert json_response(conn, :no_content) log_entry = Repo.one(ModerationLog) @@ -455,14 +455,14 @@ test "deactivates the user", %{conn: conn, admin: admin} do end test "activates the user", %{conn: conn, admin: admin} do - user = insert(:user, info: %{deactivated: true}) + user = insert(:user, deactivated: true) conn = conn |> put("/api/pleroma/admin/users/#{user.nickname}/activation_status", %{status: true}) user = User.get_cached_by_id(user.id) - assert user.info.deactivated == false + assert user.deactivated == false assert json_response(conn, :no_content) log_entry = Repo.one(ModerationLog) @@ -485,7 +485,7 @@ test "returns 403 when requested by a non-admin", %{conn: conn} do describe "POST /api/pleroma/admin/email_invite, with valid config" do setup do - [user: insert(:user, info: %{is_admin: true})] + [user: insert(:user, is_admin: true)] end clear_config([:instance, :registrations_open]) do @@ -545,7 +545,7 @@ test "it returns 403 if requested by a non-admin", %{conn: conn} do describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do setup do - [user: insert(:user, info: %{is_admin: true})] + [user: insert(:user, is_admin: true)] end clear_config([:instance, :registrations_open]) @@ -577,7 +577,7 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn, user: us end test "/api/pleroma/admin/users/:nickname/password_reset" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -593,7 +593,7 @@ test "/api/pleroma/admin/users/:nickname/password_reset" do describe "GET /api/pleroma/admin/users" do setup do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -609,7 +609,7 @@ test "renders users array for the first page", %{conn: conn, admin: admin} do users = [ %{ - "deactivated" => admin.info.deactivated, + "deactivated" => admin.deactivated, "id" => admin.id, "nickname" => admin.nickname, "roles" => %{"admin" => true, "moderator" => false}, @@ -619,7 +619,7 @@ test "renders users array for the first page", %{conn: conn, admin: admin} do "display_name" => HTML.strip_tags(admin.name || admin.nickname) }, %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -660,7 +660,7 @@ test "regular search", %{conn: conn} do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -684,7 +684,7 @@ test "search by domain", %{conn: conn} do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -708,7 +708,7 @@ test "search by full nickname", %{conn: conn} do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -732,7 +732,7 @@ test "search by display name", %{conn: conn} do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -756,7 +756,7 @@ test "search by email", %{conn: conn} do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -780,7 +780,7 @@ test "regular search with page size", %{conn: conn} do "page_size" => 1, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -799,7 +799,7 @@ test "regular search with page size", %{conn: conn} do "page_size" => 1, "users" => [ %{ - "deactivated" => user2.info.deactivated, + "deactivated" => user2.deactivated, "id" => user2.id, "nickname" => user2.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -813,7 +813,7 @@ test "regular search with page size", %{conn: conn} do end test "only local users" do - admin = insert(:user, info: %{is_admin: true}, nickname: "john") + admin = insert(:user, is_admin: true, nickname: "john") user = insert(:user, nickname: "bob") insert(:user, nickname: "bobb", local: false) @@ -828,7 +828,7 @@ test "only local users" do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -842,7 +842,7 @@ test "only local users" do end test "only local users with no query", %{admin: old_admin} do - admin = insert(:user, info: %{is_admin: true}, nickname: "john") + admin = insert(:user, is_admin: true, nickname: "john") user = insert(:user, nickname: "bob") insert(:user, nickname: "bobb", local: false) @@ -855,7 +855,7 @@ test "only local users with no query", %{admin: old_admin} do users = [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -865,7 +865,7 @@ test "only local users with no query", %{admin: old_admin} do "display_name" => HTML.strip_tags(user.name || user.nickname) }, %{ - "deactivated" => admin.info.deactivated, + "deactivated" => admin.deactivated, "id" => admin.id, "nickname" => admin.nickname, "roles" => %{"admin" => true, "moderator" => false}, @@ -895,7 +895,7 @@ test "only local users with no query", %{admin: old_admin} do end test "load only admins", %{conn: conn, admin: admin} do - second_admin = insert(:user, info: %{is_admin: true}) + second_admin = insert(:user, is_admin: true) insert(:user) insert(:user) @@ -934,7 +934,7 @@ test "load only admins", %{conn: conn, admin: admin} do end test "load only moderators", %{conn: conn} do - moderator = insert(:user, info: %{is_moderator: true}) + moderator = insert(:user, is_moderator: true) insert(:user) insert(:user) @@ -999,11 +999,11 @@ test "load users with tags list", %{conn: conn} do end test "it works with multiple filters" do - admin = insert(:user, nickname: "john", info: %{is_admin: true}) - user = insert(:user, nickname: "bob", local: false, info: %{deactivated: true}) + admin = insert(:user, nickname: "john", is_admin: true) + user = insert(:user, nickname: "bob", local: false, deactivated: true) - insert(:user, nickname: "ken", local: true, info: %{deactivated: true}) - insert(:user, nickname: "bobb", local: false, info: %{deactivated: false}) + insert(:user, nickname: "ken", local: true, deactivated: true) + insert(:user, nickname: "bobb", local: false, deactivated: false) conn = build_conn() @@ -1015,7 +1015,7 @@ test "it works with multiple filters" do "page_size" => 50, "users" => [ %{ - "deactivated" => user.info.deactivated, + "deactivated" => user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -1030,7 +1030,7 @@ test "it works with multiple filters" do end test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) conn = @@ -1040,7 +1040,7 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do assert json_response(conn, 200) == %{ - "deactivated" => !user.info.deactivated, + "deactivated" => !user.deactivated, "id" => user.id, "nickname" => user.nickname, "roles" => %{"admin" => false, "moderator" => false}, @@ -1058,7 +1058,7 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do describe "POST /api/pleroma/admin/users/invite_token" do setup do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -1122,7 +1122,7 @@ test "with max use and expires_at", %{conn: conn} do describe "GET /api/pleroma/admin/users/invites" do setup do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -1160,7 +1160,7 @@ test "with invite", %{conn: conn} do describe "POST /api/pleroma/admin/users/revoke_invite" do test "with token" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) {:ok, invite} = UserInviteToken.create_invite() conn = @@ -1180,7 +1180,7 @@ test "with token" do end test "with invalid token" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -1193,7 +1193,7 @@ test "with invalid token" do describe "GET /api/pleroma/admin/reports/:id" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) %{conn: assign(conn, :user, admin)} end @@ -1226,7 +1226,7 @@ test "returns 404 when report id is invalid", %{conn: conn} do describe "PUT /api/pleroma/admin/reports/:id" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -1287,7 +1287,7 @@ test "returns 404 when report is not exist", %{conn: conn} do describe "GET /api/pleroma/admin/reports" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) %{conn: assign(conn, :user, admin)} end @@ -1407,7 +1407,7 @@ test "returns 403 when requested by anonymous" do # describe "POST /api/pleroma/admin/reports/:id/respond" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) %{conn: assign(conn, :user, admin), admin: admin} end @@ -1462,7 +1462,7 @@ test "returns 404 when report id is invalid", %{conn: conn} do describe "PUT /api/pleroma/admin/statuses/:id" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) activity = insert(:note_activity) %{conn: assign(conn, :user, admin), id: activity.id, admin: admin} @@ -1528,7 +1528,7 @@ test "returns 400 when visibility is unknown", %{conn: conn, id: id} do describe "DELETE /api/pleroma/admin/statuses/:id" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) activity = insert(:note_activity) %{conn: assign(conn, :user, admin), id: activity.id, admin: admin} @@ -1558,7 +1558,7 @@ test "returns error when status is not exist", %{conn: conn} do describe "GET /api/pleroma/admin/config" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) %{conn: assign(conn, :user, admin)} end @@ -1595,7 +1595,7 @@ test "with settings in db", %{conn: conn} do describe "POST /api/pleroma/admin/config" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) temp_file = "config/test.exported_from_db.secret.exs" @@ -2163,7 +2163,7 @@ test "delete part of settings by atom subkeys", %{conn: conn} do describe "config mix tasks run" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) temp_file = "config/test.exported_from_db.secret.exs" @@ -2199,7 +2199,7 @@ test "transfer settings to DB and to file", %{conn: conn, admin: admin} do describe "GET /api/pleroma/admin/users/:nickname/statuses" do setup do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!() @@ -2256,8 +2256,8 @@ test "returns private statuses with godmode on", %{conn: conn, user: user} do describe "GET /api/pleroma/admin/moderation_log" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) - moderator = insert(:user, info: %{is_moderator: true}) + admin = insert(:user, is_admin: true) + moderator = insert(:user, is_moderator: true) %{conn: assign(conn, :user, admin), admin: admin, moderator: moderator} end @@ -2465,14 +2465,14 @@ test "returns log filtered by search", %{conn: conn, moderator: moderator} do describe "PATCH /users/:nickname/force_password_reset" do setup %{conn: conn} do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) user = insert(:user) %{conn: assign(conn, :user, admin), admin: admin, user: user} end test "sets password_reset_pending to true", %{admin: admin, user: user} do - assert user.info.password_reset_pending == false + assert user.password_reset_pending == false conn = build_conn() @@ -2483,7 +2483,7 @@ test "sets password_reset_pending to true", %{admin: admin, user: user} do ObanHelpers.perform_all() - assert User.get_by_id(user.id).info.password_reset_pending == true + assert User.get_by_id(user.id).password_reset_pending == true end end end diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs index 9df4cd539..082e691c4 100644 --- a/test/web/admin_api/search_test.exs +++ b/test/web/admin_api/search_test.exs @@ -47,9 +47,9 @@ test "it returns local/external users" do end test "it returns active/deactivated users" do - insert(:user, info: %{deactivated: true}) - insert(:user, info: %{deactivated: true}) - insert(:user, info: %{deactivated: false}) + insert(:user, deactivated: true) + insert(:user, deactivated: true) + insert(:user, deactivated: false) {:ok, _results, active_count} = Search.user(%{ @@ -70,7 +70,7 @@ test "it returns active/deactivated users" do test "it returns specific user" do insert(:user) insert(:user) - user = insert(:user, nickname: "bob", local: true, info: %{deactivated: false}) + user = insert(:user, nickname: "bob", local: true, deactivated: false) {:ok, _results, total_count} = Search.user(%{query: ""}) @@ -108,7 +108,7 @@ test "it return user by full nickname" do end test "it returns admin user" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) insert(:user) insert(:user) @@ -119,7 +119,7 @@ test "it returns admin user" do end test "it returns moderator user" do - moderator = insert(:user, info: %{is_moderator: true}) + moderator = insert(:user, is_moderator: true) insert(:user) insert(:user) diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs index 475705857..ef4a806e4 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/web/admin_api/views/report_view_test.exs @@ -49,6 +49,8 @@ test "includes reported statuses" do {:ok, report_activity} = CommonAPI.report(user, %{"account_id" => other_user.id, "status_ids" => [activity.id]}) + other_user = Pleroma.User.get_by_id(other_user.id) + expected = %{ content: nil, actor: diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 83df44c36..1d2f20617 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -100,7 +100,7 @@ test "it adds emoji when updating profiles" do {:ok, activity} = CommonAPI.update(user) user = User.get_cached_by_ap_id(user.ap_id) - [firefox] = user.info.source_data["tag"] + [firefox] = user.source_data["tag"] assert firefox["name"] == ":firefox:" @@ -291,7 +291,7 @@ test "pin status", %{user: user, activity: activity} do id = activity.id user = refresh_record(user) - assert %User{info: %{pinned_activities: [^id]}} = user + assert %User{pinned_activities: [^id]} = user end test "unlisted statuses can be pinned", %{user: user} do @@ -325,7 +325,7 @@ test "unpin status", %{user: user, activity: activity} do user = refresh_record(user) - assert %User{info: %{pinned_activities: []}} = user + assert %User{pinned_activities: []} = user end test "should unpin when deleting a status", %{user: user, activity: activity} do @@ -337,7 +337,7 @@ test "should unpin when deleting a status", %{user: user, activity: activity} do user = refresh_record(user) - assert %User{info: %{pinned_activities: []}} = user + assert %User{pinned_activities: []} = user end end @@ -468,7 +468,7 @@ test "also unsubscribes a user" do describe "accept_follow_request/2" do test "after acceptance, it sets all existing pending follow request states to 'accept'" do - user = insert(:user, info: %{locked: true}) + user = insert(:user, locked: true) follower = insert(:user) follower_two = insert(:user) @@ -488,7 +488,7 @@ test "after acceptance, it sets all existing pending follow request states to 'a end test "after rejection, it sets all existing pending follow request states to 'reject'" do - user = insert(:user, info: %{locked: true}) + user = insert(:user, locked: true) follower = insert(:user) follower_two = insert(:user) diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 43a715706..776cfa22f 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -81,14 +81,16 @@ test "it federates only to reachable instances via AP" do local: false, nickname: "nick1@domain.com", ap_id: "https://domain.com/users/nick1", - info: %{ap_enabled: true, source_data: %{"inbox" => inbox1}} + source_data: %{"inbox" => inbox1}, + ap_enabled: true }) insert(:user, %{ local: false, nickname: "nick2@domain2.com", ap_id: "https://domain2.com/users/nick2", - info: %{ap_enabled: true, source_data: %{"inbox" => inbox2}} + source_data: %{"inbox" => inbox2}, + ap_enabled: true }) dt = NaiveDateTime.utc_now() @@ -162,7 +164,7 @@ test "it federates only to reachable instances via Salmon" do local: false, nickname: "nick1@domain.com", ap_id: "https://domain.com/users/nick1", - info: %{salmon: "https://domain.com/salmon"} + salmon: "https://domain.com/salmon" }) remote_user2 = @@ -170,7 +172,7 @@ test "it federates only to reachable instances via Salmon" do local: false, nickname: "nick2@domain2.com", ap_id: "https://domain2.com/users/nick2", - info: %{salmon: "https://domain2.com/salmon"} + salmon: "https://domain2.com/salmon" }) remote_user2_id = remote_user2.id diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs index ab9dab352..b5dbd4a25 100644 --- a/test/web/masto_fe_controller_test.exs +++ b/test/web/masto_fe_controller_test.exs @@ -23,7 +23,7 @@ test "put settings", %{conn: conn} do assert _result = json_response(conn, 200) user = User.get_cached_by_ap_id(user.ap_id) - assert user.info.settings == %{"programming" => "socks"} + assert user.settings == %{"programming" => "socks"} end describe "index/2 redirections" do diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs index 618031b40..519b56d6c 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs @@ -153,7 +153,7 @@ test "updates the user's skip_thread_containment option", %{conn: conn} do |> json_response(200) assert response["pleroma"]["skip_thread_containment"] == true - assert refresh_record(user).info.skip_thread_containment + assert refresh_record(user).skip_thread_containment end test "updates the user's hide_follows status", %{conn: conn} do diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index 6a59c3d94..a4bec2248 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -255,7 +255,7 @@ test "getting followers", %{conn: conn} do test "getting followers, hide_followers", %{conn: conn} do user = insert(:user) - other_user = insert(:user, %{info: %{hide_followers: true}}) + other_user = insert(:user, hide_followers: true) {:ok, _user} = User.follow(user, other_user) conn = @@ -267,7 +267,7 @@ test "getting followers, hide_followers", %{conn: conn} do test "getting followers, hide_followers, same user requesting", %{conn: conn} do user = insert(:user) - other_user = insert(:user, %{info: %{hide_followers: true}}) + other_user = insert(:user, hide_followers: true) {:ok, _user} = User.follow(user, other_user) conn = @@ -335,7 +335,7 @@ test "getting following", %{conn: conn} do end test "getting following, hide_follows", %{conn: conn} do - user = insert(:user, %{info: %{hide_follows: true}}) + user = insert(:user, hide_follows: true) other_user = insert(:user) {:ok, user} = User.follow(user, other_user) @@ -347,7 +347,7 @@ test "getting following, hide_follows", %{conn: conn} do end test "getting following, hide_follows, same user requesting", %{conn: conn} do - user = insert(:user, %{info: %{hide_follows: true}}) + user = insert(:user, hide_follows: true) other_user = insert(:user) {:ok, user} = User.follow(user, other_user) @@ -669,7 +669,7 @@ test "Account registration via Application", %{conn: conn} do token_from_db = Repo.preload(token_from_db, :user) assert token_from_db.user - assert token_from_db.user.info.confirmation_pending + assert token_from_db.user.confirmation_pending end test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do @@ -713,7 +713,7 @@ test "rate limit", %{conn: conn} do token_from_db = Repo.preload(token_from_db, :user) assert token_from_db.user - assert token_from_db.user.info.confirmation_pending + assert token_from_db.user.confirmation_pending end conn = @@ -798,7 +798,7 @@ test "verify_credentials", %{conn: conn} do end test "verify_credentials default scope unlisted", %{conn: conn} do - user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}}) + user = insert(:user, default_scope: "unlisted") conn = conn @@ -810,7 +810,7 @@ test "verify_credentials default scope unlisted", %{conn: conn} do end test "locked accounts", %{conn: conn} do - user = insert(:user, %{info: %User.Info{default_scope: "private"}}) + user = insert(:user, default_scope: "private") conn = conn diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs index a308a7620..34b434f3f 100644 --- a/test/web/mastodon_api/controllers/conversation_controller_test.exs +++ b/test/web/mastodon_api/controllers/conversation_controller_test.exs @@ -17,7 +17,7 @@ test "returns a list of conversations", %{conn: conn} do {:ok, user_two} = User.follow(user_two, user_one) - assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 0 + assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 {:ok, direct} = CommonAPI.post(user_one, %{ @@ -25,7 +25,7 @@ test "returns a list of conversations", %{conn: conn} do "visibility" => "direct" }) - assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 1 + assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1 {:ok, _follower_only} = CommonAPI.post(user_one, %{ @@ -56,7 +56,7 @@ test "returns a list of conversations", %{conn: conn} do assert is_binary(res_id) assert unread == true assert res_last_status["id"] == direct.id - assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 1 + assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 end test "updates the last_status on reply", %{conn: conn} do @@ -107,7 +107,7 @@ test "the user marks a conversation as read", %{conn: conn} do |> post("/api/v1/conversations/#{direct_conversation_id}/read") |> json_response(200) - assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 0 + assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 # The conversation is marked as unread on reply {:ok, _} = @@ -123,7 +123,7 @@ test "the user marks a conversation as read", %{conn: conn} do |> get("/api/v1/conversations") |> json_response(200) - assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 1 + assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 # A reply doesn't increment the user's unread_conversation_count if the conversation is unread {:ok, _} = @@ -133,7 +133,7 @@ test "the user marks a conversation as read", %{conn: conn} do "in_reply_to_status_id" => direct.id }) - assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 1 + assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 end test "(vanilla) Mastodon frontend behaviour", %{conn: conn} do diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/web/mastodon_api/controllers/follow_request_controller_test.exs index 4bf292df5..913f8c038 100644 --- a/test/web/mastodon_api/controllers/follow_request_controller_test.exs +++ b/test/web/mastodon_api/controllers/follow_request_controller_test.exs @@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do describe "locked accounts" do test "/api/v1/follow_requests works" do - user = insert(:user, %{info: %User.Info{locked: true}}) + user = insert(:user, locked: true) other_user = insert(:user) {:ok, _activity} = ActivityPub.follow(other_user, user) @@ -32,7 +32,7 @@ test "/api/v1/follow_requests works" do end test "/api/v1/follow_requests/:id/authorize works" do - user = insert(:user, %{info: %User.Info{locked: true}}) + user = insert(:user, locked: true) other_user = insert(:user) {:ok, _activity} = ActivityPub.follow(other_user, user) @@ -57,7 +57,7 @@ test "/api/v1/follow_requests/:id/authorize works" do end test "/api/v1/follow_requests/:id/reject works" do - user = insert(:user, %{info: %User.Info{locked: true}}) + user = insert(:user, locked: true) other_user = insert(:user) {:ok, _activity} = ActivityPub.follow(other_user, user) diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/web/mastodon_api/controllers/instance_controller_test.exs index f8049f81f..e00de6b18 100644 --- a/test/web/mastodon_api/controllers/instance_controller_test.exs +++ b/test/web/mastodon_api/controllers/instance_controller_test.exs @@ -41,20 +41,13 @@ test "get instance stats", %{conn: conn} do user = insert(:user, %{local: true}) user2 = insert(:user, %{local: true}) - {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated) + {:ok, _user2} = User.deactivate(user2, !user2.deactivated) insert(:user, %{local: false, nickname: "u@peer1.com"}) insert(:user, %{local: false, nickname: "u@peer2.com"}) {:ok, _} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofe"}) - # Stats should count users with missing or nil `info.deactivated` value - - {:ok, _user} = - user.id - |> User.get_cached_by_id() - |> User.update_info(&Ecto.Changeset.change(&1, %{deactivated: nil})) - Pleroma.Stats.force_update() conn = get(conn, "/api/v1/instance") diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 2de2725e0..10efb265b 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -526,8 +526,8 @@ test "when you didn't create it", %{conn: conn} do test "when you're an admin or moderator", %{conn: conn} do activity1 = insert(:note_activity) activity2 = insert(:note_activity) - admin = insert(:user, info: %{is_admin: true}) - moderator = insert(:user, info: %{is_moderator: true}) + admin = insert(:user, is_admin: true) + moderator = insert(:user, is_moderator: true) res_conn = conn diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs index 7fcb2bd55..561ef05aa 100644 --- a/test/web/mastodon_api/mastodon_api_test.exs +++ b/test/web/mastodon_api/mastodon_api_test.exs @@ -14,11 +14,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do import Pleroma.Factory describe "follow/3" do - test "returns error when user deactivated" do + test "returns error when followed user is deactivated" do follower = insert(:user) - user = insert(:user, local: true, info: %{deactivated: true}) + user = insert(:user, local: true, deactivated: true) {:error, error} = MastodonAPI.follow(follower, user) - assert error == "Could not follow user: You are deactivated." + assert error == "Could not follow user: #{user.nickname} is deactivated." end test "following for user" do diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index b7a4938a6..8c13ac862 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -26,12 +26,10 @@ test "Represent a user account" do user = insert(:user, %{ - info: %{ - note_count: 5, - follower_count: 3, - source_data: source_data, - background: background_image - }, + follower_count: 3, + note_count: 5, + source_data: source_data, + background: background_image, nickname: "shp@shitposter.club", name: ":karjalanpiirakka: shp", bio: "valid html", @@ -101,7 +99,7 @@ test "Represent the user account for the account owner" do "non_followers" => true } - privacy = user.info.default_scope + privacy = user.default_scope assert %{ pleroma: %{notification_settings: ^notification_settings}, @@ -112,7 +110,9 @@ test "Represent the user account for the account owner" do test "Represent a Service(bot) account" do user = insert(:user, %{ - info: %{note_count: 5, follower_count: 3, source_data: %{"type" => "Service"}}, + follower_count: 3, + note_count: 5, + source_data: %{"type" => "Service"}, nickname: "shp@shitposter.club", inserted_at: ~N[2017-08-15 15:47:06.597036] }) @@ -164,8 +164,8 @@ test "Represent a Service(bot) account" do end test "Represent a deactivated user for an admin" do - admin = insert(:user, %{info: %{is_admin: true}}) - deactivated_user = insert(:user, %{info: %{deactivated: true}}) + admin = insert(:user, is_admin: true) + deactivated_user = insert(:user, deactivated: true) represented = AccountView.render("show.json", %{user: deactivated_user, for: admin}) assert represented[:pleroma][:deactivated] == true end @@ -253,7 +253,7 @@ test "represent a relationship for the user blocking a domain" do test "represent a relationship for the user with a pending follow request" do user = insert(:user) - other_user = insert(:user, %{info: %User.Info{locked: true}}) + other_user = insert(:user, locked: true) {:ok, user, other_user, _} = CommonAPI.follow(user, other_user) user = User.get_cached_by_id(user.id) @@ -282,7 +282,9 @@ test "represent a relationship for the user with a pending follow request" do test "represent an embedded relationship" do user = insert(:user, %{ - info: %{note_count: 5, follower_count: 0, source_data: %{"type" => "Service"}}, + follower_count: 0, + note_count: 5, + source_data: %{"type" => "Service"}, nickname: "shp@shitposter.club", inserted_at: ~N[2017-08-15 15:47:06.597036] }) @@ -352,7 +354,7 @@ test "represent an embedded relationship" do end test "returns the settings store if the requesting user is the represented user and it's requested specifically" do - user = insert(:user, %{info: %User.Info{pleroma_settings_store: %{fe: "test"}}}) + user = insert(:user, pleroma_settings_store: %{fe: "test"}) result = AccountView.render("show.json", %{user: user, for: user, with_pleroma_settings: true}) @@ -374,14 +376,13 @@ test "sanitizes display names" do describe "hiding follows/following" do test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do - info = %{ - hide_followers: true, - hide_followers_count: true, - hide_follows: true, - hide_follows_count: true - } - - user = insert(:user, info: info) + user = + insert(:user, %{ + hide_followers: true, + hide_followers_count: true, + hide_follows: true, + hide_follows_count: true + }) other_user = insert(:user) {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) @@ -395,7 +396,7 @@ test "shows when follows/followers stats are hidden and sets follow/follower cou end test "shows when follows/followers are hidden" do - user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + user = insert(:user, hide_followers: true, hide_follows: true) other_user = insert(:user) {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) @@ -408,7 +409,7 @@ test "shows when follows/followers are hidden" do end test "shows actual follower/following count to the account owner" do - user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + user = insert(:user, hide_followers: true, hide_follows: true) other_user = insert(:user) {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) @@ -456,7 +457,7 @@ test "shows zero when no follow requests are pending" do end test "shows non-zero when follow requests are pending" do - user = insert(:user, %{info: %{locked: true}}) + user = insert(:user, locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) @@ -468,7 +469,7 @@ test "shows non-zero when follow requests are pending" do end test "decreases when accepting a follow request" do - user = insert(:user, %{info: %{locked: true}}) + user = insert(:user, locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) @@ -485,7 +486,7 @@ test "decreases when accepting a follow request" do end test "decreases when rejecting a follow request" do - user = insert(:user, %{info: %{locked: true}}) + user = insert(:user, locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) @@ -502,14 +503,14 @@ test "decreases when rejecting a follow request" do end test "shows non-zero when historical unapproved requests are present" do - user = insert(:user, %{info: %{locked: true}}) + user = insert(:user, locked: true) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) other_user = insert(:user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: false})) + {:ok, user} = User.update_and_set_cache(user, %{locked: false}) assert %{locked: false, follow_requests_count: 1} = AccountView.render("show.json", %{user: user, for: user}) diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index e15a0bfff..a3281b25b 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -24,8 +24,8 @@ test "GET /.well-known/nodeinfo", %{conn: conn} do end test "nodeinfo shows staff accounts", %{conn: conn} do - moderator = insert(:user, %{local: true, info: %{is_moderator: true}}) - admin = insert(:user, %{local: true, info: %{is_admin: true}}) + moderator = insert(:user, local: true, is_moderator: true) + admin = insert(:user, local: true, is_admin: true) conn = conn diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index 41aaf6189..ad8d79083 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -780,8 +780,8 @@ test "rejects token exchange for valid credentials belonging to unconfirmed user {:ok, user} = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) - |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true)) - |> Repo.update() + |> User.confirmation_changeset(need_confirmation: true) + |> User.update_and_set_cache() refute Pleroma.User.auth_active?(user) @@ -808,7 +808,7 @@ test "rejects token exchange for valid credentials belonging to deactivated user user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password), - info: %{deactivated: true} + deactivated: true ) app = insert(:oauth_app) @@ -834,7 +834,7 @@ test "rejects token exchange for user with password_reset_pending set to true" d user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password), - info: %{password_reset_pending: true} + password_reset_pending: true ) app = insert(:oauth_app, scopes: ["read", "write"]) diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index b1af918d8..376446f93 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -51,7 +51,7 @@ test "decodes a salmon with a changed magic key", %{conn: conn} do end) =~ "[error]" # Wrong key - info = %{ + update_params = %{ magic_key: "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" } @@ -59,7 +59,8 @@ test "decodes a salmon with a changed magic key", %{conn: conn} do # Set a wrong magic-key for a user so it has to refetch "http://gs.example.org:4040/index.php/user/1" |> User.get_cached_by_ap_id() - |> User.update_info(&User.Info.remote_user_creation(&1, info)) + |> User.update_changeset(update_params) + |> User.update_and_set_cache() assert capture_log(fn -> conn = diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index 70a0e4473..ef34425da 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -33,7 +33,7 @@ test "handle incoming note - GS, Salmon" do object = Object.normalize(activity) user = User.get_cached_by_ap_id(activity.data["actor"]) - assert user.info.note_count == 1 + assert user.note_count == 1 assert activity.data["type"] == "Create" assert object.data["type"] == "Note" @@ -328,7 +328,7 @@ test "handle incoming follows" do test "refuse following over OStatus if the followed's account is locked" do incoming = File.read!("test/fixtures/follow.xml") - _user = insert(:user, info: %{locked: true}, ap_id: "https://pawoo.net/users/pekorino") + _user = insert(:user, locked: true, ap_id: "https://pawoo.net/users/pekorino") {:ok, [{:error, "It's not possible to follow locked accounts over OStatus"}]} = OStatus.handle_incoming(incoming) @@ -392,7 +392,7 @@ test "tries to use the information in poco fields" do assert user.name == "Constance Variable" assert user.nickname == "lambadalambda@social.heldscal.la" assert user.local == false - assert user.info.uri == uri + assert user.uri == uri assert user.ap_id == uri assert user.bio == "Call me Deacon Blues." assert user.avatar["type"] == "Image" @@ -402,36 +402,34 @@ test "tries to use the information in poco fields" do assert user == user_again end - test "find_or_make_user sets all the nessary input fields" do + test "find_or_make_user sets all the necessary input fields" do uri = "https://social.heldscal.la/user/23211" {:ok, user} = OStatus.find_or_make_user(uri) - assert user.info == - %User.Info{ - id: user.info.id, - ap_enabled: false, - background: %{}, - banner: %{}, - blocks: [], - deactivated: false, - default_scope: "public", - domain_blocks: [], - follower_count: 0, - is_admin: false, - is_moderator: false, - keys: nil, - locked: false, - no_rich_text: false, - note_count: 0, - settings: nil, - source_data: %{}, - hub: "https://social.heldscal.la/main/push/hub", - magic_key: - "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB", - salmon: "https://social.heldscal.la/main/salmon/user/23211", - topic: "https://social.heldscal.la/api/statuses/user_timeline/23211.atom", - uri: "https://social.heldscal.la/user/23211" - } + assert user.ap_enabled == false + assert user.background == %{} + assert user.banner == %{} + assert user.blocks == [] + assert user.deactivated == false + assert user.default_scope == "public" + assert user.domain_blocks == [] + assert user.follower_count == 0 + assert user.is_admin == false + assert user.is_moderator == false + assert user.is_moderator == false + assert is_nil(user.keys) + assert user.locked == false + + assert user.magic_key == + "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB" + + assert user.no_rich_text == false + assert user.note_count == 0 + assert is_nil(user.settings) + assert user.hub == "https://social.heldscal.la/main/push/hub" + assert user.salmon == "https://social.heldscal.la/main/salmon/user/23211" + assert user.topic == "https://social.heldscal.la/api/statuses/user_timeline/23211.atom" + assert user.uri == "https://social.heldscal.la/user/23211" end test "find_make_or_update_actor takes an author element and returns an updated user" do @@ -465,7 +463,7 @@ test "find_or_make_user disallows protocol downgrade" do user = insert(:user, %{ ap_id: "https://social.heldscal.la/user/23211", - info: %{ap_enabled: true}, + ap_enabled: true, local: false }) @@ -484,7 +482,7 @@ test "find_make_or_update_actor disallows protocol downgrade" do user = insert(:user, %{ ap_id: "https://social.heldscal.la/user/23211", - info: %{ap_enabled: true}, + ap_enabled: true, local: false }) diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs index 3b4665afd..c809f510f 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/web/pleroma_api/controllers/account_controller_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Config - alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -20,10 +19,10 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do setup do {:ok, user} = insert(:user) - |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true)) - |> Repo.update() + |> User.confirmation_changeset(need_confirmation: true) + |> User.update_and_set_cache() - assert user.info.confirmation_pending + assert user.confirmation_pending [user: user] end @@ -105,7 +104,7 @@ test "can set profile banner", %{conn: conn} do |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image}) user = refresh_record(user) - assert user.info.banner["type"] == "Image" + assert user.banner["type"] == "Image" assert %{"url" => _} = json_response(conn, 200) end @@ -119,7 +118,7 @@ test "can reset profile banner", %{conn: conn} do |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""}) user = refresh_record(user) - assert user.info.banner == %{} + assert user.banner == %{} assert %{"url" => nil} = json_response(conn, 200) end @@ -135,7 +134,7 @@ test "background image can be set", %{conn: conn} do |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image}) user = refresh_record(user) - assert user.info.background["type"] == "Image" + assert user.background["type"] == "Image" assert %{"url" => _} = json_response(conn, 200) end @@ -148,14 +147,14 @@ test "background image can be reset", %{conn: conn} do |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""}) user = refresh_record(user) - assert user.info.background == %{} + assert user.background == %{} assert %{"url" => nil} = json_response(conn, 200) end end describe "getting favorites timeline of specified user" do setup do - [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}}) + [current_user, user] = insert_pair(:user, hide_favorites: false) [current_user: current_user, user: user] end @@ -319,7 +318,7 @@ test "returns 403 error when user has hidden own favorites", %{ conn: conn, current_user: current_user } do - user = insert(:user, %{info: %{hide_favorites: true}}) + user = insert(:user, hide_favorites: true) activity = insert(:note_activity) CommonAPI.favorite(activity.id, user) @@ -341,7 +340,7 @@ test "hides favorites for new users by default", %{conn: conn, current_user: cur |> assign(:user, current_user) |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - assert user.info.hide_favorites + assert user.hide_favorites assert json_response(conn, 403) == %{"error" => "Can't get favorites"} end end diff --git a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs index 5f74460e8..3d3becefd 100644 --- a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs @@ -38,7 +38,7 @@ test "shared & non-shared pack information in list_packs is ok" do end test "listing remote packs" do - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() |> assign(:user, admin) resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) @@ -121,7 +121,7 @@ test "downloading shared & unshared packs from another instance via download_fro text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) end) - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() |> assign(:user, admin) @@ -206,7 +206,7 @@ test "downloading shared & unshared packs from another instance via download_fro end) {:ok, - admin: insert(:user, info: %{is_admin: true}), + admin: insert(:user, is_admin: true), pack_file: pack_file, new_data: %{ "license" => "Test license changed", @@ -303,7 +303,7 @@ test "updating pack files" do File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2") end) - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() @@ -391,7 +391,7 @@ test "creating and deleting a pack" do File.rm_rf!("#{@emoji_dir_path}/test_created") end) - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) conn = build_conn() |> assign(:user, admin) @@ -431,7 +431,7 @@ test "filesystem import" do refute Map.has_key?(resp, "test_pack_for_import") - admin = insert(:user, info: %{is_admin: true}) + admin = insert(:user, is_admin: true) assert conn |> assign(:user, admin) diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs index 153ec41ac..a3ef80c9a 100644 --- a/test/web/salmon/salmon_test.exs +++ b/test/web/salmon/salmon_test.exs @@ -71,9 +71,7 @@ test "it gets a magic key" do [:passthrough], [] do user_data = %{ - info: %{ - salmon: "http://test-example.org/salmon" - }, + salmon: "http://test-example.org/salmon", local: false } diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index d33eb1e42..400f3287d 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -213,7 +213,7 @@ test "it sends message if recipients invalid and thread containment is disabled" test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do Pleroma.Config.put([:instance, :skip_thread_containment], false) author = insert(:user) - user = insert(:user, following: [author.ap_id], info: %{skip_thread_containment: true}) + user = insert(:user, following: [author.ap_id], skip_thread_containment: true) activity = insert(:note_activity, diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs index dc6d4e3e3..840c84a05 100644 --- a/test/web/twitter_api/password_controller_test.exs +++ b/test/web/twitter_api/password_controller_test.exs @@ -59,7 +59,7 @@ test "it returns HTTP 200", %{conn: conn} do end test "it sets password_reset_pending to false", %{conn: conn} do - user = insert(:user, info: %{password_reset_pending: true}) + user = insert(:user, password_reset_pending: true) {:ok, token} = PasswordResetToken.create_token(user) {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{}) @@ -75,7 +75,7 @@ test "it sets password_reset_pending to false", %{conn: conn} do |> post("/api/pleroma/password_reset", %{data: params}) |> html_response(:ok) - assert User.get_by_id(user.id).info.password_reset_pending == false + assert User.get_by_id(user.id).password_reset_pending == false end end end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index d1d61d11a..85a9be3e0 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -71,7 +71,7 @@ test "it sends confirmation email if :account_activation_required is specified i {:ok, user} = TwitterAPI.register_user(data) ObanHelpers.perform_all() - assert user.info.confirmation_pending + assert user.confirmation_pending email = Pleroma.Emails.UserEmail.account_confirmation_email(user) diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 9d4cb70f0..246da4da4 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -164,7 +164,7 @@ test "it updates notification settings", %{conn: conn} do "follows" => true, "non_follows" => true, "non_followers" => true - } == user.info.notification_settings + } == user.notification_settings end end @@ -370,7 +370,7 @@ test "follows user", %{conn: conn} do end test "returns error when user is deactivated", %{conn: conn} do - user = insert(:user, info: %{deactivated: true}) + user = insert(:user, deactivated: true) user2 = insert(:user) response = @@ -568,7 +568,7 @@ test "it returns HTTP 200", %{conn: conn} do user = User.get_cached_by_id(user.id) - assert user.info.deactivated == true + assert user.deactivated == true end test "it returns returns when password invalid", %{conn: conn} do @@ -583,7 +583,7 @@ test "it returns returns when password invalid", %{conn: conn} do assert response == %{"error" => "Invalid password."} user = User.get_cached_by_id(user.id) - refute user.info.deactivated + refute user.deactivated end end diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs index 46ca545de..eae4013be 100644 --- a/test/web/websub/websub_test.exs +++ b/test/web/websub/websub_test.exs @@ -109,7 +109,7 @@ def accepting_verifier(subscription) do test "initiate a subscription for a given user and topic" do subscriber = insert(:user) - user = insert(:user, %{info: %Pleroma.User.Info{topic: "some_topic", hub: "some_hub"}}) + user = insert(:user, topic: "some_topic", hub: "some_hub") {:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1) assert websub.subscribers == [subscriber.ap_id] From 66b5d0ff558bffeddf6475af72b73bf2870512f6 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 17 Oct 2019 15:26:59 +0300 Subject: [PATCH 02/28] add Markers /api/v1/markers --- lib/pleroma/marker.ex | 74 +++++++++++ .../controllers/marker_controller.ex | 32 +++++ .../web/mastodon_api/views/marker_view.ex | 17 +++ lib/pleroma/web/router.ex | 3 + .../20191014181019_create_markers.exs | 15 +++ test/marker_test.exs | 51 +++++++ test/support/factory.ex | 9 ++ .../controllers/marker_controller_test.exs | 124 ++++++++++++++++++ .../mastodon_api/views/marker_view_test.exs | 27 ++++ 9 files changed, 352 insertions(+) create mode 100644 lib/pleroma/marker.ex create mode 100644 lib/pleroma/web/mastodon_api/controllers/marker_controller.ex create mode 100644 lib/pleroma/web/mastodon_api/views/marker_view.ex create mode 100644 priv/repo/migrations/20191014181019_create_markers.exs create mode 100644 test/marker_test.exs create mode 100644 test/web/mastodon_api/controllers/marker_controller_test.exs create mode 100644 test/web/mastodon_api/views/marker_view_test.exs diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex new file mode 100644 index 000000000..7f87c86c3 --- /dev/null +++ b/lib/pleroma/marker.ex @@ -0,0 +1,74 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Marker do + use Ecto.Schema + + import Ecto.Changeset + import Ecto.Query + + alias Ecto.Multi + alias Pleroma.Repo + alias Pleroma.User + + @timelines ["notifications"] + + schema "markers" do + field(:last_read_id, :string, default: "") + field(:timeline, :string, default: "") + field(:lock_version, :integer, default: 0) + + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + timestamps() + end + + def get_markers(user, timelines \\ []) do + Repo.all(get_query(user, timelines)) + end + + def upsert(%User{} = user, attrs) do + attrs + |> Map.take(@timelines) + |> Enum.reduce(Multi.new(), fn {timeline, timeline_attrs}, multi -> + marker = + user + |> get_marker(timeline) + |> changeset(timeline_attrs) + + Multi.insert(multi, timeline, marker, + returning: true, + on_conflict: {:replace, [:last_read_id]}, + conflict_target: [:user_id, :timeline] + ) + end) + |> Repo.transaction() + end + + defp get_marker(user, timeline) do + case Repo.find_resource(get_query(user, timeline)) do + {:ok, marker} -> %__MODULE__{marker | user: user} + _ -> %__MODULE__{timeline: timeline, user_id: user.id} + end + end + + @doc false + defp changeset(marker, attrs) do + marker + |> cast(attrs, [:last_read_id]) + |> validate_required([:user_id, :timeline, :last_read_id]) + |> validate_inclusion(:timeline, @timelines) + end + + defp by_timeline(query, timeline) do + from(m in query, where: m.timeline in ^List.wrap(timeline)) + end + + defp by_user_id(query, id), do: from(m in query, where: m.user_id == ^id) + + defp get_query(user, timelines) do + __MODULE__ + |> by_user_id(user.id) + |> by_timeline(timelines) + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex new file mode 100644 index 000000000..ce025624d --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MarkerController do + use Pleroma.Web, :controller + alias Pleroma.Plugs.OAuthScopesPlug + + plug( + OAuthScopesPlug, + %{scopes: ["read:statuses"]} + when action == :index + ) + + plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action == :upsert) + plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + # GET /api/v1/markers + def index(%{assigns: %{user: user}} = conn, params) do + markers = Pleroma.Marker.get_markers(user, params["timeline"]) + render(conn, "markers.json", %{markers: markers}) + end + + # POST /api/v1/markers + def upsert(%{assigns: %{user: user}} = conn, params) do + with {:ok, result} <- Pleroma.Marker.upsert(user, params), + markers <- Map.values(result) do + render(conn, "markers.json", %{markers: markers}) + end + end +end diff --git a/lib/pleroma/web/mastodon_api/views/marker_view.ex b/lib/pleroma/web/mastodon_api/views/marker_view.ex new file mode 100644 index 000000000..38fbeed5f --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/marker_view.ex @@ -0,0 +1,17 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MarkerView do + use Pleroma.Web, :view + + def render("markers.json", %{markers: markers}) do + Enum.reduce(markers, %{}, fn m, acc -> + Map.put_new(acc, m.timeline, %{ + last_read_id: m.last_read_id, + version: m.lock_version, + updated_at: NaiveDateTime.to_iso8601(m.updated_at) + }) + end) + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ae799b8ac..45684284c 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -394,6 +394,9 @@ defmodule Pleroma.Web.Router do get("/push/subscription", SubscriptionController, :get) put("/push/subscription", SubscriptionController, :update) delete("/push/subscription", SubscriptionController, :delete) + + get("/markers", MarkerController, :index) + post("/markers", MarkerController, :upsert) end scope "/api/web", Pleroma.Web do diff --git a/priv/repo/migrations/20191014181019_create_markers.exs b/priv/repo/migrations/20191014181019_create_markers.exs new file mode 100644 index 000000000..c717831ba --- /dev/null +++ b/priv/repo/migrations/20191014181019_create_markers.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.CreateMarkers do + use Ecto.Migration + + def change do + create_if_not_exists table(:markers) do + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:timeline, :string, default: "", null: false) + add(:last_read_id, :string, default: "", null: false) + add(:lock_version, :integer, default: 0, null: false) + timestamps() + end + + create_if_not_exists(unique_index(:markers, [:user_id, :timeline])) + end +end diff --git a/test/marker_test.exs b/test/marker_test.exs new file mode 100644 index 000000000..04bd67fe6 --- /dev/null +++ b/test/marker_test.exs @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.MarkerTest do + use Pleroma.DataCase + alias Pleroma.Marker + + import Pleroma.Factory + + describe "get_markers/2" do + test "returns user markers" do + user = insert(:user) + marker = insert(:marker, user: user) + insert(:marker, timeline: "home", user: user) + assert Marker.get_markers(user, ["notifications"]) == [refresh_record(marker)] + end + end + + describe "upsert/2" do + test "creates a marker" do + user = insert(:user) + + {:ok, %{"notifications" => %Marker{} = marker}} = + Marker.upsert( + user, + %{"notifications" => %{"last_read_id" => "34"}} + ) + + assert marker.timeline == "notifications" + assert marker.last_read_id == "34" + assert marker.lock_version == 0 + end + + test "updates exist marker" do + user = insert(:user) + marker = insert(:marker, user: user, last_read_id: "8909") + + {:ok, %{"notifications" => %Marker{}}} = + Marker.upsert( + user, + %{"notifications" => %{"last_read_id" => "9909"}} + ) + + marker = refresh_record(marker) + assert marker.timeline == "notifications" + assert marker.last_read_id == "9909" + assert marker.lock_version == 0 + end + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index b180844cd..4537c458b 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -397,4 +397,13 @@ def config_factory do ) } end + + def marker_factory do + %Pleroma.Marker{ + user: build(:user), + timeline: "notifications", + lock_version: 0, + last_read_id: "1" + } + end end diff --git a/test/web/mastodon_api/controllers/marker_controller_test.exs b/test/web/mastodon_api/controllers/marker_controller_test.exs new file mode 100644 index 000000000..1fcad873d --- /dev/null +++ b/test/web/mastodon_api/controllers/marker_controller_test.exs @@ -0,0 +1,124 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + + describe "GET /api/v1/markers" do + test "gets markers with correct scopes", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: ["read:statuses"]) + + {:ok, %{"notifications" => marker}} = + Pleroma.Marker.upsert( + user, + %{"notifications" => %{"last_read_id" => "69420"}} + ) + + response = + conn + |> assign(:user, user) + |> assign(:token, token) + |> get("/api/v1/markers", %{timeline: ["notifications"]}) + |> json_response(200) + + assert response == %{ + "notifications" => %{ + "last_read_id" => "69420", + "updated_at" => NaiveDateTime.to_iso8601(marker.updated_at), + "version" => 0 + } + } + end + + test "gets markers with missed scopes", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: []) + + Pleroma.Marker.upsert(user, %{"notifications" => %{"last_read_id" => "69420"}}) + + response = + conn + |> assign(:user, user) + |> assign(:token, token) + |> get("/api/v1/markers", %{timeline: ["notifications"]}) + |> json_response(403) + + assert response == %{"error" => "Insufficient permissions: read:statuses."} + end + end + + describe "POST /api/v1/markers" do + test "creates a marker with correct scopes", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: ["write:statuses"]) + + response = + conn + |> assign(:user, user) + |> assign(:token, token) + |> post("/api/v1/markers", %{ + home: %{last_read_id: "777"}, + notifications: %{"last_read_id" => "69420"} + }) + |> json_response(200) + + assert %{ + "notifications" => %{ + "last_read_id" => "69420", + "updated_at" => _, + "version" => 0 + } + } = response + end + + test "updates exist marker", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: ["write:statuses"]) + + {:ok, %{"notifications" => marker}} = + Pleroma.Marker.upsert( + user, + %{"notifications" => %{"last_read_id" => "69477"}} + ) + + response = + conn + |> assign(:user, user) + |> assign(:token, token) + |> post("/api/v1/markers", %{ + home: %{last_read_id: "777"}, + notifications: %{"last_read_id" => "69888"} + }) + |> json_response(200) + + assert response == %{ + "notifications" => %{ + "last_read_id" => "69888", + "updated_at" => NaiveDateTime.to_iso8601(marker.updated_at), + "version" => 0 + } + } + end + + test "creates a marker with missed scopes", %{conn: conn} do + user = insert(:user) + token = insert(:oauth_token, user: user, scopes: []) + + response = + conn + |> assign(:user, user) + |> assign(:token, token) + |> post("/api/v1/markers", %{ + home: %{last_read_id: "777"}, + notifications: %{"last_read_id" => "69420"} + }) + |> json_response(403) + + assert response == %{"error" => "Insufficient permissions: write:statuses."} + end + end +end diff --git a/test/web/mastodon_api/views/marker_view_test.exs b/test/web/mastodon_api/views/marker_view_test.exs new file mode 100644 index 000000000..8a5c89d56 --- /dev/null +++ b/test/web/mastodon_api/views/marker_view_test.exs @@ -0,0 +1,27 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do + use Pleroma.DataCase + alias Pleroma.Web.MastodonAPI.MarkerView + import Pleroma.Factory + + test "returns markers" do + marker1 = insert(:marker, timeline: "notifications", last_read_id: "17") + marker2 = insert(:marker, timeline: "home", last_read_id: "42") + + assert MarkerView.render("markers.json", %{markers: [marker1, marker2]}) == %{ + "home" => %{ + last_read_id: "42", + updated_at: NaiveDateTime.to_iso8601(marker2.updated_at), + version: 0 + }, + "notifications" => %{ + last_read_id: "17", + updated_at: NaiveDateTime.to_iso8601(marker1.updated_at), + version: 0 + } + } + end +end From 152caef51d69ba4a47ac59346c782dfff8488f8b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 18 Oct 2019 17:51:34 -0500 Subject: [PATCH 03/28] Direct messages should provide a distinct push notification subject --- lib/pleroma/web/push/impl.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index 35d3ff07c..dd445e8bf 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -125,6 +125,10 @@ def format_body( end end + def format_title(%{activity: %{data: %{"directMessage" => true}}}) do + "New Direct Message" + end + def format_title(%{activity: %{data: %{"type" => type}}}) do case type do "Create" -> "New Mention" From e7333db72ade8214ad80122d49862e520b093e8a Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 5 Oct 2019 20:06:03 +0000 Subject: [PATCH 04/28] user info: add invisible field --- lib/pleroma/user/info.ex | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 2d39abcb3..53525b386 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -53,6 +53,7 @@ defmodule Pleroma.User.Info do field(:fields, {:array, :map}, default: nil) field(:raw_fields, {:array, :map}, default: []) field(:discoverable, :boolean, default: false) + field(:invisible, :boolean, default: false) field(:notification_settings, :map, default: %{ @@ -393,6 +394,14 @@ def set_source_data(info, source_data) do |> validate_required([:source_data]) end + def set_invisible(info, invisible) do + params = %{invisible: invisible} + + info + |> cast(params, [:invisible]) + |> validate_required([:invisible]) + end + def admin_api_update(info, params) do info |> cast(params, [ From 1469a084d4c95d24619f88c462601570f85ecfa2 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 5 Oct 2019 20:06:31 +0000 Subject: [PATCH 05/28] relay: set invisible to true --- lib/pleroma/web/activity_pub/relay.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 03fc434a9..de80612f1 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -10,8 +10,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do require Logger def get_actor do - "#{Pleroma.Web.Endpoint.url()}/relay" - |> User.get_or_create_service_actor_by_ap_id() + actor = + "#{Pleroma.Web.Endpoint.url()}/relay" + |> User.get_or_create_service_actor_by_ap_id() + + {:ok, actor} = User.update_info(actor, &User.Info.set_invisible(&1, true)) + actor end @spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()} From 95871cb4628933900f2004a8bece1b929d5525bf Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 5 Oct 2019 20:11:43 +0000 Subject: [PATCH 06/28] user: implement User.invisible?/1 --- lib/pleroma/user.ex | 3 +++ test/user_test.exs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ec705b8f6..2bbfaa55b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -88,6 +88,9 @@ 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 invisible?(%User{info: %User.Info{invisible: true}}), do: true + def invisible?(_), do: false + def avatar_url(user, options \\ []) do case user.avatar do %{"url" => [%{"href" => href} | _]} -> href diff --git a/test/user_test.exs b/test/user_test.exs index ad050b7da..05bdb9a61 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1232,6 +1232,20 @@ test "returns true for local admins" do end end + describe "invisible?/1" do + test "returns true for an invisible user" do + user = insert(:user, local: true, info: %{invisible: true}) + + assert User.invisible?(user) + end + + test "returns false for a non-invisible user" do + user = insert(:user, local: true) + + refute User.invisible?(user) + end + end + describe "visible_for?/2" do test "returns true when the account is itself" do user = insert(:user, local: true) From ef659331b03925c41cd3e557bd39cb2d73dd6aa1 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 5 Oct 2019 20:41:33 +0000 Subject: [PATCH 07/28] implement invisible support for remote users --- lib/pleroma/user/info.ex | 3 +- lib/pleroma/web/activity_pub/activity_pub.ex | 10 +++- .../web/activity_pub/transmogrifier.ex | 11 +++- lib/pleroma/web/activity_pub/utils.ex | 10 ++-- .../tesla_mock/relay@mastdon.example.org.json | 54 +++++++++++++++++++ test/support/http_request_mock.ex | 8 +++ test/web/activity_pub/activity_pub_test.exs | 6 +++ 7 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/tesla_mock/relay@mastdon.example.org.json diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 53525b386..982fb61c6 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -267,7 +267,8 @@ def remote_user_creation(info, params) do :follower_count, :fields, :following_count, - :discoverable + :discoverable, + :invisible ]) |> validate_fields(true) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 94c467b69..1cfe826fa 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1107,6 +1107,13 @@ defp object_to_user_data(data) do data = Transmogrifier.maybe_fix_user_object(data) discoverable = data["discoverable"] || false + invisible = + if is_list(data["type"]) do + Enum.member?(data["type"], "Invisible") + else + false + end + user_data = %{ ap_id: data["id"], info: %{ @@ -1115,7 +1122,8 @@ defp object_to_user_data(data) do banner: banner, fields: fields, locked: locked, - discoverable: discoverable + discoverable: discoverable, + invisible: invisible }, avatar: avatar, name: data["name"], diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 2c1ce9c55..49bbeb857 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -596,13 +596,20 @@ def handle_incoming( data, _options ) - when object_type in ["Person", "Application", "Service", "Organization"] do + when object_type in [ + "Person", + "Application", + "Service", + "Organization", + ["Application", "Invisible"] + ] do with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) banner = new_user_data[:info][:banner] locked = new_user_data[:info][:locked] || false attachment = get_in(new_user_data, [:info, :source_data, "attachment"]) || [] + invisible = new_user_data[:info][:invisible] || false fields = attachment @@ -612,7 +619,7 @@ def handle_incoming( update_data = new_user_data |> Map.take([:name, :bio, :avatar]) - |> Map.put(:info, %{banner: banner, locked: locked, fields: fields}) + |> Map.put(:info, %{banner: banner, locked: locked, fields: fields, invisible: invisible}) actor |> User.upgrade_changeset(update_data, true) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 4ef479f96..6b28df92c 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -491,10 +491,14 @@ def add_announce_to_object( %Activity{data: %{"actor" => actor}}, object ) do - announcements = take_announcements(object) + unless actor |> User.get_cached_by_ap_id() |> User.invisible?() do + announcements = take_announcements(object) - with announcements <- Enum.uniq([actor | announcements]) do - update_element_in_object("announcement", announcements, object) + with announcements <- Enum.uniq([actor | announcements]) do + update_element_in_object("announcement", announcements, object) + end + else + {:ok, object} end end diff --git a/test/fixtures/tesla_mock/relay@mastdon.example.org.json b/test/fixtures/tesla_mock/relay@mastdon.example.org.json new file mode 100644 index 000000000..b70be2bf4 --- /dev/null +++ b/test/fixtures/tesla_mock/relay@mastdon.example.org.json @@ -0,0 +1,54 @@ +{ + "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": "as:movedTo", + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji" + }], + "id": "http://mastodon.example.org/users/admin", + "type": ["Application", "Invisible"], + "following": "http://mastodon.example.org/users/admin/following", + "followers": "http://mastodon.example.org/users/admin/followers", + "inbox": "http://mastodon.example.org/users/admin/inbox", + "outbox": "http://mastodon.example.org/users/admin/outbox", + "preferredUsername": "admin", + "name": null, + "summary": "\u003cp\u003e\u003c/p\u003e", + "url": "http://mastodon.example.org/@admin", + "manuallyApprovesFollowers": false, + "publicKey": { + "id": "http://mastodon.example.org/users/admin#main-key", + "owner": "http://mastodon.example.org/users/admin", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtc4Tir+3ADhSNF6VKrtW\nOU32T01w7V0yshmQei38YyiVwVvFu8XOP6ACchkdxbJ+C9mZud8qWaRJKVbFTMUG\nNX4+6Q+FobyuKrwN7CEwhDALZtaN2IPbaPd6uG1B7QhWorrY+yFa8f2TBM3BxnUy\nI4T+bMIZIEYG7KtljCBoQXuTQmGtuffO0UwJksidg2ffCF5Q+K//JfQagJ3UzrR+\nZXbKMJdAw4bCVJYs4Z5EhHYBwQWiXCyMGTd7BGlmMkY6Av7ZqHKC/owp3/0EWDNz\nNqF09Wcpr3y3e8nA10X40MJqp/wR+1xtxp+YGbq/Cj5hZGBG7etFOmIpVBrDOhry\nBwIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "attachment": [{ + "type": "PropertyValue", + "name": "foo", + "value": "bar" + }, + { + "type": "PropertyValue", + "name": "foo1", + "value": "bar1" + } + ], + "endpoints": { + "sharedInbox": "http://mastodon.example.org/inbox" + }, + "icon": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" + }, + "image": { + "type": "Image", + "mediaType": "image/png", + "url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" + } +} diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 7d65209fb..eba22c40b 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -348,6 +348,14 @@ def get("http://mastodon.example.org/users/admin", _, _, Accept: "application/ac }} end + def get("http://mastodon.example.org/users/relay", _, _, Accept: "application/activity+json") do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json") + }} + end + def get("http://mastodon.example.org/users/gargron", _, _, Accept: "application/activity+json") do {:error, :nxdomain} end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 28a9b773c..b87050a4a 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -179,6 +179,12 @@ test "it returns a user" do assert user.follower_address == "http://mastodon.example.org/users/admin/followers" end + test "it returns a user that is invisible" do + user_id = "http://mastodon.example.org/users/relay" + {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) + assert user.info.invisible + end + test "it fetches the appropriate tag-restricted posts" do user = insert(:user) From 80d3912a56816e4cb136a33a7aafcb0d0fede0fa Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 8 Oct 2019 20:59:43 +0000 Subject: [PATCH 08/28] test: activitypub: use User.invisible?/1 for testing invisibility --- test/web/activity_pub/activity_pub_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index b87050a4a..8ae946969 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -182,7 +182,7 @@ test "it returns a user" do test "it returns a user that is invisible" do user_id = "http://mastodon.example.org/users/relay" {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) - assert user.info.invisible + assert User.invisible?(user) end test "it fetches the appropriate tag-restricted posts" do From 9694d514371a454d320b0129332c28a4695fd340 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 14 Oct 2019 09:09:32 +0300 Subject: [PATCH 09/28] added test fo Pleroma.Web.MastodonAPI.StatusController --- .../controllers/status_controller_test.exs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 2de2725e0..7b52abdce 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -12,6 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.ScheduledActivity + alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI @@ -29,6 +30,34 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do [conn: conn] end + test "posting a status and checks reblog count after perform all backroud job", %{conn: conn} do + Pleroma.Config.put([:instance, :federating], true) + Pleroma.Config.get([:instance, :allow_relay], true) + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("api/v1/statuses", %{ + "content_type" => "text/plain", + "source" => "Pleroma FE", + "status" => "Hello world", + "visibility" => "public" + }) + |> json_response(200) + + assert response["reblogs_count"] == 0 + ObanHelpers.perform_all() + + response = + conn + |> assign(:user, user) + |> get("api/v1/statuses/#{response["id"]}", %{}) + |> json_response(200) + + assert response["reblogs_count"] == 0 + end + test "posting a status", %{conn: conn} do idempotency_key = "Pikachu rocks!" From 189a2889258038ae9372113e5d901f18b7417a82 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 14 Oct 2019 09:31:08 +0300 Subject: [PATCH 10/28] fix test --- test/web/mastodon_api/controllers/status_controller_test.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 7b52abdce..ce964359b 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -19,6 +19,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do import Pleroma.Factory + clear_config([:instance, :federating]) + clear_config([:instance, :allow_relay]) + describe "posting statuses" do setup do user = insert(:user) From c9280b97306b894a38377acf43c62d7808df01d8 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 19 Oct 2019 17:46:24 +0000 Subject: [PATCH 11/28] rework to use properties instead of compound typing, per SocialCG --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 +------- lib/pleroma/web/activity_pub/transmogrifier.ex | 3 +-- lib/pleroma/web/activity_pub/views/user_view.ex | 3 ++- priv/static/schemas/litepub-0.1.jsonld | 1 + test/fixtures/tesla_mock/relay@mastdon.example.org.json | 3 ++- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1cfe826fa..9a0a3522a 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1106,13 +1106,7 @@ defp object_to_user_data(data) do locked = data["manuallyApprovesFollowers"] || false data = Transmogrifier.maybe_fix_user_object(data) discoverable = data["discoverable"] || false - - invisible = - if is_list(data["type"]) do - Enum.member?(data["type"], "Invisible") - else - false - end + invisible = data["invisible"] || false user_data = %{ ap_id: data["id"], diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 49bbeb857..4a250d131 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -600,8 +600,7 @@ def handle_incoming( "Person", "Application", "Service", - "Organization", - ["Application", "Invisible"] + "Organization" ] do with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 9b39d1629..8c5b4460b 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -55,7 +55,8 @@ def render("service.json", %{user: user}) do "owner" => user.ap_id, "publicKeyPem" => public_key }, - "endpoints" => endpoints + "endpoints" => endpoints, + "invisible" => User.invisible?(user) } |> Map.merge(Utils.make_json_ld_header()) end diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld index 1cfcb7ec7..c8e69cab5 100644 --- a/priv/static/schemas/litepub-0.1.jsonld +++ b/priv/static/schemas/litepub-0.1.jsonld @@ -19,6 +19,7 @@ "value": "schema:value", "sensitive": "as:sensitive", "litepub": "http://litepub.social/ns#", + "invisible": "litepub:invisible", "directMessage": "litepub:directMessage", "listMessage": { "@id": "litepub:listMessage", diff --git a/test/fixtures/tesla_mock/relay@mastdon.example.org.json b/test/fixtures/tesla_mock/relay@mastdon.example.org.json index b70be2bf4..c1fab7d3b 100644 --- a/test/fixtures/tesla_mock/relay@mastdon.example.org.json +++ b/test/fixtures/tesla_mock/relay@mastdon.example.org.json @@ -12,7 +12,8 @@ "Emoji": "toot:Emoji" }], "id": "http://mastodon.example.org/users/admin", - "type": ["Application", "Invisible"], + "type": "Application", + "invisible": true, "following": "http://mastodon.example.org/users/admin/following", "followers": "http://mastodon.example.org/users/admin/followers", "inbox": "http://mastodon.example.org/users/admin/inbox", From 52d56ed705232b7b3b43d78aaef7c5170a5c1217 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 19 Oct 2019 17:50:17 +0000 Subject: [PATCH 12/28] tests: add test verifying the relay user is invisible --- test/web/activity_pub/relay_test.exs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 4a0a03944..ac2007b2c 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do alias Pleroma.Activity alias Pleroma.Object + alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay @@ -19,6 +20,11 @@ test "gets an actor for the relay" do assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay" end + test "relay actor is invisible" do + user = Relay.get_actor() + assert User.invisible?(user) + end + describe "follow/1" do test "returns errors when user not found" do assert capture_log(fn -> From ba92522c6902c2992f0b9fa50aaded1087e125ba Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 19 Oct 2019 17:53:52 +0000 Subject: [PATCH 13/28] tests: add test to ensure invisible actors are rendered with the invisible hint set to true --- test/web/activity_pub/views/user_view_test.exs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 3155749aa..a31b4c92e 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -76,6 +76,12 @@ test "Does not add an avatar image if the user hasn't set one" do assert result["image"]["url"] == "https://somebanner" end + test "renders an invisible user with the invisible property set to true" do + user = insert(:user, %{info: %{invisible: true}}) + + assert %{"invisible" => true} = UserView.render("service.json", %{user: user}) + end + describe "endpoints" do test "local users have a usable endpoints structure" do user = insert(:user) From 05c58eaecef3d51b567ff1529aa33f36e03f5452 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 19 Oct 2019 23:23:13 +0000 Subject: [PATCH 14/28] change Maksim's test description --- test/web/mastodon_api/controllers/status_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index ce964359b..4da610b28 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -33,7 +33,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do [conn: conn] end - test "posting a status and checks reblog count after perform all backroud job", %{conn: conn} do + test "posting a status does not increment reblog_count when relaying", %{conn: conn} do Pleroma.Config.put([:instance, :federating], true) Pleroma.Config.get([:instance, :allow_relay], true) user = insert(:user) From e8843974cb9b8adfe8798bb8f7ff17b7a92f5ab8 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 20 Oct 2019 13:42:42 +0300 Subject: [PATCH 15/28] [#1304] Moved remaining fields from User.Info to User. Misc. fixes / improvements. --- docs/API/admin_api.md | 4 +- lib/mix/tasks/pleroma/user.ex | 16 +- lib/pleroma/notification.ex | 6 +- lib/pleroma/user.ex | 228 ++++++++++++++---- lib/pleroma/user/info.ex | 107 -------- lib/pleroma/user/search.ex | 4 +- lib/pleroma/web/activity_pub/activity_pub.ex | 18 +- lib/pleroma/web/common_api/common_api.ex | 8 +- .../controllers/account_controller.ex | 6 +- .../controllers/domain_block_controller.ex | 4 +- lib/pleroma/web/streamer/worker.ex | 8 +- .../web/twitter_api/twitter_api_controller.ex | 4 +- ...154608_copy_users_info_fields_to_users.exs | 139 ++++++++++- test/user_test.exs | 8 +- 14 files changed, 355 insertions(+), 205 deletions(-) delete mode 100644 lib/pleroma/user/info.ex diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md index ee9e68cb1..b56f53967 100644 --- a/docs/API/admin_api.md +++ b/docs/API/admin_api.md @@ -160,7 +160,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: none - Response: - On failure: `{"error": "…"}` - - On success: JSON of the `user.info` + - On success: JSON of the user ### Remove user from permission group @@ -168,7 +168,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: none - Response: - 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. ## `/api/pleroma/admin/users/:nickname/activation_status` diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 265c5f1a7..d7bdc2310 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -5,6 +5,7 @@ defmodule Mix.Tasks.Pleroma.User do use Mix.Task import Mix.Pleroma + alias Ecto.Changeset alias Pleroma.User alias Pleroma.UserInviteToken alias Pleroma.Web.OAuth @@ -364,21 +365,30 @@ def run(["sign_out", nickname]) do end 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}") user end 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}") user end 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}") user diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 19d22370f..6ded91f3c 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -58,11 +58,11 @@ def for_user_query(user, opts \\ []) do if opts[:with_muted] do query else - where(query, [n, a], a.actor not in ^user.info.muted_notifications) - |> where([n, a], a.actor not in ^user.info.blocks) + where(query, [n, a], a.actor not in ^user.muted_notifications) + |> where([n, a], a.actor not in ^user.blocks) |> where( [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, on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 165342011..d16d22198 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -122,7 +122,8 @@ defmodule Pleroma.User do has_many(:notifications, Notification) has_many(:registrations, Registration) has_many(:deliveries, Delivery) - embeds_one(:info, User.Info) + + field(:info, :map, default: %{}) timestamps() end @@ -304,14 +305,39 @@ def remote_user_creation(params) do changeset = %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]) |> unique_constraint(:nickname) |> validate_format(:nickname, @email_regex) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) |> validate_fields(true) - |> change_info(& &1) case params[:source_data] do %{"followers" => followers, "following" => following} -> @@ -330,7 +356,31 @@ def update_changeset(struct, params \\ %{}) do name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) 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) |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: bio_limit) @@ -355,15 +405,27 @@ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do :follower_address, :following_address, :avatar, - :last_refreshed_at - ] ++ @info_fields + :last_refreshed_at, + :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) |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, max: name_limit) |> validate_fields(remote?) - |> change_info(& &1) end def password_update_changeset(struct, params) do @@ -426,7 +488,6 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do |> validate_format(:email, @email_regex) |> validate_length(:bio, max: bio_limit) |> validate_length(:name, min: 1, max: name_limit) - |> change_info(& &1) |> maybe_validate_required_email(opts[:external]) |> put_password_hash |> put_ap_id() @@ -884,7 +945,9 @@ def update_note_count(%User{} = user, note_count \\ nil) do ) |> Repo.one() - update_and_set_cache(user, %{note_count: note_count}) + user + |> cast(%{note_count: note_count}, [:note_count]) + |> update_and_set_cache() end @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()} 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 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 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) - update_info(blocker, &User.Info.add_to_block(&1, ap_id)) + add_to_block(blocker, ap_id) end # 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 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 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() def muted_notifications?(nil, _), do: false 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 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_ap_id?(%User{} = user, %User{} = target) do - Enum.member?(user.info.blocks, target.ap_id) + Enum.member?(user.blocks, target.ap_id) end def blocks_ap_id?(_, _), do: false 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) Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) end @@ -1126,13 +1189,13 @@ def subscribed_to?(user, %{ap_id: ap_id}) do @spec muted_users(User.t()) :: [User.t()] 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() end @spec blocked_users(User.t()) :: [User.t()] 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() end @@ -1142,14 +1205,6 @@ def subscribers(user) do |> Repo.all() 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 BackgroundWorker.enqueue("deactivate_user", %{"user_id" => user.id, "status" => status}) end @@ -1385,7 +1440,7 @@ def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do else _ -> {:ok, user} = - %User{info: %User.Info{}} + %User{} |> cast(%{}, [:ap_id, :nickname, :local]) |> put_change(:ap_id, uri) |> put_change(:nickname, nickname) @@ -1549,7 +1604,6 @@ def error_user(ap_id) do %User{ name: ap_id, ap_id: ap_id, - info: %User.Info{}, nickname: "erroruser@example.com", inserted_at: NaiveDateTime.utc_now() } @@ -1562,7 +1616,7 @@ def all_superusers do end 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 @doc """ @@ -1741,28 +1795,6 @@ def update_source_data(user, source_data) do |> update_and_set_cache() 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 %{ admin: is_admin, @@ -1918,4 +1950,96 @@ def add_to_subscribers(user, subscribed) do def remove_from_subscribers(user, subscribed) do set_subscribers(user, List.delete(user.subscribers, subscribed)) 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 diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex deleted file mode 100644 index fe59ddeab..000000000 --- a/lib/pleroma/user/info.ex +++ /dev/null @@ -1,107 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# 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 diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex index 6fb2c2352..7fffb1e55 100644 --- a/lib/pleroma/user/search.ex +++ b/lib/pleroma/user/search.ex @@ -68,14 +68,14 @@ defp search_query(query_string, for_user, following) do defp base_query(_user, false), do: 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 from(q in query, where: not (q.ap_id in ^blocks)) end 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 domains = Enum.join(domain_blocks, ",") diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 78efaae2a..b9e88ec70 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -235,8 +235,6 @@ def create(%{to: to, actor: actor, context: context, object: object} = params, f {:fake, false, activity} <- {:fake, fake, activity}, _ <- increase_replies_count_if_reply(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 <- maybe_federate(activity) do {:ok, activity} @@ -429,8 +427,6 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, options \\ [ {:ok, activity} <- insert(data, local, false), stream_out_participations(object, user), _ <- 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 <- maybe_federate(activity) do {: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, %{"muting_user" => %User{info: info}} = opts) do - mutes = info.mutes + defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do + mutes = user.mutes 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_blocked(query, %{"blocking_user" => %User{info: info}}) do - blocks = info.blocks || [] - domain_blocks = info.domain_blocks || [] + defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do + blocks = user.blocks || [] + domain_blocks = user.domain_blocks || [] 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_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do - muted_reblogs = info.muted_reblogs || [] + defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user}) do + muted_reblogs = user.muted_reblogs || [] from( activity in query, diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index ef738a870..449b808b5 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -392,14 +392,14 @@ defp set_visibility(activity, %{"visibility" => visibility}) do defp set_visibility(activity, _), do: {:ok, activity} def hide_reblogs(user, %{ap_id: ap_id} = _muted) do - if ap_id not in user.info.muted_reblogs do - User.update_info(user, &User.Info.add_reblog_mute(&1, ap_id)) + if ap_id not in user.muted_reblogs do + User.add_reblog_mute(user, ap_id) end end def show_reblogs(user, %{ap_id: ap_id} = _muted) do - if ap_id in user.info.muted_reblogs do - User.update_info(user, &User.Info.remove_reblog_mute(&1, ap_id)) + if ap_id in user.muted_reblogs do + User.remove_reblog_mute(user, ap_id) end end end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 7ba2f9ff1..73fad519e 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -197,11 +197,7 @@ def update_credentials(%{assigns: %{user: original_user}} = conn, params) do |> Enum.dedup() user_params = Map.put(user_params, :emoji, user_emojis) - - changeset = - user - |> User.update_changeset(user_params) - |> User.change_info(& &1) + changeset = User.update_changeset(user, user_params) with {:ok, user} <- User.update_and_set_cache(changeset) do if original_user != user, do: CommonAPI.update(user) diff --git a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex index c7606246b..456fe7ab2 100644 --- a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex @@ -21,8 +21,8 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) @doc "GET /api/v1/domain_blocks" - def index(%{assigns: %{user: %{info: info}}} = conn, _) do - json(conn, Map.get(info, :domain_blocks, [])) + def index(%{assigns: %{user: user}} = conn, _) do + json(conn, Map.get(user, :domain_blocks, [])) end @doc "POST /api/v1/domain_blocks" diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex index 9910c3484..c2ee9e1f5 100644 --- a/lib/pleroma/web/streamer/worker.ex +++ b/lib/pleroma/web/streamer/worker.ex @@ -129,12 +129,12 @@ defp do_stream(%{topic: topic, item: item}) do end defp should_send?(%User{} = user, %Activity{} = item) do - blocks = user.info.blocks || [] - mutes = user.info.mutes || [] - reblog_mutes = user.info.muted_reblogs || [] + blocks = user.blocks || [] + mutes = user.mutes || [] + reblog_mutes = user.muted_reblogs || [] recipient_blocks = MapSet.new(blocks ++ mutes) 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), true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 5eafc01de..39f10c49f 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -23,7 +23,9 @@ def confirm_email(conn, %{"user_id" => uid, "token" => token}) do with %User{} = user <- User.get_cached_by_id(uid), true <- user.local and user.confirmation_pending and user.confirmation_token == token, {: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: "/") end end diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs index b26b122eb..6b096a962 100644 --- a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -1,6 +1,98 @@ defmodule Pleroma.Repo.Migrations.CopyUsersInfoaddsToUsers do 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 alter table(:users) do add(:banner, :map, default: %{}) @@ -8,11 +100,10 @@ def change do add(:source_data, :map, default: %{}) add(:note_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(:locked, :boolean, default: false) - add(:confirmation_pending, :boolean, default: false) - add(:password_reset_pending, :boolean, default: false) + add(:locked, :boolean, default: false, null: false) + add(:confirmation_pending, :boolean, default: false, null: false) + add(:password_reset_pending, :boolean, default: false, null: false) add(:confirmation_token, :text, default: nil) add(:default_scope, :string, default: "public") add(:blocks, {:array, :text}, default: []) @@ -50,5 +141,45 @@ def change do add(:notification_settings, :map, default: %{}) add(:skip_thread_containment, :boolean, default: false, null: false) 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 diff --git a/test/user_test.exs b/test/user_test.exs index 381d8ea27..d96bc9829 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1133,11 +1133,9 @@ test "with overly long fields" do ap_id: user.ap_id, name: user.name, nickname: user.nickname, - info: %{ - fields: [ - %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)} - ] - } + fields: [ + %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)} + ] } assert {:ok, %User{}} = User.insert_or_update_user(data) From b4cbf0568bd6924ded9b9fbdb588a4da92bf83e7 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 20 Oct 2019 13:58:27 +0300 Subject: [PATCH 16/28] [#1304] Analysis issue fix. --- lib/pleroma/user.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index d16d22198..282cf6962 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2014,11 +2014,11 @@ def remove_from_mutes(user, muted) do end end - defp set_notification_mutes(user, _muted_notifications, _notifications? = false) do + defp set_notification_mutes(user, _muted_notifications, false = _notifications?) do {:ok, user} end - defp set_notification_mutes(user, muted_notifications, _notifications? = true) do + defp set_notification_mutes(user, muted_notifications, true = _notifications?) do params = %{muted_notifications: muted_notifications} user From ee04fbc35ad56784614c8cdd3f863da284a5725e Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sun, 20 Oct 2019 22:29:56 +0300 Subject: [PATCH 17/28] [#1304]. Post-merge fixes. Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into 1304-user-info-deprecation # Conflicts: # CHANGELOG.md # lib/pleroma/notification.ex # lib/pleroma/user.ex # lib/pleroma/user/info.ex # lib/pleroma/web/admin_api/admin_api_controller.ex # lib/pleroma/web/ostatus/handlers/follow_handler.ex # lib/pleroma/web/ostatus/ostatus.ex # lib/pleroma/web/salmon/salmon.ex # lib/pleroma/web/websub/websub.ex # test/web/admin_api/admin_api_controller_test.exs # test/web/federator_test.exs # test/web/mastodon_api/controllers/conversation_controller_test.exs # test/web/ostatus/ostatus_controller_test.exs # test/web/ostatus/ostatus_test.exs # test/web/salmon/salmon_test.exs # test/web/websub/websub_test.exs --- docs/API/admin_api.md | 4 +-- lib/pleroma/user.ex | 11 +----- .../web/admin_api/admin_api_controller.ex | 36 +++++-------------- ...154608_copy_users_info_fields_to_users.exs | 6 ---- test/conversation/participation_test.exs | 8 ++--- .../conversation_controller_test.exs | 4 +-- .../pleroma_api_controller_test.exs | 4 +-- 7 files changed, 20 insertions(+), 53 deletions(-) diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md index 6faf1786b..e64ae6429 100644 --- a/docs/API/admin_api.md +++ b/docs/API/admin_api.md @@ -180,7 +180,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - `nicknames`: nicknames array - Response: - On failure: `{"error": "…"}` - - On success: JSON of the `user.info` + - On success: JSON of the user ## DEPRECATED `DELETE /api/pleroma/admin/users/:nickname/permission_group/:permission_group` @@ -200,7 +200,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - `nicknames`: nicknames array - Response: - 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. ## `PATCH /api/pleroma/admin/users/activate` diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e2ebb7d64..89f88c74d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -89,9 +89,6 @@ defmodule Pleroma.User do field(:settings, :map, default: nil) field(:magic_key, :string, default: nil) field(:uri, :string, default: nil) - field(:topic, :string, default: nil) - field(:hub, :string, default: nil) - field(:salmon, :string, default: nil) field(:hide_followers_count, :boolean, default: false) field(:hide_follows_count, :boolean, default: false) field(:hide_followers, :boolean, default: false) @@ -250,9 +247,6 @@ def following_count(%User{} = user) do :settings, :magic_key, :uri, - :topic, - :hub, - :salmon, :hide_followers_count, :hide_follows_count, :hide_followers, @@ -317,9 +311,6 @@ def remote_user_creation(params) do :locked, :magic_key, :uri, - :hub, - :topic, - :salmon, :hide_followers, :hide_follows, :hide_followers_count, @@ -1453,7 +1444,7 @@ def public_key(%{source_data: %{"publicKey" => %{"publicKeyPem" => public_key_pe {:ok, key} end - def public_key_from_info(_), do: {:error, "not found key"} + def public_key(_), 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), diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 66b5276d4..7ffbb23e7 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -51,8 +51,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do :tag_users, :untag_users, :right_add, - :right_delete, - :set_activation_status + :right_delete ] ) @@ -364,11 +363,11 @@ def right_add_multiple(%{assigns: %{user: admin}} = conn, %{ "nicknames" => nicknames }) when permission_group in ["moderator", "admin"] do - info = Map.put(%{}, "is_" <> permission_group, true) + update = %{:"is_#{permission_group}" => true} users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) - User.update_info(users, &User.Info.admin_api_update(&1, info)) + for u <- users, do: User.admin_api_update(u, update) ModerationLog.insert_log(%{ action: "grant", @@ -377,7 +376,7 @@ def right_add_multiple(%{assigns: %{user: admin}} = conn, %{ permission: permission_group }) - json(conn, info) + json(conn, update) end def right_add_multiple(conn, _) do @@ -429,11 +428,11 @@ def right_delete_multiple( ) when permission_group in ["moderator", "admin"] do with false <- Enum.member?(nicknames, admin_nickname) do - info = Map.put(%{}, "is_" <> permission_group, false) + update = %{:"is_#{permission_group}" => false} users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) - User.update_info(users, &User.Info.admin_api_update(&1, info)) + for u <- users, do: User.admin_api_update(u, update) ModerationLog.insert_log(%{ action: "revoke", @@ -442,7 +441,7 @@ def right_delete_multiple( permission: permission_group }) - json(conn, info) + json(conn, update) else _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.") end @@ -481,25 +480,6 @@ def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" render_error(conn, :forbidden, "You can't revoke your own admin status.") end - def set_activation_status(%{assigns: %{user: admin}} = conn, %{ - "nickname" => nickname, - "status" => status - }) do - with {:ok, status} <- Ecto.Type.cast(:boolean, status), - %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, _} <- User.deactivate(user, !status) do - action = if(user.deactivated, do: "activate", else: "deactivate") - - ModerationLog.insert_log(%{ - actor: admin, - subject: user, - action: action - }) - - json_response(conn, :no_content, "") - end - end - def relay_list(conn, _params) do with {:ok, list} <- Relay.list() do json(conn, %{relays: list}) @@ -507,6 +487,8 @@ def relay_list(conn, _params) do _ -> conn |> put_status(500) + end + end def relay_follow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do with {:ok, _message} <- Relay.follow(target) do diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs index 6b096a962..d9df5bb51 100644 --- a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -28,9 +28,6 @@ defmodule Pleroma.Repo.Migrations.CopyUsersInfoaddsToUsers do :settings, :magic_key, :uri, - :topic, - :hub, - :salmon, :hide_followers_count, :hide_follows_count, :hide_followers, @@ -121,9 +118,6 @@ def change do add(:settings, :map, default: nil) add(:magic_key, :text, default: nil) add(:uri, :text, default: nil) - add(:topic, :text, default: nil) - add(:hub, :text, default: nil) - add(:salmon, :text, default: nil) add(:hide_followers_count, :boolean, default: false, null: false) add(:hide_follows_count, :boolean, default: false, null: false) add(:hide_followers, :boolean, default: false, null: false) diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 64c350904..91867bf70 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -36,8 +36,8 @@ test "for a new conversation or a reply, it doesn't mark the author's participat [%{read: true}] = Participation.for_user(user) [%{read: false} = participation] = Participation.for_user(other_user) - assert User.get_cached_by_id(user.id).info.unread_conversation_count == 0 - assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 1 + assert User.get_cached_by_id(user.id).unread_conversation_count == 0 + assert User.get_cached_by_id(other_user.id).unread_conversation_count == 1 {:ok, _} = CommonAPI.post(other_user, %{ @@ -52,8 +52,8 @@ test "for a new conversation or a reply, it doesn't mark the author's participat [%{read: false}] = Participation.for_user(user) [%{read: true}] = Participation.for_user(other_user) - assert User.get_cached_by_id(user.id).info.unread_conversation_count == 1 - assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 0 + assert User.get_cached_by_id(user.id).unread_conversation_count == 1 + assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 end test "for a new conversation, it sets the recipents of the participation" do diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs index b92da665b..542af4944 100644 --- a/test/web/mastodon_api/controllers/conversation_controller_test.exs +++ b/test/web/mastodon_api/controllers/conversation_controller_test.exs @@ -95,8 +95,8 @@ test "the user marks a conversation as read", %{conn: conn} do "visibility" => "direct" }) - assert User.get_cached_by_id(user_one.id).info.unread_conversation_count == 0 - assert User.get_cached_by_id(user_two.id).info.unread_conversation_count == 1 + assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 + assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1 [%{"id" => direct_conversation_id, "unread" => true}] = conn diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index 9cccc8c8a..0c83edb56 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -108,7 +108,7 @@ test "POST /api/v1/pleroma/conversations/read", %{conn: conn} do [participation2, participation1] = Participation.for_user(other_user) assert Participation.get(participation2.id).read == false assert Participation.get(participation1.id).read == false - assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 2 + assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2 [%{"unread" => false}, %{"unread" => false}] = conn @@ -119,7 +119,7 @@ test "POST /api/v1/pleroma/conversations/read", %{conn: conn} do [participation2, participation1] = Participation.for_user(other_user) assert Participation.get(participation2.id).read == true assert Participation.get(participation1.id).read == true - assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 0 + assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 end describe "POST /api/v1/pleroma/notifications/read" do From 75da202ab74489af15e086f06810e22211d52d33 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 21 Oct 2019 10:20:28 +0300 Subject: [PATCH 18/28] [#1304] Typo fix. --- .../20191009154608_copy_users_info_fields_to_users.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs index d9df5bb51..72c852d2b 100644 --- a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -1,4 +1,4 @@ -defmodule Pleroma.Repo.Migrations.CopyUsersInfoaddsToUsers do +defmodule Pleroma.Repo.Migrations.CopyUsersInfoFieldsToUsers do use Ecto.Migration @info_fields [ @@ -136,7 +136,7 @@ def change do add(:skip_thread_containment, :boolean, default: false, null: false) end - if direction == :up do + if direction() == :up do for f <- @info_fields do set_field = "update users set #{f} =" From 31d6ef6f92ff028499faa85945a51fdd6b5fcf89 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 21 Oct 2019 11:53:11 +0300 Subject: [PATCH 19/28] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19cd1e539..d7be06bf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: `POST/DELETE /api/pleroma/admin/users/:nickname/permission_group/:permission_group` are deprecated in favor of: `POST/DELETE /api/pleroma/admin/users/permission_group/:permission_group` (both accept `nicknames` array), `DELETE /api/pleroma/admin/users` (`nickname` query param or `nickname` sent in JSON body) is deprecated in favor of: `DELETE /api/pleroma/admin/users` (`nicknames` query array param or `nicknames` sent in JSON body). - Admin API: Add `GET /api/pleroma/admin/relay` endpoint - lists all followed relays - Pleroma API: `POST /api/v1/pleroma/conversations/read` to mark all conversations as read +- Mastodon API: Add `/api/v1/markers` for managing timeline read markers ### Changed - **Breaking:** Elixir >=1.8 is now required (was >= 1.7) From 7c7f90bc4f361b8bf4b49790640a4aa490ee619f Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 21 Oct 2019 11:58:22 +0300 Subject: [PATCH 20/28] [#1304] Merged `develop`, handled User.Info.invisible. --- lib/pleroma/user.ex | 16 ++++++++++++++-- lib/pleroma/web/activity_pub/relay.ex | 2 +- ...009154608_copy_users_info_fields_to_users.exs | 3 +++ .../20191017225002_drop_websub_tables.exs | 4 +++- test/user_test.exs | 2 +- test/web/activity_pub/views/user_view_test.exs | 2 +- 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 00a1df133..e8038c1c1 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -103,6 +103,7 @@ defmodule Pleroma.User do field(:fields, {:array, :map}, default: nil) field(:raw_fields, {:array, :map}, default: []) field(:discoverable, :boolean, default: false) + field(:invisible, :boolean, default: false) field(:skip_thread_containment, :boolean, default: false) field(:notification_settings, :map, @@ -142,7 +143,7 @@ def superuser?(%User{local: true, is_admin: true}), do: true def superuser?(%User{local: true, is_moderator: true}), do: true def superuser?(_), do: false - def invisible?(%User{info: %User.Info{invisible: true}}), do: true + def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false def avatar_url(user, options \\ []) do @@ -264,6 +265,7 @@ def following_count(%User{} = user) do :fields, :raw_fields, :discoverable, + :invisible, :skip_thread_containment, :notification_settings ] @@ -321,7 +323,8 @@ def remote_user_creation(params) do :follower_count, :fields, :following_count, - :discoverable + :discoverable, + :invisible ] ) |> validate_required([:name, :ap_id]) @@ -2021,4 +2024,13 @@ def remove_reblog_mute(user, ap_id) do |> cast(params, [:muted_reblogs]) |> update_and_set_cache() end + + def set_invisible(user, invisible) do + params = %{invisible: invisible} + + user + |> cast(params, [:invisible]) + |> validate_required([:invisible]) + |> update_and_set_cache() + end end diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index de80612f1..a9434d75c 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -14,7 +14,7 @@ def get_actor do "#{Pleroma.Web.Endpoint.url()}/relay" |> User.get_or_create_service_actor_by_ap_id() - {:ok, actor} = User.update_info(actor, &User.Info.set_invisible(&1, true)) + {:ok, actor} = User.set_invisible(actor, true) actor end diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs index 72c852d2b..87b1e2c8c 100644 --- a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -42,6 +42,7 @@ defmodule Pleroma.Repo.Migrations.CopyUsersInfoFieldsToUsers do :fields, :raw_fields, :discoverable, + :invisible, :skip_thread_containment, :notification_settings ] @@ -77,6 +78,7 @@ defmodule Pleroma.Repo.Migrations.CopyUsersInfoFieldsToUsers do :hide_follows, :hide_favorites, :discoverable, + :invisible, :skip_thread_containment ] @@ -132,6 +134,7 @@ def change do add(:fields, {:array, :map}, default: nil) add(:raw_fields, {:array, :map}, default: []) add(:discoverable, :boolean, default: false, null: false) + add(:invisible, :boolean, default: false, null: false) add(:notification_settings, :map, default: %{}) add(:skip_thread_containment, :boolean, default: false, null: false) end diff --git a/priv/repo/migrations/20191017225002_drop_websub_tables.exs b/priv/repo/migrations/20191017225002_drop_websub_tables.exs index 9e483b2a1..4cf67a59c 100644 --- a/priv/repo/migrations/20191017225002_drop_websub_tables.exs +++ b/priv/repo/migrations/20191017225002_drop_websub_tables.exs @@ -1,8 +1,10 @@ defmodule Pleroma.Repo.Migrations.DropWebsubTables do use Ecto.Migration - def change do + def up do drop_if_exists(table(:websub_client_subscriptions)) drop_if_exists(table(:websub_server_subscriptions)) end + + def down, do: :noop end diff --git a/test/user_test.exs b/test/user_test.exs index c78e1512a..92de31c74 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1233,7 +1233,7 @@ test "returns true for local admins" do describe "invisible?/1" do test "returns true for an invisible user" do - user = insert(:user, local: true, info: %{invisible: true}) + user = insert(:user, local: true, invisible: true) assert User.invisible?(user) end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 392b717b1..3299be2d5 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -75,7 +75,7 @@ test "Does not add an avatar image if the user hasn't set one" do end test "renders an invisible user with the invisible property set to true" do - user = insert(:user, %{info: %{invisible: true}}) + user = insert(:user, invisible: true) assert %{"invisible" => true} = UserView.render("service.json", %{user: user}) end From 2dbee29cf5a1a17438e8bc3d2586717da64e20ff Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 21 Oct 2019 12:38:35 +0300 Subject: [PATCH 21/28] Do not include notifications from blocked users when with_muted is set This is not what with_muted is for per documentation and it was agreed on irc that this behavior doesn't make sense. --- lib/pleroma/notification.ex | 15 ++++++++++----- test/notification_test.exs | 12 ++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index d145f8d5b..e5da1492b 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -55,9 +55,19 @@ def for_user_query(user, opts \\ []) do ) |> preload([n, a, o], activity: {a, object: o}) |> exclude_muted(user, opts) + |> exclude_blocked(user) |> exclude_visibility(opts) end + defp exclude_blocked(query, user) do + query + |> where([n, a], a.actor not in ^user.info.blocks) + |> where( + [n, a], + fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks + ) + end + defp exclude_muted(query, _, %{with_muted: true}) do query end @@ -65,11 +75,6 @@ defp exclude_muted(query, _, %{with_muted: true}) do defp exclude_muted(query, user, _opts) do query |> where([n, a], a.actor not in ^user.info.muted_notifications) - |> where([n, a], a.actor not in ^user.info.blocks) - |> where( - [n, a], - fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks - ) |> join(:left, [n, a], tm in Pleroma.ThreadMute, on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) ) diff --git a/test/notification_test.exs b/test/notification_test.exs index 54c0f9877..96316f8dd 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -683,7 +683,7 @@ test "it doesn't return notifications for muted thread" do assert Notification.for_user(user) == [] end - test "it returns notifications for muted user with notifications and with_muted parameter" do + test "it returns notifications from a muted user when with_muted is set" do user = insert(:user) muted = insert(:user) {:ok, user} = User.mute(user, muted) @@ -693,27 +693,27 @@ test "it returns notifications for muted user with notifications and with_muted assert length(Notification.for_user(user, %{with_muted: true})) == 1 end - test "it returns notifications for blocked user and with_muted parameter" do + test "it doesn't return notifications from a blocked user when with_muted is set" do user = insert(:user) blocked = insert(:user) {:ok, user} = User.block(user, blocked) {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"}) - assert length(Notification.for_user(user, %{with_muted: true})) == 1 + assert length(Notification.for_user(user, %{with_muted: true})) == 0 end - test "it returns notificatitons for blocked domain and with_muted parameter" do + test "it doesn't return notifications from a domain-blocked user when with_muted is set" do user = insert(:user) blocked = insert(:user, ap_id: "http://some-domain.com") {:ok, user} = User.block_domain(user, "some-domain.com") {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"}) - assert length(Notification.for_user(user, %{with_muted: true})) == 1 + assert length(Notification.for_user(user, %{with_muted: true})) == 0 end - test "it returns notifications for muted thread with_muted parameter" do + test "it returns notifications from muted threads when with_muted is set" do user = insert(:user) another_user = insert(:user) From 2cbb3f236466600db10cb0482e5b2d0ce1f4b945 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 21 Oct 2019 18:34:20 -0500 Subject: [PATCH 22/28] Add tests for the subject of push notifications --- test/web/push/impl_test.exs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index 2f6ce4bd2..38b16973d 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -97,7 +97,7 @@ test "delete subsciption if restult send message between 400..500" do refute Pleroma.Repo.get(Subscription, subscription.id) end - test "renders body for create activity" do + test "renders title and body for create activity" do user = insert(:user, nickname: "Bob") {:ok, activity} = @@ -116,18 +116,24 @@ test "renders body for create activity" do object ) == "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." + + assert Impl.format_title(%{activity: activity}) == + "New Mention" end - test "renders body for follow activity" do + test "renders title and body for follow activity" do user = insert(:user, nickname: "Bob") other_user = insert(:user) {:ok, _, _, activity} = CommonAPI.follow(user, other_user) object = Object.normalize(activity) assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has followed you" + + assert Impl.format_title(%{activity: activity}) == + "New Follower" end - test "renders body for announce activity" do + test "renders title and body for announce activity" do user = insert(:user) {:ok, activity} = @@ -141,9 +147,12 @@ test "renders body for announce activity" do assert Impl.format_body(%{activity: announce_activity}, user, object) == "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." + + assert Impl.format_title(%{activity: announce_activity}) == + "New Repeat" end - test "renders body for like activity" do + test "renders title and body for like activity" do user = insert(:user, nickname: "Bob") {:ok, activity} = @@ -156,5 +165,21 @@ test "renders body for like activity" do object = Object.normalize(activity) assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post" + + assert Impl.format_title(%{activity: activity}) == + "New Favorite" + end + + test "renders title for create activity with direct visibility" do + user = insert(:user, nickname: "Bob") + + {:ok, activity} = + CommonAPI.post(user, %{ + "visibility" => "direct", + "status" => "This is just between you and me, pal" + }) + + assert Impl.format_title(%{activity: activity}) == + "New Direct Message" end end From 0c628fafc56e1b6108660071d39b94f786233391 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 21 Oct 2019 18:35:43 -0500 Subject: [PATCH 23/28] Spelling --- test/web/push/impl_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index 38b16973d..9b554601d 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -84,7 +84,7 @@ test "fail message sending" do ) == :error end - test "delete subsciption if restult send message between 400..500" do + test "delete subscription if result send message between 400..500" do subscription = insert(:push_subscription) assert Impl.push_message( From 277aea45b9799596c4144b80b9e77e2801d9becd Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 22 Oct 2019 19:43:31 -0500 Subject: [PATCH 24/28] tests: transmogrifier: add explicit regression tests for JSON-LD string to single-element array deserialization There appears to be confusion on whether or not Pleroma can handle this particular sin of JSON-LD. It can, and we will add regression tests to prove that it can handle this particular sin. Which, by the way, this is actually not a "feature" of JSON-LD, but whatever. --- test/web/activity_pub/transmogrifier_test.exs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index dbb6e59b0..77e041b4a 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1106,6 +1106,50 @@ test "it accepts Flag activities" do assert activity.data["actor"] == other_user.ap_id assert activity.data["cc"] == [user.ap_id] end + + test "it correctly processes messages with non-array to field" do + user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => "https://www.w3.org/ns/activitystreams#Public", + "type" => "Create", + "object" => %{ + "content" => "blah blah blah", + "type" => "Note", + "attributedTo" => user.ap_id, + "inReplyTo" => nil + }, + "actor" => user.ap_id + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(message) + + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] + end + + test "it correctly processes messages with non-array cc field" do + user = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "to" => user.follower_address, + "cc" => "https://www.w3.org/ns/activitystreams#Public", + "type" => "Create", + "object" => %{ + "content" => "blah blah blah", + "type" => "Note", + "attributedTo" => user.ap_id, + "inReplyTo" => nil + }, + "actor" => user.ap_id + } + + assert {:ok, activity} = Transmogrifier.handle_incoming(message) + + assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] + assert [user.follower_address] == activity.data["to"] + end end describe "prepare outgoing" do From 3f6a596922fa6839ca26b3136074e4cf054458ad Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 22 Oct 2019 20:50:25 -0500 Subject: [PATCH 25/28] activitypub: visibility: refactor is_public?() to use JSON-LD safe accessors --- lib/pleroma/web/activity_pub/utils.ex | 42 +++++----- lib/pleroma/web/activity_pub/visibility.ex | 3 +- .../activity_pub_controller_test.exs | 81 +++++++++++++++++++ 3 files changed, 105 insertions(+), 21 deletions(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 6b28df92c..699d5162f 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -49,26 +49,28 @@ def determine_explicit_mentions(%{"tag" => tag} = object) when is_map(tag) do def determine_explicit_mentions(_), do: [] - @spec recipient_in_collection(any(), any()) :: boolean() - defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == coll - defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll - defp recipient_in_collection(_, _), do: false + @spec label_in_collection?(any(), any()) :: boolean() + defp label_in_collection?(ap_id, coll) when is_binary(coll), do: ap_id == coll + defp label_in_collection?(ap_id, coll) when is_list(coll), do: ap_id in coll + defp label_in_collection?(_, _), do: false + + @spec label_in_message?(String.t(), map()) :: boolean() + def label_in_message?(label, params), + do: + [params["to"], params["cc"], params["bto"], params["bcc"]] + |> Enum.any?(&label_in_collection?(label, &1)) + + @spec unaddressed_message?(map()) :: boolean() + def unaddressed_message?(params), + do: + [params["to"], params["cc"], params["bto"], params["bcc"]] + |> Enum.all?(&is_nil(&1)) @spec recipient_in_message(User.t(), User.t(), map()) :: boolean() - def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params) do - addresses = [params["to"], params["cc"], params["bto"], params["bcc"]] - - cond do - Enum.any?(addresses, &recipient_in_collection(ap_id, &1)) -> true - # if the message is unaddressed at all, then assume it is directly addressed - # to the recipient - Enum.all?(addresses, &is_nil(&1)) -> true - # if the message is sent from somebody the user is following, then assume it - # is addressed to the recipient - User.following?(recipient, actor) -> true - true -> false - end - end + def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params), + do: + label_in_message?(ap_id, params) || unaddressed_message?(params) || + User.following?(recipient, actor) defp extract_list(target) when is_binary(target), do: [target] defp extract_list(lst) when is_list(lst), do: lst @@ -76,8 +78,8 @@ defp extract_list(_), do: [] def maybe_splice_recipient(ap_id, params) do need_splice? = - !recipient_in_collection(ap_id, params["to"]) && - !recipient_in_collection(ap_id, params["cc"]) + !label_in_collection?(ap_id, params["to"]) && + !label_in_collection?(ap_id, params["cc"]) if need_splice? do cc_list = extract_list(params["cc"]) diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 270d0fa02..f3ab48f7c 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Web.ActivityPub.Utils require Pleroma.Constants @@ -15,7 +16,7 @@ def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def is_public?(%Object{data: data}), do: is_public?(data) def is_public?(%Activity{data: data}), do: is_public?(data) def is_public?(%{"directMessage" => true}), do: false - def is_public?(data), do: Pleroma.Constants.as_public() in (data["to"] ++ (data["cc"] || [])) + def is_public?(data), do: Utils.label_in_message?(Pleroma.Constants.as_public(), data) def is_private?(activity) do with false <- is_public?(activity), diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 6a3e48b5e..fc0444c32 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -354,6 +354,87 @@ test "it inserts an incoming activity into the database", %{conn: conn, data: da assert Activity.get_by_ap_id(data["id"]) end + test "it accepts messages with to as string instead of array", %{conn: conn, data: data} do + user = insert(:user) + + data = + Map.put(data, "to", user.ap_id) + |> Map.delete("cc") + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/inbox", data) + + assert "ok" == json_response(conn, 200) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + assert Activity.get_by_ap_id(data["id"]) + end + + test "it accepts messages with cc as string instead of array", %{conn: conn, data: data} do + user = insert(:user) + + data = + Map.put(data, "cc", user.ap_id) + |> Map.delete("to") + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/inbox", data) + + assert "ok" == json_response(conn, 200) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + %Activity{} = activity = Activity.get_by_ap_id(data["id"]) + assert user.ap_id in activity.recipients + end + + test "it accepts messages with bcc as string instead of array", %{conn: conn, data: data} do + user = insert(:user) + + data = + Map.put(data, "bcc", user.ap_id) + |> Map.delete("to") + |> Map.delete("cc") + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/inbox", data) + + assert "ok" == json_response(conn, 200) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + assert Activity.get_by_ap_id(data["id"]) + end + + test "it accepts announces with to as string instead of array", %{conn: conn} do + user = insert(:user) + + data = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "actor" => "http://mastodon.example.org/users/admin", + "id" => "http://mastodon.example.org/users/admin/statuses/19512778738411822/activity", + "object" => "https://mastodon.social/users/emelie/statuses/101849165031453009", + "to" => "https://www.w3.org/ns/activitystreams#Public", + "cc" => [user.ap_id], + "type" => "Announce" + } + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/inbox", data) + + assert "ok" == json_response(conn, 200) + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + %Activity{} = activity = Activity.get_by_ap_id(data["id"]) + assert "https://www.w3.org/ns/activitystreams#Public" in activity.recipients + end + test "it accepts messages from actors that are followed by the user", %{ conn: conn, data: data From 11cd9944258bfc2123b821b21321e12097d0f19b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 23 Oct 2019 17:15:48 +0300 Subject: [PATCH 26/28] [#1304] Fixed null::jsonb handling in User.Info migration. --- lib/pleroma/user.ex | 2 +- ...09154608_copy_users_info_fields_to_users.exs | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e8038c1c1..7bef6e281 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -100,7 +100,7 @@ defmodule Pleroma.User do field(:mascot, :map, default: nil) field(:emoji, {:array, :map}, default: []) field(:pleroma_settings_store, :map, default: %{}) - field(:fields, {:array, :map}, default: nil) + field(:fields, {:array, :map}, default: []) field(:raw_fields, {:array, :map}, default: []) field(:discoverable, :boolean, default: false) field(:invisible, :boolean, default: false) diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs index 87b1e2c8c..9dd27511c 100644 --- a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -1,6 +1,8 @@ defmodule Pleroma.Repo.Migrations.CopyUsersInfoFieldsToUsers do use Ecto.Migration + @jsonb_array_default "'[]'::jsonb" + @info_fields [ :banner, :background, @@ -129,10 +131,10 @@ def change do add(:pinned_activities, {:array, :text}, default: []) add(:email_notifications, :map, default: %{"digest" => false}) add(:mascot, :map, default: nil) - add(:emoji, {:array, :map}, default: []) + add(:emoji, :map, default: fragment(@jsonb_array_default)) add(:pleroma_settings_store, :map, default: %{}) - add(:fields, {:array, :map}, default: nil) - add(:raw_fields, {:array, :map}, default: []) + add(:fields, :map, default: fragment(@jsonb_array_default)) + add(:raw_fields, :map, default: fragment(@jsonb_array_default)) add(:discoverable, :boolean, default: false, null: false) add(:invisible, :boolean, default: false, null: false) add(:notification_settings, :map, default: %{}) @@ -143,12 +145,15 @@ def change do for f <- @info_fields do set_field = "update users set #{f} =" + # Coercion of null::jsonb to NULL + jsonb = "case when info->>'#{f}' IS NULL then null else info->'#{f}' end" + cond do f in @jsonb_fields -> - execute("#{set_field} info->'#{f}'") + execute("#{set_field} #{jsonb}") f in @array_jsonb_fields -> - execute("#{set_field} ARRAY(SELECT jsonb_array_elements(info->'#{f}'))") + execute("#{set_field} coalesce(#{jsonb}, #{@jsonb_array_default})") f in @int_fields -> execute("#{set_field} (info->>'#{f}')::int") @@ -157,7 +162,7 @@ def change do execute("#{set_field} coalesce((info->>'#{f}')::boolean, false)") f in @array_text_fields -> - execute("#{set_field} ARRAY(SELECT jsonb_array_elements_text(info->'#{f}'))") + execute("#{set_field} ARRAY(SELECT jsonb_array_elements_text(#{jsonb}))") true -> execute("#{set_field} info->>'#{f}'") From 065e9fac12c1ea06eca2ff55a8253d4bc23362e1 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 23 Oct 2019 17:31:02 +0300 Subject: [PATCH 27/28] [#1304] Adjusted User.Info references from Notification. --- lib/pleroma/notification.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 83844d3be..b7ecf51e4 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -61,10 +61,10 @@ def for_user_query(user, opts \\ []) do defp exclude_blocked(query, user) do query - |> where([n, a], a.actor not in ^user.info.blocks) + |> where([n, a], a.actor not in ^user.blocks) |> where( [n, a], - fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks + fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.domain_blocks ) end From c0246309a5013b17a405644a0918ec0d3569eaf1 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 23 Oct 2019 19:30:02 +0300 Subject: [PATCH 28/28] [#1304] Extra bullet-proofing. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 7fc5051ea..07dde3537 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1164,7 +1164,7 @@ defp maybe_update_follow_information(data) do with {:enabled, true} <- {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, {:ok, info} <- fetch_follow_information_for_user(data) do - info = Map.merge(data.info, info) + info = Map.merge(data[:info] || %{}, info) Map.put(data, :info, info) else {:enabled, false} ->