From a9459ff98f0af590931ef279c2bc7efb0cceac5a Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 14 Jul 2019 00:37:19 +0300 Subject: [PATCH 1/3] Admin API: Endpoint for fetching latest user's statuses --- CHANGELOG.md | 1 + docs/api/admin_api.md | 12 +++++++ .../web/admin_api/admin_api_controller.ex | 16 +++++++++ lib/pleroma/web/router.ex | 1 + test/support/factory.ex | 5 ++- .../admin_api/admin_api_controller_test.exs | 33 +++++++++++++++++++ 6 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 942733ab6..86cbaeff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Configuration: `federation_incoming_replies_max_depth` option - Added synchronization of following/followers counters for external users - Configuration: `enabled` option for `Pleroma.Emails.Mailer`, defaulting to `false`. - Mastodon API: Add support for categories for custom emojis by reusing the group feature. +- Admin API: Endpoint for fetching latest user's statuses ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index c429da822..3880af218 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -187,6 +187,18 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - On failure: `Not found` - On success: JSON of the user +## `/api/pleroma/admin/users/:nickname_or_id/statuses` + +### Retrive user's latest statuses + +- Method: `GET` +- Params: + - `nickname` or `id` + - *optional* `page_size`: number of statuses to return (default is `20`) +- Response: + - On failure: `Not found` + - On success: JSON array of user's latest statuses + ## `/api/pleroma/admin/relay` ### Follow a Relay diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 4a0bf4823..64ad7e8e2 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -82,6 +82,22 @@ def user_show(conn, %{"nickname" => nickname}) do end end + def list_user_statuses(conn, %{"nickname" => nickname} = params) do + with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do + {_, page_size} = page_params(params) + + activities = + ActivityPub.fetch_user_activities(user, nil, %{ + "limit" => page_size + }) + + conn + |> json(StatusView.render("index.json", %{activities: activities, as: :activity})) + else + _ -> {:error, :not_found} + end + end + def user_toggle_activation(conn, %{"nickname" => nickname}) do user = User.get_cached_by_nickname(nickname) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index d53fa8a35..9315302c8 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -197,6 +197,7 @@ defmodule Pleroma.Web.Router do get("/users", AdminAPIController, :list_users) get("/users/:nickname", AdminAPIController, :user_show) + get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/reports", AdminAPIController, :list_reports) get("/reports/:id", AdminAPIController, :report_show) diff --git a/test/support/factory.ex b/test/support/factory.ex index 531eb81e4..807b34545 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -118,7 +118,10 @@ def direct_note_activity_factory do def note_activity_factory(attrs \\ %{}) do user = attrs[:user] || insert(:user) note = attrs[:note] || insert(:note, user: user) + published = attrs[:published] || DateTime.utc_now() |> DateTime.to_iso8601() attrs = Map.drop(attrs, [:user, :note]) + require IEx + IEx.pry() data = %{ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), @@ -126,7 +129,7 @@ def note_activity_factory(attrs \\ %{}) do "actor" => note.data["actor"], "to" => note.data["to"], "object" => note.data["id"], - "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "published" => published, "context" => note.data["context"] } diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 1b71cbff3..9d4b3d74b 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1863,6 +1863,39 @@ test "dispatch setting", %{conn: conn} do } end end + + describe "GET /api/pleroma/admin/users/:nickname/statuses" do + setup do + admin = insert(:user, info: %{is_admin: true}) + user = insert(:user) + + date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!() + date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!() + date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!() + + insert(:note_activity, user: user, published: date1) + insert(:note_activity, user: user, published: date2) + insert(:note_activity, user: user, published: date3) + + conn = + build_conn() + |> assign(:user, admin) + + {:ok, conn: conn, user: user} + end + + test "renders user's statuses", %{conn: conn, user: user} do + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") + + assert json_response(conn, 200) |> length() == 3 + end + + test "renders user's statuses with a limit", %{conn: conn, user: user} do + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2") + + assert json_response(conn, 200) |> length() == 2 + end + end end # Needed for testing From 14ab2fd0f43f0f8338f685d2ea599479e1e103bf Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 23 Jul 2019 12:30:37 +0300 Subject: [PATCH 2/3] remove pry --- test/support/factory.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/support/factory.ex b/test/support/factory.ex index 807b34545..d02bd9212 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -120,8 +120,6 @@ def note_activity_factory(attrs \\ %{}) do note = attrs[:note] || insert(:note, user: user) published = attrs[:published] || DateTime.utc_now() |> DateTime.to_iso8601() attrs = Map.drop(attrs, [:user, :note]) - require IEx - IEx.pry() data = %{ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), From 03471151d6089e318abaf5265d42ffedf7a5b902 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 24 Jul 2019 01:50:09 +0300 Subject: [PATCH 3/3] AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) --- CHANGELOG.md | 1 + docs/api/admin_api.md | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 23 +++++++++++++----- .../web/admin_api/admin_api_controller.ex | 5 +++- .../admin_api/admin_api_controller_test.exs | 24 +++++++++++++++++++ 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a0f2cdc9..6c9381b45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set - NodeInfo: Return `skipThreadContainment` in `metadata` for the `skip_thread_containment` option - Mastodon API: Unsubscribe followers when they unfollow a user +- AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) ### Fixed - Not being able to pin unlisted posts diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 3880af218..98968c1a6 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -195,6 +195,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - Params: - `nickname` or `id` - *optional* `page_size`: number of statuses to return (default is `20`) + - *optional* `godmode`: `true`/`false` – allows to see private statuses - Response: - On failure: `Not found` - On success: JSON array of user's latest statuses diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 31397b09f..a42c50875 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -631,17 +631,28 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do |> Map.put("pinned_activity_ids", user.info.pinned_activities) recipients = - if reading_user do - ["https://www.w3.org/ns/activitystreams#Public"] ++ - [reading_user.ap_id | reading_user.following] - else - ["https://www.w3.org/ns/activitystreams#Public"] - end + user_activities_recipients(%{ + "godmode" => params["godmode"], + "reading_user" => reading_user + }) fetch_activities(recipients, params) |> Enum.reverse() end + defp user_activities_recipients(%{"godmode" => true}) do + [] + end + + defp user_activities_recipients(%{"reading_user" => reading_user}) do + if reading_user do + ["https://www.w3.org/ns/activitystreams#Public"] ++ + [reading_user.ap_id | reading_user.following] + else + ["https://www.w3.org/ns/activitystreams#Public"] + end + end + defp restrict_since(query, %{"since_id" => ""}), do: query defp restrict_since(query, %{"since_id" => since_id}) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 64ad7e8e2..5c64bb81b 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -83,12 +83,15 @@ def user_show(conn, %{"nickname" => nickname}) do end def list_user_statuses(conn, %{"nickname" => nickname} = params) do + godmode = params["godmode"] == "true" || params["godmode"] == true + with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do {_, page_size} = page_params(params) activities = ActivityPub.fetch_user_activities(user, nil, %{ - "limit" => page_size + "limit" => page_size, + "godmode" => godmode }) conn diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 25e062878..20d5268a2 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1934,6 +1934,30 @@ test "renders user's statuses with a limit", %{conn: conn, user: user} do assert json_response(conn, 200) |> length() == 2 end + + test "doesn't return private statuses by default", %{conn: conn, user: user} do + {:ok, _private_status} = + CommonAPI.post(user, %{"status" => "private", "visibility" => "private"}) + + {:ok, _public_status} = + CommonAPI.post(user, %{"status" => "public", "visibility" => "public"}) + + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") + + assert json_response(conn, 200) |> length() == 4 + end + + test "returns private statuses with godmode on", %{conn: conn, user: user} do + {:ok, _private_status} = + CommonAPI.post(user, %{"status" => "private", "visibility" => "private"}) + + {:ok, _public_status} = + CommonAPI.post(user, %{"status" => "public", "visibility" => "public"}) + + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true") + + assert json_response(conn, 200) |> length() == 5 + end end end