diff --git a/lib/pleroma/web/api_spec/operations/admin/report_operation.ex b/lib/pleroma/web/api_spec/operations/admin/report_operation.ex
index cfa892d29..30e56366e 100644
--- a/lib/pleroma/web/api_spec/operations/admin/report_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/report_operation.ex
@@ -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
index 000000000..ee8870dc2
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex
@@ -0,0 +1,97 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# 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
index 000000000..d93d7570a
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/controllers/report_controller.ex
@@ -0,0 +1,46 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# 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
index 000000000..a0b3f085c
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/views/report_view.ex
@@ -0,0 +1,55 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# 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
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index d71011033..0064dacc8 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -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
index 000000000..c507aeca0
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs
@@ -0,0 +1,80 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# 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