From 30af5da33043192dff626e869f2628ffc709f836 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 14 Nov 2019 23:44:07 +0900 Subject: [PATCH 01/19] Admin API: list all statuses from a given instance --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 26 +++++++++++++ .../web/admin_api/admin_api_controller.ex | 15 ++++++++ lib/pleroma/web/router.ex | 2 + .../admin_api/admin_api_controller_test.exs | 37 +++++++++++++++++++ 5 files changed, 81 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ec084dbd..66644efc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Add `/api/v1/markers` for managing timeline read markers - Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations` - Configuration: `feed` option for user atom feed. +- Admin API: Add `/api/pleroma/admin/instances/:instance/statuses` - lists all statuses from a given instance ### Fixed diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 65dd251f3..8b5bd83e2 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -708,6 +708,17 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do |> Enum.reverse() end + def fetch_instance_activities(params) do + params = + params + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("instance", params["instance"]) + |> Map.put("whole_db", true) + + fetch_activities([Pleroma.Constants.as_public()], params, :offset) + |> Enum.reverse() + end + defp user_activities_recipients(%{"godmode" => true}) do [] end @@ -935,6 +946,20 @@ defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user}) do defp restrict_muted_reblogs(query, _), do: query + defp restrict_instance(query, %{"instance" => instance}) do + users = + from( + u in User, + select: u.ap_id, + where: fragment("? LIKE ?", u.nickname, ^"%@#{instance}") + ) + |> Repo.all() + + from(activity in query, where: activity.actor in ^users) + end + + defp restrict_instance(query, _), do: query + defp exclude_poll_votes(query, %{"include_poll_votes" => true}), do: query defp exclude_poll_votes(query, _) do @@ -1015,6 +1040,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_reblogs(opts) |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) + |> restrict_instance(opts) |> Activity.restrict_deactivated_users() |> exclude_poll_votes(opts) |> exclude_visibility(opts) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 30fc01755..2f43f018b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -226,6 +226,21 @@ def user_show(conn, %{"nickname" => nickname}) do end end + def list_instance_statuses(conn, %{"instance" => instance} = params) do + {page, page_size} = page_params(params) + + activities = + ActivityPub.fetch_instance_activities(%{ + "instance" => instance, + "limit" => page_size, + "offset" => (page - 1) * page_size + }) + + conn + |> put_view(StatusView) + |> render("index.json", %{activities: activities, as: :activity}) + end + def list_user_statuses(conn, %{"nickname" => nickname} = params) do godmode = params["godmode"] == "true" || params["godmode"] == true diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8fb4aec13..1e2982b67 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -177,6 +177,8 @@ defmodule Pleroma.Web.Router do get("/users/:nickname", AdminAPIController, :user_show) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) + get("/instances/:instance/statuses", AdminAPIController, :list_instance_statuses) + get("/reports", AdminAPIController, :list_reports) get("/reports/:id", AdminAPIController, :report_show) put("/reports/:id", AdminAPIController, :report_update_state) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 2a9e4f5a0..5958e6462 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -2640,6 +2640,43 @@ test "DELETE /relay", %{admin: admin} do "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin" end end + + describe "instances" do + test "GET /instances/:instance/statuses" do + admin = insert(:user, is_admin: true) + user = insert(:user, local: false, nickname: "archaeme@archae.me") + user2 = insert(:user, local: false, nickname: "test@test.com") + insert_pair(:note_activity, user: user) + insert(:note_activity, user: user2) + + conn = + build_conn() + |> assign(:user, admin) + |> get("/api/pleroma/admin/instances/archae.me/statuses") + + response = json_response(conn, 200) + + assert length(response) == 2 + + conn = + build_conn() + |> assign(:user, admin) + |> get("/api/pleroma/admin/instances/test.com/statuses") + + response = json_response(conn, 200) + + assert length(response) == 1 + + conn = + build_conn() + |> assign(:user, admin) + |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") + + response = json_response(conn, 200) + + assert length(response) == 0 + end + end end # Needed for testing From c506cc48ef230da30d5786285806de904b725981 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sat, 16 Nov 2019 18:44:48 +0900 Subject: [PATCH 02/19] Admin API: Error when trying to update reports in the "old" format --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/utils.ex | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ad91b0d..740facf04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) - Mastodon API: Inability to get some local users by nickname in `/api/v1/accounts/:id_or_nickname` +- Admin API: Error when trying to update reports in the "old" format ## [1.1.2] - 2019-10-18 diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index c45662359..01aacbde3 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -903,7 +903,13 @@ def update_report_state(_, _), do: {:error, "Unsupported state"} def strip_report_status_data(activity) do [actor | reported_activities] = activity.data["object"] - stripped_activities = Enum.map(reported_activities, & &1["id"]) + + stripped_activities = + Enum.map(reported_activities, fn + act when is_map(act) -> act["id"] + act when is_binary(act) -> act + end) + new_data = put_in(activity.data, ["object"], [actor | stripped_activities]) {:ok, %{activity | data: new_data}} From 46eb160135cf408fee87bb76fc46acfc51af901d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 19 Nov 2019 20:14:02 +0900 Subject: [PATCH 03/19] AdminAPI: Confirm user account, resend confirmation email --- CHANGELOG.md | 1 + docs/API/admin_api.md | 16 +++++ lib/pleroma/moderation_log.ex | 26 +++++++- lib/pleroma/user.ex | 9 +++ .../web/admin_api/admin_api_controller.ex | 41 ++++++++++-- .../web/admin_api/views/account_view.ex | 3 +- lib/pleroma/web/router.ex | 3 + .../admin_api/admin_api_controller_test.exs | 62 +++++++++++++++++++ 8 files changed, 153 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ad91b0d..4b33718a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations` - Configuration: `feed` option for user atom feed. - Pleroma API: Add Emoji reactions +- Admin API: `PATCH /api/pleroma/users/confirm_email` to confirm email for multiple users, `PATCH /api/pleroma/users/resend_confirmation_email` to resend confirmation email for multiple users ### Fixed diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md index 9d914c9a6..d943b3ee3 100644 --- a/docs/API/admin_api.md +++ b/docs/API/admin_api.md @@ -878,3 +878,19 @@ Compile time settings (need instance reboot): - Authentication: required - Params: None - Response: JSON, "ok" and 200 status + +## `PATCH /api/pleroma/admin/users/confirm_email` + +### Confirm users' emails + +- Params: + - `nicknames` +- Response: Array of user nicknames + +## `PATCH /api/pleroma/admin/users/resend_confirmation_email` + +### Resend confirmation email + +- Params: + - `nicknames` +- Response: Array of user nicknames diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index ffa5dc25d..706f089dc 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -624,7 +624,31 @@ def get_log_entry_message(%ModerationLog{ "subject" => subjects } }) do - "@#{actor_nickname} force password reset for users: #{users_to_nicknames_string(subjects)}" + "@#{actor_nickname} forced password reset for users: #{users_to_nicknames_string(subjects)}" + end + + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "confirm_email", + "subject" => subjects + } + }) do + "@#{actor_nickname} confirmed email for users: #{users_to_nicknames_string(subjects)}" + end + + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "resend_confirmation_email", + "subject" => subjects + } + }) do + "@#{actor_nickname} re-sent confirmation email for users: #{ + users_to_nicknames_string(subjects) + }" end defp nicknames_to_string(nicknames) do diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f8c2db1e1..f031d2179 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -489,6 +489,10 @@ def try_send_confirmation_email(%User{} = user) do end end + def try_send_confirmation_email(users) do + Enum.map(users, &try_send_confirmation_email/1) + end + def needs_update?(%User{local: true}), do: false def needs_update?(%User{local: false, last_refreshed_at: nil}), do: true @@ -1572,6 +1576,11 @@ def toggle_confirmation(%User{} = user) do |> update_and_set_cache() end + @spec toggle_confirmation([User.t()]) :: [{:ok, User.t()} | {:error, Changeset.t()}] + def toggle_confirmation(users) do + Enum.map(users, &toggle_confirmation/1) + end + def get_mascot(%{mascot: %{} = mascot}) when not is_nil(mascot) do mascot end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 8c1318d1b..c46ce76da 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -335,7 +335,7 @@ def list_users(conn, params) do } with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)), - {:ok, users, count} <- filter_relay_user(users, count), + {:ok, users, count} <- filter_service_users(users, count), do: conn |> json( @@ -347,15 +347,16 @@ def list_users(conn, params) do ) end - defp filter_relay_user(users, count) do - filtered_users = Enum.reject(users, &relay_user?/1) - count = if Enum.any?(users, &relay_user?/1), do: length(filtered_users), else: count + defp filter_service_users(users, count) do + filtered_users = Enum.reject(users, &service_user?/1) + count = if Enum.any?(users, &service_user?/1), do: length(filtered_users), else: count {:ok, filtered_users, count} end - defp relay_user?(user) do - user.ap_id == Relay.relay_ap_id() + defp service_user?(user) do + String.match?(user.ap_id, ~r/.*\/relay$/) or + String.match?(user.ap_id, ~r/.*\/internal\/fetch$/) end @filters ~w(local external active deactivated is_admin is_moderator) @@ -799,6 +800,34 @@ def reload_emoji(conn, _params) do conn |> json("ok") end + def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do + users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) + + User.toggle_confirmation(users) + + ModerationLog.insert_log(%{ + actor: admin, + subject: users, + action: "confirm_email" + }) + + conn |> json("") + end + + def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do + users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) + + User.try_send_confirmation_email(users) + + ModerationLog.insert_log(%{ + actor: admin, + subject: users, + action: "resend_confirmation_email" + }) + + conn |> json("") + end + def errors(conn, {:error, :not_found}) do conn |> put_status(:not_found) diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index 6aa7257ce..d9dba5c51 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -36,7 +36,8 @@ def render("show.json", %{user: user}) do "deactivated" => user.deactivated, "local" => user.local, "roles" => User.roles(user), - "tags" => user.tags || [] + "tags" => user.tags || [], + "confirmation_pending" => user.confirmation_pending } end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9b8b373b8..b654d00c7 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -177,6 +177,9 @@ defmodule Pleroma.Web.Router do get("/users/:nickname", AdminAPIController, :user_show) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) + patch("/users/confirm_email", AdminAPIController, :confirm_email) + patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) + get("/reports", AdminAPIController, :list_reports) get("/grouped_reports", AdminAPIController, :list_grouped_reports) get("/reports/:id", AdminAPIController, :report_show) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 3a4c4d65c..8fabfd963 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -2839,6 +2839,68 @@ test "DELETE /relay", %{admin: admin} do "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin" end end + + describe "PATCH /confirm_email" do + setup %{conn: conn} do + admin = insert(:user, is_admin: true) + + %{conn: assign(conn, :user, admin), admin: admin} + end + + test "it confirms emails of two users", %{admin: admin} do + [first_user, second_user] = insert_pair(:user, confirmation_pending: true) + + assert first_user.confirmation_pending == true + assert second_user.confirmation_pending == true + + build_conn() + |> assign(:user, admin) + |> patch("/api/pleroma/admin/users/confirm_email", %{ + nicknames: [ + first_user.nickname, + second_user.nickname + ] + }) + + assert first_user.confirmation_pending == true + assert second_user.confirmation_pending == true + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{ + second_user.nickname + }" + end + end + + describe "PATCH /resend_confirmation_email" do + setup %{conn: conn} do + admin = insert(:user, is_admin: true) + + %{conn: assign(conn, :user, admin), admin: admin} + end + + test "it resend emails for two users", %{admin: admin} do + [first_user, second_user] = insert_pair(:user, confirmation_pending: true) + + build_conn() + |> assign(:user, admin) + |> patch("/api/pleroma/admin/users/resend_confirmation_email", %{ + nicknames: [ + first_user.nickname, + second_user.nickname + ] + }) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{ + second_user.nickname + }" + end + end end # Needed for testing From b88dbc17c8e404d0dcc16746d4a55210d7c8fd97 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 19 Nov 2019 22:50:24 +0900 Subject: [PATCH 04/19] Fix tests --- .../admin_api/admin_api_controller_test.exs | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 8fabfd963..9b4f359dc 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -225,7 +225,8 @@ test "Show", %{conn: conn} do "roles" => %{"admin" => false, "moderator" => false}, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } assert expected == json_response(conn, 200) @@ -634,7 +635,8 @@ test "renders users array for the first page", %{conn: conn, admin: admin} do "local" => true, "tags" => [], "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname) + "display_name" => HTML.strip_tags(admin.name || admin.nickname), + "confirmation_pending" => false }, %{ "deactivated" => user.deactivated, @@ -644,7 +646,8 @@ test "renders users array for the first page", %{conn: conn, admin: admin} do "local" => false, "tags" => ["foo", "bar"], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] |> Enum.sort_by(& &1["nickname"]) @@ -685,7 +688,8 @@ test "regular search", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -709,7 +713,8 @@ test "search by domain", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -733,7 +738,8 @@ test "search by full nickname", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -757,7 +763,8 @@ test "search by display name", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -781,7 +788,8 @@ test "search by email", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -805,7 +813,8 @@ test "regular search with page size", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -824,7 +833,8 @@ test "regular search with page size", %{conn: conn} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname) + "display_name" => HTML.strip_tags(user2.name || user2.nickname), + "confirmation_pending" => false } ] } @@ -853,7 +863,8 @@ test "only local users" do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -880,7 +891,8 @@ test "only local users with no query", %{admin: old_admin} do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false }, %{ "deactivated" => admin.deactivated, @@ -890,7 +902,8 @@ test "only local users with no query", %{admin: old_admin} do "local" => true, "tags" => [], "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname) + "display_name" => HTML.strip_tags(admin.name || admin.nickname), + "confirmation_pending" => false }, %{ "deactivated" => false, @@ -900,7 +913,8 @@ test "only local users with no query", %{admin: old_admin} do "roles" => %{"admin" => true, "moderator" => false}, "tags" => [], "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname) + "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname), + "confirmation_pending" => false } ] |> Enum.sort_by(& &1["nickname"]) @@ -929,7 +943,8 @@ test "load only admins", %{conn: conn, admin: admin} do "local" => admin.local, "tags" => [], "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname) + "display_name" => HTML.strip_tags(admin.name || admin.nickname), + "confirmation_pending" => false }, %{ "deactivated" => false, @@ -939,7 +954,8 @@ test "load only admins", %{conn: conn, admin: admin} do "local" => second_admin.local, "tags" => [], "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname) + "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname), + "confirmation_pending" => false } ] |> Enum.sort_by(& &1["nickname"]) @@ -970,7 +986,8 @@ test "load only moderators", %{conn: conn} do "local" => moderator.local, "tags" => [], "avatar" => User.avatar_url(moderator) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(moderator.name || moderator.nickname) + "display_name" => HTML.strip_tags(moderator.name || moderator.nickname), + "confirmation_pending" => false } ] } @@ -994,7 +1011,8 @@ test "load users with tags list", %{conn: conn} do "local" => user1.local, "tags" => ["first"], "avatar" => User.avatar_url(user1) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user1.name || user1.nickname) + "display_name" => HTML.strip_tags(user1.name || user1.nickname), + "confirmation_pending" => false }, %{ "deactivated" => false, @@ -1004,7 +1022,8 @@ test "load users with tags list", %{conn: conn} do "local" => user2.local, "tags" => ["second"], "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname) + "display_name" => HTML.strip_tags(user2.name || user2.nickname), + "confirmation_pending" => false } ] |> Enum.sort_by(& &1["nickname"]) @@ -1040,7 +1059,8 @@ test "it works with multiple filters" do "local" => user.local, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } ] } @@ -1066,7 +1086,8 @@ test "it omits relay user", %{admin: admin} do "local" => true, "tags" => [], "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname) + "display_name" => HTML.strip_tags(admin.name || admin.nickname), + "confirmation_pending" => false } ] } @@ -1135,7 +1156,8 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do "local" => true, "tags" => [], "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname) + "display_name" => HTML.strip_tags(user.name || user.nickname), + "confirmation_pending" => false } log_entry = Repo.one(ModerationLog) From ff9133b978edb637081882e7efd49e2f538e9e15 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 19 Nov 2019 16:01:17 -0600 Subject: [PATCH 05/19] Allow mix tasks to always run with debug logging --- config/config.exs | 1 + config/prod.exs | 2 +- config/test.exs | 2 +- lib/mix/pleroma.ex | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/config.exs b/config/config.exs index bf2b3f6e2..9ac78c589 100644 --- a/config/config.exs +++ b/config/config.exs @@ -180,6 +180,7 @@ # Configures Elixir's Logger config :logger, :console, + level: :debug, format: "$time $metadata[$level] $message\n", metadata: [:request_id] diff --git a/config/prod.exs b/config/prod.exs index 9c205cbd2..301d2b9cb 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -20,7 +20,7 @@ config :phoenix, serve_endpoints: true # Do not print debug messages in production -config :logger, level: :warn +config :logger, :console, level: :warn # ## SSL Support # diff --git a/config/test.exs b/config/test.exs index da2778aa7..559ff423e 100644 --- a/config/test.exs +++ b/config/test.exs @@ -15,7 +15,7 @@ method: Pleroma.Captcha.Mock # Print only warnings and errors during test -config :logger, level: :warn +config :logger, :console, level: :warn config :pleroma, :auth, oauth_consumer_strategies: [] diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index faeb30e1d..94eeb7d68 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -6,6 +6,7 @@ defmodule Mix.Pleroma do @doc "Common functions to be reused in mix tasks" def start_pleroma do Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) + Application.put_env(:logger, :console, level: :debug) {:ok, _} = Application.ensure_all_started(:pleroma) end From cb513a599cc3211e6f5e5d1a1710ec2ae85ec37a Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 19 Nov 2019 16:21:30 -0600 Subject: [PATCH 06/19] Allow test builds to have info and debug logs stripped --- config/test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/test.exs b/config/test.exs index 559ff423e..da2778aa7 100644 --- a/config/test.exs +++ b/config/test.exs @@ -15,7 +15,7 @@ method: Pleroma.Captcha.Mock # Print only warnings and errors during test -config :logger, :console, level: :warn +config :logger, level: :warn config :pleroma, :auth, oauth_consumer_strategies: [] From 1c17f1832983a784156118d1cd488bfde88f092b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 20 Nov 2019 09:14:27 -0600 Subject: [PATCH 07/19] Be specific about format for logs in test as we have tests that check it --- config/test.exs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/test.exs b/config/test.exs index da2778aa7..f8188b9e4 100644 --- a/config/test.exs +++ b/config/test.exs @@ -15,7 +15,9 @@ method: Pleroma.Captcha.Mock # Print only warnings and errors during test -config :logger, level: :warn +config :logger, + level: :warn, + format: "[$level] $message" config :pleroma, :auth, oauth_consumer_strategies: [] From c65190c799b6217dca36f9fe4768024b50b725a8 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 20 Nov 2019 11:18:42 -0600 Subject: [PATCH 08/19] Console backend's log format should be prefixed and suffixed with newlines. This is how upstream does it by default. --- config/config.exs | 2 +- config/test.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.exs b/config/config.exs index 9ac78c589..1e36d3314 100644 --- a/config/config.exs +++ b/config/config.exs @@ -181,7 +181,7 @@ # Configures Elixir's Logger config :logger, :console, level: :debug, - format: "$time $metadata[$level] $message\n", + format: "\n$time $metadata[$level] $message\n", metadata: [:request_id] config :logger, :ex_syslogger, diff --git a/config/test.exs b/config/test.exs index f8188b9e4..07e70dd4d 100644 --- a/config/test.exs +++ b/config/test.exs @@ -17,7 +17,7 @@ # Print only warnings and errors during test config :logger, level: :warn, - format: "[$level] $message" + format: "\n[$level] $message\n" config :pleroma, :auth, oauth_consumer_strategies: [] From edaae845afc63d558c22019b3b3f87bc510a3bdf Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 20 Nov 2019 11:55:30 -0600 Subject: [PATCH 09/19] Some tasks try to set log level in test environment, but we were stripping logs belog :warn. Ensure console backend logs in test environment are :warn, but mix tasks run in test env do not run with :debug because it's far too verbose. --- config/test.exs | 2 +- lib/mix/pleroma.ex | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config/test.exs b/config/test.exs index 07e70dd4d..9b737d4d7 100644 --- a/config/test.exs +++ b/config/test.exs @@ -15,7 +15,7 @@ method: Pleroma.Captcha.Mock # Print only warnings and errors during test -config :logger, +config :logger, :console, level: :warn, format: "\n[$level] $message\n" diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index 94eeb7d68..73a076a53 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -6,7 +6,11 @@ defmodule Mix.Pleroma do @doc "Common functions to be reused in mix tasks" def start_pleroma do Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) - Application.put_env(:logger, :console, level: :debug) + + if Pleroma.Config.get(:env) != :test do + Application.put_env(:logger, :console, level: :debug) + end + {:ok, _} = Application.ensure_all_started(:pleroma) end From 320690f7a5bf1622e25114b6ad4c0b0c5a252748 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 21 Nov 2019 14:03:01 +0100 Subject: [PATCH 10/19] Object: Use inspect to log missing preload. --- lib/pleroma/object.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index d9b41d710..cde0eddd9 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -63,7 +63,7 @@ def get_by_ap_id(ap_id) do end defp warn_on_no_object_preloaded(ap_id) do - "Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object" + "Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object" |> Logger.debug() Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}") From dc9303eac563d23aebce04ad03e55ab072e548ed Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 21 Nov 2019 15:03:27 +0000 Subject: [PATCH 11/19] Revert "Merge branch 'patch-1' into 'develop'" This reverts merge request !1829 --- config/releases.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/releases.exs b/config/releases.exs index 36c493673..98c5ceccd 100644 --- a/config/releases.exs +++ b/config/releases.exs @@ -1,6 +1,6 @@ import Config -config :pleroma, :instance, static: "/var/lib/pleroma/static" +config :pleroma, :instance, static_dir: "/var/lib/pleroma/static" config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads" config_path = System.get_env("PLEROMA_CONFIG_PATH") || "/etc/pleroma/config.exs" From fbc379d68990b166e1034cfff252f975f793eba1 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Sun, 17 Nov 2019 21:58:30 +0100 Subject: [PATCH 12/19] Add CLI list users command --- CHANGELOG.md | 1 + docs/administration/CLI_tasks/user.md | 5 +++++ lib/mix/tasks/pleroma/user.ex | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d9b97f0b..e237ec731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Authentication: Added rate limit for password-authorized actions / login existence checks - Static Frontend: Add the ability to render user profiles and notices server-side without requiring JS app. - Mix task to re-count statuses for all users (`mix pleroma.count_statuses`) +- Mix task to list all users (`mix pleroma.user list`) - Support for `X-Forwarded-For` and similar HTTP headers which used by reverse proxies to pass a real user IP address to the backend. Must not be enabled unless your instance is behind at least one reverse proxy (such as Nginx, Apache HTTPD or Varnish Cache). - MRF: New module which handles incoming posts based on their age. By default, all incoming posts that are older than 2 days will be unlisted and not shown to their followers.
diff --git a/docs/administration/CLI_tasks/user.md b/docs/administration/CLI_tasks/user.md index cf120f2c9..96b2d9e6a 100644 --- a/docs/administration/CLI_tasks/user.md +++ b/docs/administration/CLI_tasks/user.md @@ -15,6 +15,11 @@ $PREFIX new [] - `--admin`/`--no-admin` - whether the user should be an admin - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions +## List local users +```sh +$PREFIX list +``` + ## Generate an invite link ```sh $PREFIX invite [] diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 4e3b80db3..bc8eacda8 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -364,6 +364,24 @@ def run(["sign_out", nickname]) do end end + def run(["list"]) do + start_pleroma() + + Pleroma.User.Query.build(%{local: true}) + |> Pleroma.RepoStreamer.chunk_stream(500) + |> Stream.each(fn users -> + users + |> Enum.each(fn user -> + shell_info( + "#{user.nickname} moderator: #{user.info.is_moderator}, admin: #{user.info.is_admin}, locked: #{ + user.info.locked + }, deactivated: #{user.info.deactivated}" + ) + end) + end) + |> Stream.run() + end + defp set_moderator(user, value) do {:ok, user} = user From b64c7b35d429546695550b37ca1e690b46c86f5d Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 22 Nov 2019 09:11:36 +0900 Subject: [PATCH 13/19] Swap map with each --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f031d2179..f1830509c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -490,7 +490,7 @@ def try_send_confirmation_email(%User{} = user) do end def try_send_confirmation_email(users) do - Enum.map(users, &try_send_confirmation_email/1) + Enum.each(users, &try_send_confirmation_email/1) end def needs_update?(%User{local: true}), do: false From 4a5bb7eb021aa828fc24dfb7dbfdb1711e191daa Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 22 Nov 2019 19:58:39 +0300 Subject: [PATCH 14/19] OTP releases: only set name and distribution type if not set already Fixes not being able to run two OTP releases on one machine because of the name conflict. --- rel/env.sh.eex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rel/env.sh.eex b/rel/env.sh.eex index a4ce25295..e1b87102d 100644 --- a/rel/env.sh.eex +++ b/rel/env.sh.eex @@ -8,5 +8,5 @@ # fi # Set the release to work across nodes -export RELEASE_DISTRIBUTION=name -export RELEASE_NODE=<%= @release.name %>@127.0.0.1 +export RELEASE_DISTRIBUTION="${RELEASE_DISTRIBUTION:-name}" +export RELEASE_NODE="${RELEASE_NODE:-<%= @release.name %>@127.0.0.1}" From 9f2993044098ced1585c8886c16da19dd046b5fd Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 23 Nov 2019 22:55:41 +0300 Subject: [PATCH 15/19] fetcher: move local object checking into a reusable function --- lib/pleroma/object.ex | 4 ++++ lib/pleroma/object/fetcher.ex | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index cde0eddd9..b4ed3a9b2 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -255,4 +255,8 @@ def update_data(%Object{data: data} = object, attrs \\ %{}) do |> Object.change(%{data: Map.merge(data || %{}, attrs)}) |> Repo.update() end + + def local?(%Object{data: %{"id" => id}}) do + String.starts_with?(id, Pleroma.Web.base_url() <> "/") + end end diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 9a9a46550..4d71c91a8 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -49,7 +49,7 @@ defp reinject_object(struct, data) do end def refetch_object(%Object{data: %{"id" => id}} = object) do - with {:local, false} <- {:local, String.starts_with?(id, Pleroma.Web.base_url() <> "/")}, + with {:local, false} <- {:local, Object.local?(object)}, {:ok, data} <- fetch_and_contain_remote_object_from_id(id), {:ok, object} <- reinject_object(object, data) do {:ok, object} From d3656c2725fa80ea66dd9de2d74893fe9888ef57 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 25 Nov 2019 09:53:11 +0000 Subject: [PATCH 16/19] add ability to set a custom user-agent string --- config/config.exs | 1 + docs/configuration/cheatsheet.md | 7 +++++++ lib/pleroma/application.ex | 10 ++++++++-- test/http/request_builder_test.exs | 10 ++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/config/config.exs b/config/config.exs index 1e36d3314..b60ffef7d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -209,6 +209,7 @@ config :pleroma, :http, proxy_url: nil, send_user_agent: true, + user_agent: :default, adapter: [ ssl_options: [ # Workaround for remote server certificate chain issues diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 07d9a1d45..082906293 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -74,6 +74,13 @@ You shouldn't edit the base config directly to avoid breakages and merge conflic * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. +## :http + +* `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`) +* `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`) +* `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default` +* `adapter`: array of hackney options + ## Federation ### MRF policies diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2b6a55f98..9dbd1e26b 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -17,8 +17,14 @@ def named_version, do: @name <> " " <> @version def repository, do: @repository def user_agent do - info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>" - named_version() <> "; " <> info + case Pleroma.Config.get([:http, :user_agent], :default) do + :default -> + info = "#{Pleroma.Web.base_url()} <#{Pleroma.Config.get([:instance, :email], "")}>" + named_version() <> "; " <> info + + custom -> + custom + end end # See http://elixir-lang.org/docs/stable/elixir/Application.html diff --git a/test/http/request_builder_test.exs b/test/http/request_builder_test.exs index 170ca916f..80ef25d7b 100644 --- a/test/http/request_builder_test.exs +++ b/test/http/request_builder_test.exs @@ -16,11 +16,21 @@ test "don't send pleroma user agent" do test "send pleroma user agent" do Pleroma.Config.put([:http, :send_user_agent], true) + Pleroma.Config.put([:http, :user_agent], :default) assert RequestBuilder.headers(%{}, []) == %{ headers: [{"User-Agent", Pleroma.Application.user_agent()}] } end + + test "send custom user agent" do + Pleroma.Config.put([:http, :send_user_agent], true) + Pleroma.Config.put([:http, :user_agent], "totally-not-pleroma") + + assert RequestBuilder.headers(%{}, []) == %{ + headers: [{"User-Agent", "totally-not-pleroma"}] + } + end end describe "add_optional_params/3" do From e2dc89069d6d77a10848e53f321e2e464f539a25 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 25 Nov 2019 11:26:42 +0000 Subject: [PATCH 17/19] move documentation section for http client --- docs/configuration/cheatsheet.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 082906293..dc2f55229 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -74,13 +74,6 @@ You shouldn't edit the base config directly to avoid breakages and merge conflic * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. -## :http - -* `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`) -* `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`) -* `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default` -* `adapter`: array of hackney options - ## Federation ### MRF policies @@ -355,7 +348,17 @@ Available caches: * `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration). * `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds). -## :hackney_pools +## HTTP client + +### :http + +* `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`) +* `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`) +* `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default` +* `adapter`: array of hackney options + + +### :hackney_pools Advanced. Tweaks Hackney (http client) connections pools. From 02f7383891ff0a8dd17f00d6d00ec3495116e38a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 25 Nov 2019 17:19:33 +0300 Subject: [PATCH 18/19] ActivityPub controller: do not render remote users --- .../web/activity_pub/activity_pub_controller.ex | 3 ++- .../activity_pub/activity_pub_controller_test.exs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index b2cd965fe..dec5da0d3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -45,7 +45,7 @@ def relay_active?(conn, _) do end def user(conn, %{"nickname" => nickname}) do - with %User{} = user <- User.get_cached_by_nickname(nickname), + with %User{local: true} = user <- User.get_cached_by_nickname(nickname), {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_content_type("application/activity+json") @@ -53,6 +53,7 @@ def user(conn, %{"nickname" => nickname}) do |> render("user.json", %{user: user}) else nil -> {:error, :not_found} + %{local: false} -> {:error, :not_found} 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 a5414c521..1aa73d75c 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -110,6 +110,19 @@ test "it returns a json representation of the user with accept application/ld+js assert json_response(conn, 200) == UserView.render("user.json", %{user: user}) end + + test "it returns 404 for remote users", %{ + conn: conn + } do + user = insert(:user, local: false, nickname: "remoteuser@example.com") + + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/users/#{user.nickname}.json") + + assert json_response(conn, 404) + end end describe "/object/:uuid" do From 4b10804f21b80b74f9f9f85c9ecd6e1ec791255d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 25 Nov 2019 17:55:17 +0300 Subject: [PATCH 19/19] OStatus controller: don't serve json at /notice/, redirect instead --- lib/pleroma/web/ostatus/ostatus_controller.ex | 46 ++++------- test/web/ostatus/ostatus_controller_test.exs | 79 ++++--------------- 2 files changed, 28 insertions(+), 97 deletions(-) diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 12a7c2365..01ec7941e 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Plugs.RateLimiter alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPubController - alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.Metadata.PlayerView @@ -38,11 +37,9 @@ def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do with id <- o_status_url(conn, :object, uuid), {_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id_with_object(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + {_, true} <- {:public?, Visibility.is_public?(activity)} do case format do - "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, nil, activity, user) + _ -> redirect(conn, to: "/notice/#{activity.id}") end else reason when reason in [{:public?, false}, {:activity, nil}] -> @@ -61,11 +58,9 @@ def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do with id <- o_status_url(conn, :activity, uuid), {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + {_, true} <- {:public?, Visibility.is_public?(activity)} do case format do - "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, format, activity, user) + _ -> redirect(conn, to: "/notice/#{activity.id}") end else reason when reason in [{:public?, false}, {:activity, nil}] -> @@ -81,7 +76,15 @@ def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do {_, true} <- {:public?, Visibility.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do cond do - format == "html" && activity.data["type"] == "Create" -> + format in ["json", "activity+json"] -> + if activity.local do + %{data: %{"id" => redirect_url}} = Object.normalize(activity) + redirect(conn, external: redirect_url) + else + {:error, :not_found} + end + + activity.data["type"] == "Create" -> %Object{} = object = Object.normalize(activity) RedirectController.redirector_with_meta( @@ -94,11 +97,8 @@ def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do } ) - format == "html" -> - RedirectController.redirector(conn, nil) - true -> - represent_activity(conn, format, activity, user) + RedirectController.redirector(conn, nil) end else reason when reason in [{:public?, false}, {:activity, nil}] -> @@ -135,24 +135,6 @@ def notice_player(conn, %{"id" => id}) do end end - defp represent_activity( - conn, - "activity+json", - %Activity{data: %{"type" => "Create"}} = activity, - _user - ) do - object = Object.normalize(activity) - - conn - |> put_resp_header("content-type", "application/activity+json") - |> put_view(ObjectView) - |> render("object.json", %{object: object}) - end - - defp represent_activity(_conn, _, _, _) do - {:error, :not_found} - end - def errors(conn, {:error, :not_found}) do render_error(conn, :not_found, "Not found") end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 37b7b62f5..50235dfef 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -35,23 +35,6 @@ test "redirects to /notice/id for html format", %{conn: conn} do assert redirected_to(conn) == "/notice/#{note_activity.id}" end - test "500s when user not found", %{conn: conn} do - note_activity = insert(:note_activity) - object = Object.normalize(note_activity) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - User.invalidate_cache(user) - Pleroma.Repo.delete(user) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) - url = "/objects/#{uuid}" - - conn = - conn - |> put_req_header("accept", "application/xml") - |> get(url) - - assert response(conn, 500) == ~S({"error":"Something went wrong"}) - end - test "404s on private objects", %{conn: conn} do note_activity = insert(:direct_note_activity) object = Object.normalize(note_activity) @@ -82,21 +65,6 @@ test "redirects to /notice/id for html format", %{conn: conn} do assert redirected_to(conn) == "/notice/#{note_activity.id}" end - test "505s when user not found", %{conn: conn} do - note_activity = insert(:note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - User.invalidate_cache(user) - Pleroma.Repo.delete(user) - - conn = - conn - |> put_req_header("accept", "text/html") - |> get("/activities/#{uuid}") - - assert response(conn, 500) == ~S({"error":"Something went wrong"}) - end - test "404s on private activities", %{conn: conn} do note_activity = insert(:direct_note_activity) [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) @@ -127,21 +95,28 @@ test "gets an activity in AS2 format", %{conn: conn} do end describe "GET notice/2" do - test "gets a notice in xml format", %{conn: conn} do + test "redirects to a proper object URL when json requested and the object is local", %{ + conn: conn + } do note_activity = insert(:note_activity) + expected_redirect_url = Object.normalize(note_activity).data["id"] - conn - |> get("/notice/#{note_activity.id}") - |> response(200) + redirect_url = + conn + |> put_req_header("accept", "application/activity+json") + |> get("/notice/#{note_activity.id}") + |> redirected_to() + + assert redirect_url == expected_redirect_url end - test "gets a notice in AS2 format", %{conn: conn} do - note_activity = insert(:note_activity) + test "returns a 404 on remote notice when json requested", %{conn: conn} do + note_activity = insert(:note_activity, local: false) conn |> put_req_header("accept", "application/activity+json") |> get("/notice/#{note_activity.id}") - |> json_response(200) + |> response(404) end test "500s when actor not found", %{conn: conn} do @@ -157,32 +132,6 @@ test "500s when actor not found", %{conn: conn} do assert response(conn, 500) == ~S({"error":"Something went wrong"}) end - test "only gets a notice in AS2 format for Create messages", %{conn: conn} do - note_activity = insert(:note_activity) - url = "/notice/#{note_activity.id}" - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get(url) - - assert json_response(conn, 200) - - user = insert(:user) - - {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user) - url = "/notice/#{like_activity.id}" - - assert like_activity.data["type"] == "Like" - - conn = - build_conn() - |> put_req_header("accept", "application/activity+json") - |> get(url) - - assert response(conn, 404) - end - test "render html for redirect for html format", %{conn: conn} do note_activity = insert(:note_activity)