Admin API: Allow changing the state of multiple reports at once

This commit is contained in:
Maxim Filippov 2019-10-04 19:00:58 +03:00
parent 795ea5dfc2
commit 8dcc2f9f5e
7 changed files with 142 additions and 27 deletions

View File

@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed ### Changed
- **Breaking:** Elixir >=1.8 is now required (was >= 1.7) - **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
- **Breaking:** Admin API: Return link alongside with token on password reset - **Breaking:** Admin API: Return link alongside with token on password reset
- **Breaking:** Admin API: Changing report state now uses `PATCH` (it was `PUT` before) and allows updating multiple reports at once (API changed)
- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings) - Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings)
- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
- Admin API: Return `total` when querying for reports - Admin API: Return `total` when querying for reports

View File

@ -672,6 +672,18 @@ def update_report_state(%Activity{} = activity, state) when state in @supported_
|> Repo.update() |> Repo.update()
end end
def update_report_state(activity_ids, state) when state in @supported_report_states do
activities_num = length(activity_ids)
from(a in Activity, where: a.id in ^activity_ids)
|> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)])
|> Repo.update_all([])
|> case do
{^activities_num, _} -> :ok
_ -> {:error, activity_ids}
end
end
def update_report_state(_, _), do: {:error, "Unsupported state"} def update_report_state(_, _), do: {:error, "Unsupported state"}
def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do

View File

@ -480,17 +480,26 @@ def report_show(conn, %{"id" => id}) do
end end
end end
def report_update_state(%{assigns: %{user: admin}} = conn, %{"id" => id, "state" => state}) do def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
with {:ok, report} <- CommonAPI.update_report_state(id, state) do result =
ModerationLog.insert_log(%{ reports
action: "report_update", |> Enum.map(fn report ->
actor: admin, with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
subject: report ModerationLog.insert_log(%{
}) action: "report_update",
actor: admin,
subject: activity
})
conn activity
|> put_view(ReportView) else
|> render("show.json", Report.extract_report_info(report)) {:error, message} -> %{id: report["id"], error: message}
end
end)
case Enum.any?(result, &Map.has_key?(&1, :error)) do
true -> json_response(conn, :bad_request, result)
false -> json_response(conn, :no_content, "")
end end
end end

View File

@ -346,6 +346,13 @@ defp get_reported_account(account_id) do
end end
end end
def update_report_state(activity_ids, state) when is_list(activity_ids) do
case Utils.update_report_state(activity_ids, state) do
:ok -> {:ok, activity_ids}
_ -> {:error, dgettext("errors", "Could not update state")}
end
end
def update_report_state(activity_id, state) do def update_report_state(activity_id, state) do
with %Activity{} = activity <- Activity.get_by_id(activity_id) do with %Activity{} = activity <- Activity.get_by_id(activity_id) do
Utils.update_report_state(activity, state) Utils.update_report_state(activity, state)

View File

@ -194,7 +194,7 @@ defmodule Pleroma.Web.Router do
get("/reports", AdminAPIController, :list_reports) get("/reports", AdminAPIController, :list_reports)
get("/reports/:id", AdminAPIController, :report_show) get("/reports/:id", AdminAPIController, :report_show)
put("/reports/:id", AdminAPIController, :report_update_state) patch("/reports", AdminAPIController, :reports_update)
post("/reports/:id/respond", AdminAPIController, :report_respond) post("/reports/:id/respond", AdminAPIController, :report_respond)
put("/statuses/:id", AdminAPIController, :status_update) put("/statuses/:id", AdminAPIController, :status_update)

View File

