Admin API: Allow changing the state of multiple reports at once
This commit is contained in:
parent
795ea5dfc2
commit
8dcc2f9f5e
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 =
|
||||||
|
reports
|
||||||
|
|> Enum.map(fn report ->
|
||||||
|
with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
|
||||||
ModerationLog.insert_log(%{
|
ModerationLog.insert_log(%{
|
||||||
action: "report_update",
|
action: "report_update",
|
||||||
actor: admin,
|
actor: admin,
|
||||||
subject: report
|
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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|> put("/api/pleroma/admin/reports/#{id}", %{"state" => "resolved"})
|
|> patch("/api/pleroma/admin/reports", %{
|
||||||
|> json_response(:ok)
|
"reports" => [
|
||||||
|
%{"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
|
||||||
|> put("/api/pleroma/admin/reports/#{id}", %{"state" => "closed"})
|
|> patch("/api/pleroma/admin/reports", %{
|
||||||
|> json_response(:ok)
|
"reports" => [
|
||||||
|
%{"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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue