--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.ReportOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["reports"],
+ summary: "File a report",
+ description: "Report problematic users to your moderators",
+ operationId: "ReportController.create",
+ security: [%{"oAuth" => ["follow", "write:reports"]}],
+ requestBody: Helpers.request_body("Parameters", create_request(), required: true),
+ responses: %{
+ 200 => Operation.response("Report", "application/json", create_response()),
+ 400 => Operation.response("Report", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp create_request do
+ %Schema{
+ title: "ReportCreateRequest",
+ description: "POST body for creating a report",
+ type: :object,
+ properties: %{
+ account_id: %Schema{type: :string, description: "ID of the account to report"},
+ status_ids: %Schema{
+ type: :array,
+ items: %Schema{type: :string},
+ description: "Array of Statuses to attach to the report, for context"
+ },
+ comment: %Schema{
+ type: :string,
+ description: "Reason for the report"
+ },
+ forward: %Schema{
+ type: :boolean,
+ default: false,
+ description:
+ "If the account is remote, should the report be forwarded to the remote admin?"
+ }
+ },
+ required: [:account_id],
+ example: %{
+ "account_id" => "123",
+ "status_ids" => ["1337"],
+ "comment" => "bad status!",
+ "forward" => "false"
+ }
+ }
+ end
+
+ defp create_response do
+ %Schema{
+ title: "ReportResponse",
+ type: :object,
+ properties: %{
+ id: %Schema{type: :string, description: "Report ID"},
+ action_taken: %Schema{type: :boolean, description: "Is action taken?"}
+ },
+ example: %{
+ "id" => "123",
+ "action_taken" => false
+ }
+ }
+ end
+end
ThreadMute.exists?(user.id, activity.data["context"])
end
- def report(user, %{"account_id" => account_id} = data) do
- with {:ok, account} <- get_reported_account(account_id),
- {:ok, {content_html, _, _}} <- make_report_content_html(data["comment"]),
+ def report(user, data) do
+ with {:ok, account} <- get_reported_account(data.account_id),
+ {:ok, {content_html, _, _}} <- make_report_content_html(data[:comment]),
{:ok, statuses} <- get_report_statuses(account, data) do
ActivityPub.flag(%{
context: Utils.generate_context_id(),
account: account,
statuses: statuses,
content: content_html,
- forward: data["forward"] || false
+ forward: Map.get(data, :forward, false)
})
end
end
- def report(_user, _params), do: {:error, dgettext("errors", "Valid `account_id` required")}
-
defp get_reported_account(account_id) do
case User.get_cached_by_id(account_id) do
%User{} = account -> {:ok, account}
end
end
- def get_report_statuses(%User{ap_id: actor}, %{"status_ids" => status_ids}) do
+ def get_report_statuses(%User{ap_id: actor}, %{status_ids: status_ids})
+ when is_list(status_ids) do
{:ok, Activity.all_by_actor_and_id(actor, status_ids)}
end
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+ plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError)
plug(OAuthScopesPlug, %{scopes: ["write:reports"]} when action == :create)
-
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ReportOperation
+
@doc "POST /api/v1/reports"
- def create(%{assigns: %{user: user}} = conn, params) do
+ def create(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, activity} <- Pleroma.Web.CommonAPI.report(user, params) do
render(conn, "show.json", activity: activity)
end
{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
response =
{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
{:ok, %{id: second_report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel very offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel very offended",
+ status_ids: [activity.id]
})
%{
{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
response =
{:ok, %{id: first_report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
{:ok, %{id: second_report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I don't like this user"
+ account_id: target_user.id,
+ comment: "I don't like this user"
})
CommonAPI.update_report_state(second_report_id, "closed")
{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.report(user, %{"account_id" => other_user.id})
+ {:ok, activity} = CommonAPI.report(user, %{account_id: other_user.id})
expected = %{
content: nil,
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "toot"})
{:ok, report_activity} =
- CommonAPI.report(user, %{"account_id" => other_user.id, "status_ids" => [activity.id]})
+ CommonAPI.report(user, %{account_id: other_user.id, status_ids: [activity.id]})
other_user = Pleroma.User.get_by_id(other_user.id)
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.report(user, %{"account_id" => other_user.id})
+ {:ok, activity} = CommonAPI.report(user, %{account_id: other_user.id})
{:ok, activity} = CommonAPI.update_report_state(activity.id, "closed")
assert %{state: "closed"} =
{:ok, activity} =
CommonAPI.report(user, %{
- "account_id" => other_user.id,
- "comment" => "posts are too good for this instance"
+ account_id: other_user.id,
+ comment: "posts are too good for this instance"
})
assert %{content: "posts are too good for this instance"} =
{:ok, activity} =
CommonAPI.report(user, %{
- "account_id" => other_user.id,
- "comment" => ""
+ account_id: other_user.id,
+ comment: ""
})
data = Map.put(activity.data, "content", "<script> alert('hecked :D:D:D:D:D:D:D') </script>")
{:ok, activity} =
CommonAPI.report(user, %{
- "account_id" => other_user.id,
- "comment" => ""
+ account_id: other_user.id,
+ comment: ""
})
Pleroma.User.delete(other_user)
comment = "foobar"
report_data = %{
- "account_id" => target_user.id,
- "comment" => comment,
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: comment,
+ status_ids: [activity.id]
}
note_obj = %{
{:ok, %Activity{id: report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
{:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
{:ok, %Activity{id: report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
{:ok, %Activity{id: first_report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel offended",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel offended",
+ status_ids: [activity.id]
})
{:ok, %Activity{id: second_report_id}} =
CommonAPI.report(reporter, %{
- "account_id" => target_user.id,
- "comment" => "I feel very offended!",
- "status_ids" => [activity.id]
+ account_id: target_user.id,
+ comment: "I feel very offended!",
+ status_ids: [activity.id]
})
{:ok, report_ids} =
test "submit a basic report", %{conn: conn, target_user: target_user} do
assert %{"action_taken" => false, "id" => _} =
conn
+ |> put_req_header("content-type", "application/json")
|> post("/api/v1/reports", %{"account_id" => target_user.id})
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
end
test "submit a report with statuses and comment", %{
} do
assert %{"action_taken" => false, "id" => _} =
conn
+ |> put_req_header("content-type", "application/json")
|> post("/api/v1/reports", %{
"account_id" => target_user.id,
"status_ids" => [activity.id],
"comment" => "bad status!",
"forward" => "false"
})
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
end
test "account_id is required", %{
conn: conn,
activity: activity
} do
- assert %{"error" => "Valid `account_id` required"} =
+ assert %{"error" => "Missing field: account_id."} =
conn
+ |> put_req_header("content-type", "application/json")
|> post("/api/v1/reports", %{"status_ids" => [activity.id]})
- |> json_response(400)
+ |> json_response_and_validate_schema(400)
end
test "comment must be up to the size specified in the config", %{
assert ^error =
conn
+ |> put_req_header("content-type", "application/json")
|> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
- |> json_response(400)
+ |> json_response_and_validate_schema(400)
end
test "returns error when account is not exist", %{
conn: conn,
activity: activity
} do
- conn = post(conn, "/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
- assert json_response(conn, 400) == %{"error" => "Account not found"}
+ assert json_response_and_validate_schema(conn, 400) == %{"error" => "Account not found"}
end
test "doesn't fail if an admin has no email", %{conn: conn, target_user: target_user} do
assert %{"action_taken" => false, "id" => _} =
conn
+ |> put_req_header("content-type", "application/json")
|> post("/api/v1/reports", %{"account_id" => target_user.id})
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
end
end