Browse Source

Merge branch 'openapi/admin/reports' into 'develop'

Add OpenAPI spec for AdminAPI.ReportController

See merge request pleroma/pleroma!2628
1570-levenshtein-distance-user-search
lain 4 years ago
parent
commit
d6693a9102
9 changed files with 727 additions and 446 deletions
  1. +2
    -2
      docs/API/admin_api.md
  2. +1
    -0
      lib/pleroma/web/activity_pub/utils.ex
  3. +0
    -97
      lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
  4. +107
    -0
      lib/pleroma/web/admin_api/controllers/report_controller.ex
  5. +237
    -0
      lib/pleroma/web/api_spec/operations/admin/report_operation.ex
  6. +1
    -1
      lib/pleroma/web/api_spec/operations/admin/status_operation.ex
  7. +5
    -5
      lib/pleroma/web/router.ex
  8. +0
    -341
      test/web/admin_api/controllers/admin_api_controller_test.exs
  9. +374
    -0
      test/web/admin_api/controllers/report_controller_test.exs

+ 2
- 2
docs/API/admin_api.md View File

@@ -547,7 +547,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret

```json
{
"totalReports" : 1,
"total" : 1,
"reports": [
{
"account": {
@@ -768,7 +768,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
- 400 Bad Request `"Invalid parameters"` when `status` is missing
- On success: `204`, empty response

## `POST /api/pleroma/admin/reports/:report_id/notes/:id`
## `DELETE /api/pleroma/admin/reports/:report_id/notes/:id`

### Delete report note



+ 1
- 0
lib/pleroma/web/activity_pub/utils.ex View File

@@ -740,6 +740,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def get_reports(params, page, page_size) do
params =
params
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Flag")
|> Map.put("skip_preload", true)
|> Map.put("preload_report_notes", true)


+ 0
- 97
lib/pleroma/web/admin_api/controllers/admin_api_controller.ex View File

@@ -7,28 +7,22 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do

import Pleroma.Web.ControllerHelper, only: [json_response: 3]

alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.ConfigDB
alias Pleroma.MFA
alias Pleroma.ModerationLog
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.ReportNote
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.AdminAPI.ConfigView
alias Pleroma.Web.AdminAPI.ModerationLogView
alias Pleroma.Web.AdminAPI.Report
alias Pleroma.Web.AdminAPI.ReportView
alias Pleroma.Web.AdminAPI.Search
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router

@@ -73,18 +67,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do

plug(
OAuthScopesPlug,
%{scopes: ["read:reports"], admin: true}
when action in [:list_reports, :report_show]
)

plug(
OAuthScopesPlug,
%{scopes: ["write:reports"], admin: true}
when action in [:reports_update, :report_notes_create, :report_notes_delete]
)

plug(
OAuthScopesPlug,
%{scopes: ["read:statuses"], admin: true}
when action in [:list_user_statuses, :list_instance_statuses]
)
@@ -645,85 +627,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end

def list_reports(conn, params) do
{page, page_size} = page_params(params)

reports = Utils.get_reports(params, page, page_size)

conn
|> put_view(ReportView)
|> render("index.json", %{reports: reports})
end

def report_show(conn, %{"id" => id}) do
with %Activity{} = report <- Activity.get_by_id(id) do
conn
|> put_view(ReportView)
|> render("show.json", Report.extract_report_info(report))
else
_ -> {:error, :not_found}
end
end

def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
result =
reports
|> Enum.map(fn report ->
with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
ModerationLog.insert_log(%{
action: "report_update",
actor: admin,
subject: activity
})

activity
else
{: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

def report_notes_create(%{assigns: %{user: user}} = conn, %{
"id" => report_id,
"content" => content
}) do
with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
ModerationLog.insert_log(%{
action: "report_note",
actor: user,
subject: Activity.get_by_id(report_id),
text: content
})

json_response(conn, :no_content, "")
else
_ -> json_response(conn, :bad_request, "")
end
end

def report_notes_delete(%{assigns: %{user: user}} = conn, %{
"id" => note_id,
"report_id" => report_id
}) do
with {:ok, note} <- ReportNote.destroy(note_id) do
ModerationLog.insert_log(%{
action: "report_note_delete",
actor: user,
subject: Activity.get_by_id(report_id),
text: note.content
})

json_response(conn, :no_content, "")
else
_ -> json_response(conn, :bad_request, "")
end
end

def list_log(conn, params) do
{page, page_size} = page_params(params)



+ 107
- 0
lib/pleroma/web/admin_api/controllers/report_controller.ex View File

@@ -0,0 +1,107 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.AdminAPI.ReportController do
use Pleroma.Web, :controller

import Pleroma.Web.ControllerHelper, only: [json_response: 3]

alias Pleroma.Activity
alias Pleroma.ModerationLog
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.ReportNote
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.Report
alias Pleroma.Web.CommonAPI

require Logger

plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["read:reports"], admin: true} when action in [:index, :show])

plug(
OAuthScopesPlug,
%{scopes: ["write:reports"], admin: true}
when action in [:update, :notes_create, :notes_delete]
)

action_fallback(AdminAPI.FallbackController)

defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ReportOperation

def index(conn, params) do
reports = Utils.get_reports(params, params.page, params.page_size)

render(conn, "index.json", reports: reports)
end

def show(conn, %{id: id}) do
with %Activity{} = report <- Activity.get_by_id(id) do
render(conn, "show.json", Report.extract_report_info(report))
else
_ -> {:error, :not_found}
end
end

def update(%{assigns: %{user: admin}, body_params: %{reports: reports}} = conn, _) do
result =
Enum.map(reports, fn report ->
case CommonAPI.update_report_state(report.id, report.state) do
{:ok, activity} ->
ModerationLog.insert_log(%{
action: "report_update",
actor: admin,
subject: activity
})

activity

{:error, message} ->
%{id: report.id, error: message}
end
end)

if Enum.any?(result, &Map.has_key?(&1, :error)) do
json_response(conn, :bad_request, result)
else
json_response(conn, :no_content, "")
end
end

def notes_create(%{assigns: %{user: user}, body_params: %{content: content}} = conn, %{
id: report_id
}) do
with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
ModerationLog.insert_log(%{
action: "report_note",
actor: user,
subject: Activity.get_by_id(report_id),
text: content
})

json_response(conn, :no_content, "")
else
_ -> json_response(conn, :bad_request, "")
end
end

def notes_delete(%{assigns: %{user: user}} = conn, %{
id: note_id,
report_id: report_id
}) do
with {:ok, note} <- ReportNote.destroy(note_id) do
ModerationLog.insert_log(%{
action: "report_note_delete",
actor: user,
subject: Activity.get_by_id(report_id),
text: note.content
})

json_response(conn, :no_content, "")
else
_ -> json_response(conn, :bad_request, "")
end
end
end

+ 237
- 0
lib/pleroma/web/api_spec/operations/admin/report_operation.ex View File

@@ -0,0 +1,237 @@
# 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.Admin.ReportOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.Status

import Pleroma.Web.ApiSpec.Helpers

def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end

def index_operation do
%Operation{
tags: ["Admin", "Reports"],
summary: "Get a list of reports",
operationId: "AdminAPI.ReportController.index",
security: [%{"oAuth" => ["read:reports"]}],
parameters: [
Operation.parameter(
:state,
:query,
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()
}
}
}),
403 => Operation.response("Forbidden", "application/json", ApiError)
}
}
end

def show_operation do
%Operation{
tags: ["Admin", "Reports"],
summary: "Get an individual report",
operationId: "AdminAPI.ReportController.show",
parameters: [id_param()],
security: [%{"oAuth" => ["read:reports"]}],
responses: %{
200 => Operation.response("Report", "application/json", report()),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end

def update_operation do
%Operation{
tags: ["Admin", "Reports"],
summary: "Change the state of one or multiple reports",
operationId: "AdminAPI.ReportController.update",
security: [%{"oAuth" => ["write:reports"]}],
requestBody: request_body("Parameters", update_request(), required: true),
responses: %{
204 => no_content_response(),
400 => Operation.response("Bad Request", "application/json", update_400_response()),
403 => Operation.response("Forbidden", "application/json", ApiError)
}
}
end

def notes_create_operation do
%Operation{
tags: ["Admin", "Reports"],
summary: "Create report note",
operationId: "AdminAPI.ReportController.notes_create",
parameters: [id_param()],
requestBody:
request_body("Parameters", %Schema{
type: :object,
properties: %{
content: %Schema{type: :string, description: "The message"}
}
}),
security: [%{"oAuth" => ["write:reports"]}],
responses: %{
204 => no_content_response(),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end

def notes_delete_operation do
%Operation{
tags: ["Admin", "Reports"],
summary: "Delete report note",
operationId: "AdminAPI.ReportController.notes_delete",
parameters: [
Operation.parameter(:report_id, :path, :string, "Report ID"),
Operation.parameter(:id, :path, :string, "Note ID")
],
security: [%{"oAuth" => ["write:reports"]}],
responses: %{
204 => no_content_response(),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end

defp report_state do
%Schema{type: :string, enum: ["open", "closed", "resolved"]}
end

defp id_param do
Operation.parameter(:id, :path, FlakeID, "Report ID",
example: "9umDrYheeY451cQnEe",
required: true
)
end

defp report do
%Schema{
type: :object,
properties: %{
id: FlakeID,
state: report_state(),
account: account_admin(),
actor: account_admin(),
content: %Schema{type: :string},
created_at: %Schema{type: :string, format: :"date-time"},
statuses: %Schema{type: :array, items: Status},
notes: %Schema{
type: :array,
items: %Schema{
type: :object,
properties: %{
id: %Schema{type: :integer},
user_id: FlakeID,
content: %Schema{type: :string},
inserted_at: %Schema{type: :string, format: :"date-time"}
}
}
}
}
}
end

defp account_admin do
%Schema{
title: "Account",
description: "Account view for admins",
type: :object,
properties:
Map.merge(Account.schema().properties, %{
nickname: %Schema{type: :string},
deactivated: %Schema{type: :boolean},
local: %Schema{type: :boolean},
roles: %Schema{
type: :object,
properties: %{
admin: %Schema{type: :boolean},
moderator: %Schema{type: :boolean}
}
},
confirmation_pending: %Schema{type: :boolean}
})
}
end

defp update_request do
%Schema{
type: :object,
required: [:reports],
properties: %{
reports: %Schema{
type: :array,
items: %Schema{
type: :object,
properties: %{
id: %Schema{allOf: [FlakeID], description: "Required, report ID"},
state: %Schema{
type: :string,
description:
"Required, the new state. Valid values are `open`, `closed` and `resolved`"
}
}
},
example: %{
"reports" => [
%{"id" => "123", "state" => "closed"},
%{"id" => "1337", "state" => "resolved"}
]
}
}
}
}
end

defp update_400_response do
%Schema{
type: :array,
items: %Schema{
type: :object,
properties: %{
id: %Schema{allOf: [FlakeID], description: "Report ID"},
error: %Schema{type: :string, description: "Error message"}
}
}
}
end
end

+ 1
- 1
lib/pleroma/web/api_spec/operations/admin/status_operation.ex View File

@@ -123,7 +123,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
}
end

defp admin_account do
def admin_account do
%Schema{
type: :object,
properties: %{


+ 5
- 5
lib/pleroma/web/router.ex View File

@@ -183,11 +183,11 @@ defmodule Pleroma.Web.Router do
patch("/users/confirm_email", AdminAPIController, :confirm_email)
patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email)

get("/reports", AdminAPIController, :list_reports)
get("/reports/:id", AdminAPIController, :report_show)
patch("/reports", AdminAPIController, :reports_update)
post("/reports/:id/notes", AdminAPIController, :report_notes_create)
delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete)
get("/reports", ReportController, :index)
get("/reports/:id", ReportController, :show)
patch("/reports", ReportController, :update)
post("/reports/:id/notes", ReportController, :notes_create)
delete("/reports/:report_id/notes/:id", ReportController, :notes_delete)

get("/statuses/:id", StatusController, :show)
put("/statuses/:id", StatusController, :update)


+ 0
- 341
test/web/admin_api/controllers/admin_api_controller_test.exs View File

@@ -17,7 +17,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
alias Pleroma.MFA
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.ReportNote
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web
@@ -1198,286 +1197,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
end

describe "GET /api/pleroma/admin/reports/:id" do
test "returns report by its id", %{conn: conn} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
account_id: target_user.id,
comment: "I feel offended",
status_ids: [activity.id]
})

response =
conn
|> get("/api/pleroma/admin/reports/#{report_id}")
|> json_response(:ok)

assert response["id"] == report_id
end

test "returns 404 when report id is invalid", %{conn: conn} do
conn = get(conn, "/api/pleroma/admin/reports/test")

assert json_response(conn, :not_found) == %{"error" => "Not found"}
end
end

describe "PATCH /api/pleroma/admin/reports" do
setup do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
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]
})

%{
id: report_id,
second_report_id: second_report_id
}
end

test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])

response =
conn
|> assign(:token, read_token)
|> patch("/api/pleroma/admin/reports", %{
"reports" => [%{"state" => "resolved", "id" => id}]
})
|> json_response(403)

assert response == %{
"error" => "Insufficient permissions: admin:write:reports."
}

conn
|> assign(:token, write_token)
|> patch("/api/pleroma/admin/reports", %{
"reports" => [%{"state" => "resolved", "id" => id}]
})
|> json_response(:no_content)
end

test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
conn
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "resolved", "id" => id}
]
})
|> json_response(:no_content)

activity = Activity.get_by_id(id)
assert activity.data["state"] == "resolved"

log_entry = Repo.one(ModerationLog)

assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated report ##{id} with 'resolved' state"
end

test "closes report", %{conn: conn, id: id, admin: admin} do
conn
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "closed", "id" => id}
]
})
|> json_response(:no_content)

activity = Activity.get_by_id(id)
assert activity.data["state"] == "closed"

log_entry = Repo.one(ModerationLog)

assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated report ##{id} with 'closed' state"
end

test "returns 400 when state is unknown", %{conn: conn, id: id} do
conn =
conn
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "test", "id" => id}
]
})

assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
end

test "returns 404 when report is not exist", %{conn: conn} do
conn =
conn
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "closed", "id" => "test"}
]
})

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

describe "GET /api/pleroma/admin/reports" do
test "returns empty response when no reports created", %{conn: conn} do
response =
conn
|> get("/api/pleroma/admin/reports")
|> json_response(:ok)

assert Enum.empty?(response["reports"])
assert response["total"] == 0
end

test "returns reports", %{conn: conn} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
account_id: target_user.id,
comment: "I feel offended",
status_ids: [activity.id]
})

response =
conn
|> get("/api/pleroma/admin/reports")
|> json_response(:ok)

[report] = response["reports"]

assert length(response["reports"]) == 1
assert report["id"] == report_id

assert response["total"] == 1
end

test "returns reports with specified state", %{conn: conn} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: first_report_id}} =
CommonAPI.report(reporter, %{
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"
})

CommonAPI.update_report_state(second_report_id, "closed")

response =
conn
|> get("/api/pleroma/admin/reports", %{
"state" => "open"
})
|> json_response(:ok)

[open_report] = response["reports"]

assert length(response["reports"]) == 1
assert open_report["id"] == first_report_id

assert response["total"] == 1

response =
conn
|> get("/api/pleroma/admin/reports", %{
"state" => "closed"
})
|> json_response(:ok)

[closed_report] = response["reports"]

assert length(response["reports"]) == 1
assert closed_report["id"] == second_report_id

assert response["total"] == 1

response =
conn
|> get("/api/pleroma/admin/reports", %{
"state" => "resolved"
})
|> json_response(:ok)

assert Enum.empty?(response["reports"])
assert response["total"] == 0
end

test "returns 403 when requested by a non-admin" do
user = insert(:user)
token = insert(:oauth_token, user: user)

conn =
build_conn()
|> assign(:user, user)
|> assign(:token, token)
|> get("/api/pleroma/admin/reports")

assert json_response(conn, :forbidden) ==
%{"error" => "User is not an admin or OAuth admin scope is not granted."}
end

test "returns 403 when requested by anonymous" do
conn = get(build_conn(), "/api/pleroma/admin/reports")

assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
end
end

describe "GET /api/pleroma/admin/config" do
setup do: clear_config(:configurable_from_database, true)

@@ -3195,66 +2914,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
end

describe "POST /reports/:id/notes" do
setup %{conn: conn, admin: admin} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
account_id: target_user.id,
comment: "I feel offended",
status_ids: [activity.id]
})

post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
content: "this is disgusting!"
})

post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
content: "this is disgusting2!"
})

%{
admin_id: admin.id,
report_id: report_id
}
end

test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
[note, _] = Repo.all(ReportNote)

assert %{
activity_id: ^report_id,
content: "this is disgusting!",
user_id: ^admin_id
} = note
end

test "it returns reports with notes", %{conn: conn, admin: admin} do
conn = get(conn, "/api/pleroma/admin/reports")

response = json_response(conn, 200)
notes = hd(response["reports"])["notes"]
[note, _] = notes

assert note["user"]["nickname"] == admin.nickname
assert note["content"] == "this is disgusting!"
assert note["created_at"]
assert response["total"] == 1
end

test "it deletes the note", %{conn: conn, report_id: report_id} do
assert ReportNote |> Repo.all() |> length() == 2

[note, _] = Repo.all(ReportNote)

delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")

assert ReportNote |> Repo.all() |> length() == 1
end
end

describe "GET /api/pleroma/admin/config/descriptions" do
test "structure", %{conn: conn} do
admin = insert(:user, is_admin: true)


+ 374
- 0
test/web/admin_api/controllers/report_controller_test.exs View File

@@ -0,0 +1,374 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
use Pleroma.Web.ConnCase

import Pleroma.Factory

alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.ReportNote
alias Pleroma.Web.CommonAPI

setup do
admin = insert(:user, is_admin: true)
token = insert(:oauth_admin_token, user: admin)

conn =
build_conn()
|> assign(:user, admin)
|> assign(:token, token)

{:ok, %{admin: admin, token: token, conn: conn}}
end

describe "GET /api/pleroma/admin/reports/:id" do
test "returns report by its id", %{conn: conn} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
account_id: target_user.id,
comment: "I feel offended",
status_ids: [activity.id]
})

response =
conn
|> get("/api/pleroma/admin/reports/#{report_id}")
|> json_response_and_validate_schema(:ok)

assert response["id"] == report_id
end

test "returns 404 when report id is invalid", %{conn: conn} do
conn = get(conn, "/api/pleroma/admin/reports/test")

assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"}
end
end

describe "PATCH /api/pleroma/admin/reports" do
setup do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
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]
})

%{
id: report_id,
second_report_id: second_report_id
}
end

test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])

response =
conn
|> assign(:token, read_token)
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [%{"state" => "resolved", "id" => id}]
})
|> json_response_and_validate_schema(403)

assert response == %{
"error" => "Insufficient permissions: admin:write:reports."
}

conn
|> assign(:token, write_token)
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [%{"state" => "resolved", "id" => id}]
})
|> json_response_and_validate_schema(:no_content)
end

test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
conn
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "resolved", "id" => id}
]
})
|> json_response_and_validate_schema(:no_content)

activity = Activity.get_by_id(id)
assert activity.data["state"] == "resolved"

log_entry = Repo.one(ModerationLog)

assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated report ##{id} with 'resolved' state"
end

test "closes report", %{conn: conn, id: id, admin: admin} do
conn
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "closed", "id" => id}
]
})
|> json_response_and_validate_schema(:no_content)

activity = Activity.get_by_id(id)
assert activity.data["state"] == "closed"

log_entry = Repo.one(ModerationLog)

assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated report ##{id} with 'closed' state"
end

test "returns 400 when state is unknown", %{conn: conn, id: id} do
conn =
conn
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "test", "id" => id}
]
})

assert "Unsupported state" =
hd(json_response_and_validate_schema(conn, :bad_request))["error"]
end

test "returns 404 when report is not exist", %{conn: conn} do
conn =
conn
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "closed", "id" => "test"}
]
})

assert hd(json_response_and_validate_schema(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
|> put_req_header("content-type", "application/json")
|> patch("/api/pleroma/admin/reports", %{
"reports" => [
%{"state" => "resolved", "id" => id},
%{"state" => "closed", "id" => second_report_id}
]
})
|> json_response_and_validate_schema(: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

describe "GET /api/pleroma/admin/reports" do
test "returns empty response when no reports created", %{conn: conn} do
response =
conn
|> get("/api/pleroma/admin/reports")
|> json_response_and_validate_schema(:ok)

assert Enum.empty?(response["reports"])
assert response["total"] == 0
end

test "returns reports", %{conn: conn} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
account_id: target_user.id,
comment: "I feel offended",
status_ids: [activity.id]
})

response =
conn
|> get("/api/pleroma/admin/reports")
|> json_response_and_validate_schema(:ok)

[report] = response["reports"]

assert length(response["reports"]) == 1
assert report["id"] == report_id

assert response["total"] == 1
end

test "returns reports with specified state", %{conn: conn} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: first_report_id}} =
CommonAPI.report(reporter, %{
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"
})

CommonAPI.update_report_state(second_report_id, "closed")

response =
conn
|> get("/api/pleroma/admin/reports?state=open")
|> json_response_and_validate_schema(:ok)

assert [open_report] = response["reports"]

assert length(response["reports"]) == 1
assert open_report["id"] == first_report_id

assert response["total"] == 1

response =
conn
|> get("/api/pleroma/admin/reports?state=closed")
|> json_response_and_validate_schema(:ok)

assert [closed_report] = response["reports"]

assert length(response["reports"]) == 1
assert closed_report["id"] == second_report_id

assert response["total"] == 1

assert %{"total" => 0, "reports" => []} ==
conn
|> get("/api/pleroma/admin/reports?state=resolved", %{
"" => ""
})
|> json_response_and_validate_schema(:ok)
end

test "returns 403 when requested by a non-admin" do
user = insert(:user)
token = insert(:oauth_token, user: user)

conn =
build_conn()
|> assign(:user, user)
|> assign(:token, token)
|> get("/api/pleroma/admin/reports")

assert json_response(conn, :forbidden) ==
%{"error" => "User is not an admin or OAuth admin scope is not granted."}
end

test "returns 403 when requested by anonymous" do
conn = get(build_conn(), "/api/pleroma/admin/reports")

assert json_response(conn, :forbidden) == %{
"error" => "Invalid credentials."
}
end
end

describe "POST /api/pleroma/admin/reports/:id/notes" do
setup %{conn: conn, admin: admin} do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

{:ok, %{id: report_id}} =
CommonAPI.report(reporter, %{
account_id: target_user.id,
comment: "I feel offended",
status_ids: [activity.id]
})

conn
|> put_req_header("content-type", "application/json")
|> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
content: "this is disgusting!"
})

conn
|> put_req_header("content-type", "application/json")
|> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
content: "this is disgusting2!"
})

%{
admin_id: admin.id,
report_id: report_id
}
end

test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
assert [note, _] = Repo.all(ReportNote)

assert %{
activity_id: ^report_id,
content: "this is disgusting!",
user_id: ^admin_id
} = note
end

test "it returns reports with notes", %{conn: conn, admin: admin} do
conn = get(conn, "/api/pleroma/admin/reports")

response = json_response_and_validate_schema(conn, 200)
notes = hd(response["reports"])["notes"]
[note, _] = notes

assert note["user"]["nickname"] == admin.nickname
assert note["content"] == "this is disgusting!"
assert note["created_at"]
assert response["total"] == 1
end

test "it deletes the note", %{conn: conn, report_id: report_id} do
assert ReportNote |> Repo.all() |> length() == 2
assert [note, _] = Repo.all(ReportNote)

delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")

assert ReportNote |> Repo.all() |> length() == 1
end
end
end

Loading…
Cancel
Save