@ -1224,7 +1224,7 @@ test "returns 404 when report id is invalid", %{conn: conn} do
end end
end end
describe "PUT /api/pleroma/admin/reports/:id" do describe "PATCH /api/pleroma/admin/reports" do
setup %{conn: conn} do setup %{conn: conn} do
admin = insert(:user, info: %{is_admin: true}) admin = insert(:user, info: %{is_admin: true})
[reporter, target_user] = insert_pair(:user) [reporter, target_user] = insert_pair(:user)
@ -1237,16 +1237,32 @@ test "returns 404 when report id is invalid", %{conn: conn} do
"status_ids" => [activity.id] "status_ids" => [activity.id]
}) })
%{conn: assign(conn, :user, admin), id: report_id, admin: admin} {:ok, %{id: second_report_id}} =
CommonAPI.report(reporter, %{
"account_id" => target_user.id,
"comment" => "I feel very offended",
"status_ids" => [activity.id]
})
%{
conn: assign(conn, :user, admin),
id: report_id,
admin: admin,
second_report_id: second_report_id
}
end end
test "mark report as resolved", %{conn: conn, id: id, admin: admin} do test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
response = conn
conn |> patch("/api/pleroma/admin/reports", %{
|> put("/api/pleroma/admin/reports/#{id}", %{"state" => "resolved"}) "reports" => [
|> json_response(:ok) %{"state" => "resolved", "id" => id}
]
})
|> json_response(:no_content)
assert response["state"] == "resolved" activity = Activity.get_by_id(id)
assert activity.data["state"] == "resolved"
log_entry = Repo.one(ModerationLog) log_entry = Repo.one(ModerationLog)
@ -1255,12 +1271,16 @@ test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
end end
test "closes report", %{conn: conn, id: id, admin: admin} do test "closes report", %{conn: conn, id: id, admin: admin} do
response = conn
conn |> patch("/api/pleroma/admin/reports", %{
|> put("/api/pleroma/admin/reports/#{id}", %{"state" => "closed"}) "reports" => [
|> json_response(:ok) %{"state" => "closed", "id" => id}
]
})
|> json_response(:no_content)
assert response["state"] == "closed" activity = Activity.get_by_id(id)
assert activity.data["state"] == "closed"
log_entry = Repo.one(ModerationLog) log_entry = Repo.one(ModerationLog)
@ -1271,17 +1291,54 @@ test "closes report", %{conn: conn, id: id, admin: admin} do
test "returns 400 when state is unknown", %{conn: conn, id: id} do test "returns 400 when state is unknown", %{conn: conn, id: id} do
conn = conn =
conn conn
|> put("/api/pleroma/admin/reports/#{id}", %{"state" => "test"}) |> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "test", "id" => id}
]
})
assert json_response(conn, :bad_request) == "Unsupported state" assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
end end
test "returns 404 when report is not exist", %{conn: conn} do test "returns 404 when report is not exist", %{conn: conn} do
conn = conn =
conn conn
|> put("/api/pleroma/admin/reports/test", %{"state" => "closed"}) |> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "closed", "id" => "test"}
]
})
assert json_response(conn, :not_found) == "Not found" assert hd(json_response(conn, :bad_request))["error"] == "not_found"
end
test "updates state of multiple reports", %{
conn: conn,
id: id,
admin: admin,
second_report_id: second_report_id
} do
conn
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "resolved", "id" => id},
%{"state" => "closed", "id" => second_report_id}
]
})
|> json_response(:no_content)
activity = Activity.get_by_id(id)
second_activity = Activity.get_by_id(second_report_id)
assert activity.data["state"] == "resolved"
assert second_activity.data["state"] == "closed"
[first_log_entry, second_log_entry] = Repo.all(ModerationLog)
assert ModerationLog.get_log_entry_message(first_log_entry) ==
"@#{admin.nickname} updated report ##{id} with 'resolved' state"
assert ModerationLog.get_log_entry_message(second_log_entry) ==
"@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
end end
end end

View File

@ -423,6 +423,35 @@ test "does not update report state when state is unsupported" do
assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"} assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
end end
test "updates state of multiple reports" do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)
{:ok, %Activity{id: first_report_id}} =
CommonAPI.report(reporter, %{
"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]
})
{:ok, report_ids} =
CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
first_report = Activity.get_by_id(first_report_id)
second_report = Activity.get_by_id(second_report_id)
assert report_ids -- [first_report_id, second_report_id] == []
assert first_report.data["state"] == "resolved"
assert second_report.data["state"] == "resolved"
end
end end
describe "reblog muting" do describe "reblog muting" do