Enhance reports in Pleroma API: index, show
authorHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Mon, 25 Jan 2021 19:15:33 +0000 (20:15 +0100)
committerHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Wed, 17 Feb 2021 17:46:53 +0000 (18:46 +0100)
lib/pleroma/web/api_spec/operations/admin/report_operation.ex
lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex [new file with mode: 0644]
lib/pleroma/web/pleroma_api/controllers/report_controller.ex [new file with mode: 0644]
lib/pleroma/web/pleroma_api/views/report_view.ex [new file with mode: 0644]
lib/pleroma/web/router.ex
test/pleroma/web/pleroma_api/controllers/report_controller_test.exs [new file with mode: 0644]

index cfa892d296abba21076839d4b95630e6835d1811..30e56366e72520e3ff811e56aade8dfabadc8dd7 100644 (file)
@@ -136,11 +136,11 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
     }
   end
 
-  defp report_state do
+  def report_state do
     %Schema{type: :string, enum: ["open", "closed", "resolved"]}
   end
 
-  defp id_param do
+  def id_param do
     Operation.parameter(:id, :path, FlakeID, "Report ID",
       example: "9umDrYheeY451cQnEe",
       required: true
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex
new file mode 100644 (file)
index 0000000..ee8870d
--- /dev/null
@@ -0,0 +1,97 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaReportOperation do
+  alias OpenApiSpex.Operation
+  alias OpenApiSpex.Schema
+  alias Pleroma.Web.ApiSpec.Admin.ReportOperation
+  alias Pleroma.Web.ApiSpec.Schemas.Account
+  alias Pleroma.Web.ApiSpec.Schemas.ApiError
+  alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+  alias Pleroma.Web.ApiSpec.Schemas.Status
+
+  def open_api_operation(action) do
+    operation = String.to_existing_atom("#{action}_operation")
+    apply(__MODULE__, operation, [])
+  end
+
+  def index_operation do
+    %Operation{
+      tags: ["Reports"],
+      summary: "Get a list of your own reports",
+      operationId: "PleromaAPI.ReportController.index",
+      security: [%{"oAuth" => ["read:reports"]}],
+      parameters: [
+        Operation.parameter(
+          :state,
+          :query,
+          ReportOperation.report_state(),
+          "Filter by report state"
+        ),
+        Operation.parameter(
+          :limit,
+          :query,
+          %Schema{type: :integer},
+          "The number of records to retrieve"
+        ),
+        Operation.parameter(
+          :page,
+          :query,
+          %Schema{type: :integer, default: 1},
+          "Page number"
+        ),
+        Operation.parameter(
+          :page_size,
+          :query,
+          %Schema{type: :integer, default: 50},
+          "Number number of log entries per page"
+        )
+      ],
+      responses: %{
+        200 =>
+          Operation.response("Response", "application/json", %Schema{
+            type: :object,
+            properties: %{
+              total: %Schema{type: :integer},
+              reports: %Schema{
+                type: :array,
+                items: report()
+              }
+            }
+          }),
+        404 => Operation.response("Not Found", "application/json", ApiError)
+      }
+    }
+  end
+
+  def show_operation do
+    %Operation{
+      tags: ["Reports"],
+      summary: "Get an individual report",
+      operationId: "PleromaAPI.ReportController.show",
+      parameters: [ReportOperation.id_param()],
+      security: [%{"oAuth" => ["read:reports"]}],
+      responses: %{
+        200 => Operation.response("Report", "application/json", report()),
+        404 => Operation.response("Not Found", "application/json", ApiError)
+      }
+    }
+  end
+
+  # Copied from ReportOperation.report with removing notes
+  defp report do
+    %Schema{
+      type: :object,
+      properties: %{
+        id: FlakeID,
+        state: ReportOperation.report_state(),
+        account: Account,
+        actor: Account,
+        content: %Schema{type: :string},
+        created_at: %Schema{type: :string, format: :"date-time"},
+        statuses: %Schema{type: :array, items: Status}
+      }
+    }
+  end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/report_controller.ex b/lib/pleroma/web/pleroma_api/controllers/report_controller.ex
new file mode 100644 (file)
index 0000000..d93d757
--- /dev/null
@@ -0,0 +1,46 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ReportController do
+  use Pleroma.Web, :controller
+
+  alias Pleroma.Activity
+  alias Pleroma.Web.ActivityPub.Utils
+  alias Pleroma.Web.AdminAPI.Report
+
+  action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+  plug(Pleroma.Web.ApiSpec.CastAndValidate)
+  plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read:reports"]})
+
+  defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaReportOperation
+
+  @doc "GET /api/v0/pleroma/reports"
+  def index(%{assigns: %{user: user}, body_params: params} = conn, _) do
+    params =
+      params
+      |> Map.put(:actor_id, user.ap_id)
+
+    reports = Utils.get_reports(params, Map.get(params, :page, 1), Map.get(params, :size, 20))
+
+    render(conn, "index.json", %{reports: reports, for: user})
+  end
+
+  @doc "GET /api/v0/pleroma/reports/:id"
+  def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+    with %Activity{} = report <- Activity.get_report(id),
+         true <- report.actor == user.ap_id,
+         %{} = report_info <- Report.extract_report_info(report) do
+      render(conn, "show.json", Map.put(report_info, :for, user))
+    else
+      false ->
+        {:error, :not_found}
+
+      nil ->
+        {:error, :not_found}
+
+      e ->
+        {:error, inspect(e)}
+    end
+  end
+end
diff --git a/lib/pleroma/web/pleroma_api/views/report_view.ex b/lib/pleroma/web/pleroma_api/views/report_view.ex
new file mode 100644 (file)
index 0000000..a0b3f08
--- /dev/null
@@ -0,0 +1,55 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ReportView do
+  use Pleroma.Web, :view
+
+  alias Pleroma.HTML
+  alias Pleroma.Web.AdminAPI.Report
+  alias Pleroma.Web.CommonAPI.Utils
+  alias Pleroma.Web.MastodonAPI.AccountView
+  alias Pleroma.Web.MastodonAPI.StatusView
+
+  def render("index.json", %{reports: reports, for: for_user}) do
+    %{
+      reports:
+        reports[:items]
+        |> Enum.map(&Report.extract_report_info/1)
+        |> Enum.map(&render(__MODULE__, "show.json", Map.put(&1, :for, for_user))),
+      total: reports[:total]
+    }
+  end
+
+  def render("show.json", %{
+        report: report,
+        user: actor,
+        account: account,
+        statuses: statuses,
+        for: for_user
+      }) do
+    created_at = Utils.to_masto_date(report.data["published"])
+
+    content =
+      unless is_nil(report.data["content"]) do
+        HTML.filter_tags(report.data["content"])
+      else
+        nil
+      end
+
+    %{
+      id: report.id,
+      account: AccountView.render("show.json", %{user: account, for: for_user}),
+      actor: AccountView.render("show.json", %{user: actor, for: for_user}),
+      content: content,
+      created_at: created_at,
+      statuses:
+        StatusView.render("index.json", %{
+          activities: statuses,
+          as: :activity,
+          for: for_user
+        }),
+      state: report.data["state"]
+    }
+  end
+end
index d71011033cbf8b6e0f6616fc12d4d2c571f1cc47..0064dacc8ef6ebcd43a47f0410e698a214d4dcc6 100644 (file)
@@ -368,6 +368,12 @@ defmodule Pleroma.Web.Router do
     get("/statuses/:id/reactions", EmojiReactionController, :index)
   end
 
+  scope "/api/v0/pleroma", Pleroma.Web.PleromaAPI do
+    pipe_through(:authenticated_api)
+    get("/reports", ReportController, :index)
+    get("/reports/:id", ReportController, :show)
+  end
+
   scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
     scope [] do
       pipe_through(:authenticated_api)
diff --git a/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs
new file mode 100644 (file)
index 0000000..c507aec
--- /dev/null
@@ -0,0 +1,80 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ReportControllerTest do
+  use Pleroma.Web.ConnCase, async: true
+
+  import Pleroma.Factory
+
+  alias Pleroma.Web.CommonAPI
+
+  describe "GET /api/v0/pleroma/reports" do
+    test "returns list of own reports" do
+      %{conn: reporter_conn, user: reporter} = oauth_access(["read:reports"])
+      %{conn: reported_conn, user: reported} = oauth_access(["read:reports"])
+      activity = insert(:note_activity, user: reported)
+
+      {:ok, %{id: report_id}} =
+        CommonAPI.report(reporter, %{
+          account_id: reported.id,
+          comment: "You stole my sandwich!",
+          status_ids: [activity.id]
+        })
+
+      assert reported_response =
+               reported_conn
+               |> get("/api/v0/pleroma/reports")
+               |> json_response_and_validate_schema(:ok)
+
+      assert reported_response == %{"reports" => [], "total" => 0}
+
+      assert reporter_response =
+               reporter_conn
+               |> get("/api/v0/pleroma/reports")
+               |> json_response_and_validate_schema(:ok)
+
+      assert %{"reports" => [report], "total" => 1} = reporter_response
+      assert report["id"] == report_id
+      refute report["notes"]
+    end
+  end
+
+  describe "GET /api/v0/pleroma/reports/:id" do
+    test "returns report by its id" do
+      %{conn: reporter_conn, user: reporter} = oauth_access(["read:reports"])
+      %{conn: reported_conn, user: reported} = oauth_access(["read:reports"])
+      activity = insert(:note_activity, user: reported)
+
+      {:ok, %{id: report_id}} =
+        CommonAPI.report(reporter, %{
+          account_id: reported.id,
+          comment: "You stole my sandwich!",
+          status_ids: [activity.id]
+        })
+
+      assert reported_conn
+             |> get("/api/v0/pleroma/reports/#{report_id}")
+             |> json_response_and_validate_schema(:not_found)
+
+      assert response =
+               reporter_conn
+               |> get("/api/v0/pleroma/reports/#{report_id}")
+               |> json_response_and_validate_schema(:ok)
+
+      assert response["id"] == report_id
+      refute response["notes"]
+    end
+
+    test "returns 404 when report id is invalid" do
+      %{conn: conn, user: _user} = oauth_access(["read:reports"])
+
+      assert response =
+               conn
+               |> get("/api/v0/pleroma/reports/0")
+               |> json_response_and_validate_schema(:not_found)
+
+      assert response == %{"error" => "Record not found"}
+    end
+  end
+end