Merge branch 'develop' into openapi/admin/relay
This commit is contained in:
commit
70f054b083
13 changed files with 806 additions and 462 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -7,29 +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.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.MastodonAPI
|
||||
alias Pleroma.Web.Router
|
||||
|
||||
require Logger
|
||||
|
|
@ -71,18 +64,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
when action in [:user_follow, :user_unfollow]
|
||||
)
|
||||
|
||||
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}
|
||||
|
|
@ -277,7 +258,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
})
|
||||
|
||||
conn
|
||||
|> put_view(MastodonAPI.StatusView)
|
||||
|> put_view(AdminAPI.StatusView)
|
||||
|> render("index.json", %{activities: activities, as: :activity})
|
||||
else
|
||||
_ -> {:error, :not_found}
|
||||
|
|
@ -600,85 +581,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
lib/pleroma/web/admin_api/controllers/report_controller.ex
Normal file
107
lib/pleroma/web/admin_api/controllers/report_controller.ex
Normal 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
|
||||
|
|
@ -41,9 +41,7 @@ defmodule Pleroma.Web.AdminAPI.StatusController do
|
|||
|
||||
def show(conn, %{id: id}) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id) do
|
||||
conn
|
||||
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
||||
|> render("show.json", %{activity: activity})
|
||||
render(conn, "show.json", %{activity: activity})
|
||||
else
|
||||
nil -> {:error, :not_found}
|
||||
end
|
||||
|
|
|
|||
237
lib/pleroma/web/api_spec/operations/admin/report_operation.ex
Normal file
237
lib/pleroma/web/api_spec/operations/admin/report_operation.ex
Normal 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
|
||||
|
|
@ -74,7 +74,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
|
|||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Status", "application/json", Status),
|
||||
200 => Operation.response("Status", "application/json", status()),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
|
|||
}
|
||||
end
|
||||
|
||||
defp admin_account do
|
||||
def admin_account do
|
||||
%Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
|
|
|
|||
|
|
@ -113,22 +113,44 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
|
|||
query
|
||||
|> prepare_tags()
|
||||
|> Enum.map(fn tag ->
|
||||
tag = String.trim_leading(tag, "#")
|
||||
%{name: tag, url: tags_path <> tag}
|
||||
end)
|
||||
end
|
||||
|
||||
defp resource_search(:v1, "hashtags", query, _options) do
|
||||
query
|
||||
|> prepare_tags()
|
||||
|> Enum.map(fn tag -> String.trim_leading(tag, "#") end)
|
||||
prepare_tags(query)
|
||||
end
|
||||
|
||||
defp prepare_tags(query) do
|
||||
query
|
||||
|> String.split()
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
|
||||
defp prepare_tags(query, add_joined_tag \\ true) do
|
||||
tags =
|
||||
query
|
||||
|> String.split(~r/[^#\w]+/u, trim: true)
|
||||
|> Enum.uniq_by(&String.downcase/1)
|
||||
|
||||
explicit_tags = Enum.filter(tags, fn tag -> String.starts_with?(tag, "#") end)
|
||||
|
||||
tags =
|
||||
if Enum.any?(explicit_tags) do
|
||||
explicit_tags
|
||||
else
|
||||
tags
|
||||
end
|
||||
|
||||
tags = Enum.map(tags, fn tag -> String.trim_leading(tag, "#") end)
|
||||
|
||||
if Enum.empty?(explicit_tags) && add_joined_tag do
|
||||
tags
|
||||
|> Kernel.++([joined_tag(tags)])
|
||||
|> Enum.uniq_by(&String.downcase/1)
|
||||
else
|
||||
tags
|
||||
end
|
||||
end
|
||||
|
||||
defp joined_tag(tags) do
|
||||
tags
|
||||
|> Enum.map(fn tag -> String.capitalize(tag) end)
|
||||
|> Enum.join()
|
||||
end
|
||||
|
||||
defp with_fallback(f, fallback \\ []) do
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue