Merge branch 'feature/report-notes' into 'develop'
AdminAPI: Add report notes See merge request pleroma/pleroma!2031
This commit is contained in:
commit
2aa609db8a
|
@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- **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: `PUT /api/pleroma/admin/reports/:id` is now `PATCH /api/pleroma/admin/reports`, see admin_api.md for details
|
- **Breaking:** Admin API: `PUT /api/pleroma/admin/reports/:id` is now `PATCH /api/pleroma/admin/reports`, see admin_api.md for details
|
||||||
- **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string.
|
- **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string.
|
||||||
|
- **Breaking** replying to reports is now "report notes", enpoint changed from `POST /api/pleroma/admin/reports/:id/respond` to `POST /api/pleroma/admin/reports/:id/notes`
|
||||||
- Admin API: Return `total` when querying for reports
|
- Admin API: Return `total` when querying for reports
|
||||||
- Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`)
|
- Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`)
|
||||||
- Admin API: Return link alongside with token on password reset
|
- Admin API: Return link alongside with token on password reset
|
||||||
|
|
|
@ -614,78 +614,29 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
||||||
|
|
||||||
- On success: `204`, empty response
|
- On success: `204`, empty response
|
||||||
|
|
||||||
## `POST /api/pleroma/admin/reports/:id/respond`
|
## `POST /api/pleroma/admin/reports/:id/notes`
|
||||||
|
|
||||||
### Respond to a report
|
### Create report note
|
||||||
|
|
||||||
- Params:
|
- Params:
|
||||||
- `id`
|
- `id`: required, report id
|
||||||
- `status`: required, the message
|
- `content`: required, the message
|
||||||
- Response:
|
- Response:
|
||||||
- On failure:
|
- On failure:
|
||||||
- 400 Bad Request `"Invalid parameters"` when `status` is missing
|
- 400 Bad Request `"Invalid parameters"` when `status` is missing
|
||||||
- 403 Forbidden `{"error": "error_msg"}`
|
- On success: `204`, empty response
|
||||||
- 404 Not Found `"Not found"`
|
|
||||||
- On success: JSON, created Mastodon Status entity
|
|
||||||
|
|
||||||
```json
|
## `POST /api/pleroma/admin/reports/:report_id/notes/:id`
|
||||||
{
|
|
||||||
"account": { ... },
|
### Delete report note
|
||||||
"application": {
|
|
||||||
"name": "Web",
|
- Params:
|
||||||
"website": null
|
- `report_id`: required, report id
|
||||||
},
|
- `id`: required, note id
|
||||||
"bookmarked": false,
|
- Response:
|
||||||
"card": null,
|
- On failure:
|
||||||
"content": "Your claim is going to be closed",
|
- 400 Bad Request `"Invalid parameters"` when `status` is missing
|
||||||
"created_at": "2019-05-11T17:13:03.000Z",
|
- On success: `204`, empty response
|
||||||
"emojis": [],
|
|
||||||
"favourited": false,
|
|
||||||
"favourites_count": 0,
|
|
||||||
"id": "9ihuiSL1405I65TmEq",
|
|
||||||
"in_reply_to_account_id": null,
|
|
||||||
"in_reply_to_id": null,
|
|
||||||
"language": null,
|
|
||||||
"media_attachments": [],
|
|
||||||
"mentions": [
|
|
||||||
{
|
|
||||||
"acct": "user",
|
|
||||||
"id": "9i6dAJqSGSKMzLG2Lo",
|
|
||||||
"url": "https://pleroma.example.org/users/user",
|
|
||||||
"username": "user"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"acct": "admin",
|
|
||||||
"id": "9hEkA5JsvAdlSrocam",
|
|
||||||
"url": "https://pleroma.example.org/users/admin",
|
|
||||||
"username": "admin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"muted": false,
|
|
||||||
"pinned": false,
|
|
||||||
"pleroma": {
|
|
||||||
"content": {
|
|
||||||
"text/plain": "Your claim is going to be closed"
|
|
||||||
},
|
|
||||||
"conversation_id": 35,
|
|
||||||
"in_reply_to_account_acct": null,
|
|
||||||
"local": true,
|
|
||||||
"spoiler_text": {
|
|
||||||
"text/plain": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"reblog": null,
|
|
||||||
"reblogged": false,
|
|
||||||
"reblogs_count": 0,
|
|
||||||
"replies_count": 0,
|
|
||||||
"sensitive": false,
|
|
||||||
"spoiler_text": "",
|
|
||||||
"tags": [],
|
|
||||||
"uri": "https://pleroma.example.org/objects/cab0836d-9814-46cd-a0ea-529da9db5fcb",
|
|
||||||
"url": "https://pleroma.example.org/notice/9ihuiSL1405I65TmEq",
|
|
||||||
"visibility": "direct"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `PUT /api/pleroma/admin/statuses/:id`
|
## `PUT /api/pleroma/admin/statuses/:id`
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Activity do
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.ReportNote
|
||||||
alias Pleroma.ThreadMute
|
alias Pleroma.ThreadMute
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ defmodule Pleroma.Activity do
|
||||||
has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id)
|
has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id)
|
||||||
# This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark
|
# This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark
|
||||||
has_one(:bookmark, Bookmark)
|
has_one(:bookmark, Bookmark)
|
||||||
|
# This is a fake relation, do not use outside of with_preloaded_report_notes
|
||||||
|
has_many(:report_notes, ReportNote)
|
||||||
has_many(:notifications, Notification, on_delete: :delete_all)
|
has_many(:notifications, Notification, on_delete: :delete_all)
|
||||||
|
|
||||||
# Attention: this is a fake relation, don't try to preload it blindly and expect it to work!
|
# Attention: this is a fake relation, don't try to preload it blindly and expect it to work!
|
||||||
|
@ -114,6 +117,16 @@ def with_preloaded_bookmark(query, %User{} = user) do
|
||||||
|
|
||||||
def with_preloaded_bookmark(query, _), do: query
|
def with_preloaded_bookmark(query, _), do: query
|
||||||
|
|
||||||
|
def with_preloaded_report_notes(query) do
|
||||||
|
from([a] in query,
|
||||||
|
left_join: r in ReportNote,
|
||||||
|
on: a.id == r.activity_id,
|
||||||
|
preload: [report_notes: r]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_preloaded_report_notes(query, _), do: query
|
||||||
|
|
||||||
def with_set_thread_muted_field(query, %User{} = user) do
|
def with_set_thread_muted_field(query, %User{} = user) do
|
||||||
from([a] in query,
|
from([a] in query,
|
||||||
left_join: tm in ThreadMute,
|
left_join: tm in ThreadMute,
|
||||||
|
|
|
@ -128,17 +128,35 @@ def insert_log(%{
|
||||||
{:ok, ModerationLog} | {:error, any}
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
action: "report_response",
|
action: "report_note",
|
||||||
subject: %Activity{} = subject,
|
subject: %Activity{} = subject,
|
||||||
text: text
|
text: text
|
||||||
}) do
|
}) do
|
||||||
%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
"actor" => user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
"action" => "report_response",
|
"action" => "report_note",
|
||||||
"subject" => report_to_map(subject),
|
"subject" => report_to_map(subject),
|
||||||
"text" => text,
|
"text" => text
|
||||||
"message" => ""
|
}
|
||||||
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
|
def insert_log(%{
|
||||||
|
actor: %User{} = actor,
|
||||||
|
action: "report_note_delete",
|
||||||
|
subject: %Activity{} = subject,
|
||||||
|
text: text
|
||||||
|
}) do
|
||||||
|
%ModerationLog{
|
||||||
|
data: %{
|
||||||
|
"actor" => user_to_map(actor),
|
||||||
|
"action" => "report_note_delete",
|
||||||
|
"subject" => report_to_map(subject),
|
||||||
|
"text" => text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> insert_log_entry_with_message()
|
|> insert_log_entry_with_message()
|
||||||
|
@ -556,12 +574,24 @@ def get_log_entry_message(%ModerationLog{
|
||||||
def get_log_entry_message(%ModerationLog{
|
def get_log_entry_message(%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
"actor" => %{"nickname" => actor_nickname},
|
"actor" => %{"nickname" => actor_nickname},
|
||||||
"action" => "report_response",
|
"action" => "report_note",
|
||||||
"subject" => %{"id" => subject_id, "type" => "report"},
|
"subject" => %{"id" => subject_id, "type" => "report"},
|
||||||
"text" => text
|
"text" => text
|
||||||
}
|
}
|
||||||
}) do
|
}) do
|
||||||
"@#{actor_nickname} responded with '#{text}' to report ##{subject_id}"
|
"@#{actor_nickname} added note '#{text}' to report ##{subject_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_log_entry_message(ModerationLog) :: String.t()
|
||||||
|
def get_log_entry_message(%ModerationLog{
|
||||||
|
data: %{
|
||||||
|
"actor" => %{"nickname" => actor_nickname},
|
||||||
|
"action" => "report_note_delete",
|
||||||
|
"subject" => %{"id" => subject_id, "type" => "report"},
|
||||||
|
"text" => text
|
||||||
|
}
|
||||||
|
}) do
|
||||||
|
"@#{actor_nickname} deleted note '#{text}' from report ##{subject_id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_log_entry_message(ModerationLog) :: String.t()
|
@spec get_log_entry_message(ModerationLog) :: String.t()
|
||||||
|
|
|
@ -38,7 +38,10 @@ def fetch_paginated(query, params, :keyset, table_binding) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_paginated(query, %{"total" => true} = params, :offset, table_binding) do
|
def fetch_paginated(query, %{"total" => true} = params, :offset, table_binding) do
|
||||||
total = Repo.aggregate(query, :count, :id)
|
total =
|
||||||
|
query
|
||||||
|
|> Ecto.Query.exclude(:left_join)
|
||||||
|
|> Repo.aggregate(:count, :id)
|
||||||
|
|
||||||
%{
|
%{
|
||||||
total: total,
|
total: total,
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.ReportNote do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.ReportNote
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{}
|
||||||
|
|
||||||
|
schema "report_notes" do
|
||||||
|
field(:content, :string)
|
||||||
|
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
|
||||||
|
belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType)
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) ::
|
||||||
|
{:ok, ReportNote.t()} | {:error, Changeset.t()}
|
||||||
|
def create(user_id, activity_id, content) do
|
||||||
|
attrs = %{
|
||||||
|
user_id: user_id,
|
||||||
|
activity_id: activity_id,
|
||||||
|
content: content
|
||||||
|
}
|
||||||
|
|
||||||
|
%ReportNote{}
|
||||||
|
|> cast(attrs, [:user_id, :activity_id, :content])
|
||||||
|
|> validate_required([:user_id, :activity_id, :content])
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec destroy(FlakeId.Ecto.CompatType.t()) ::
|
||||||
|
{:ok, ReportNote.t()} | {:error, Changeset.t()}
|
||||||
|
def destroy(id) do
|
||||||
|
from(r in ReportNote, where: r.id == ^id)
|
||||||
|
|> Repo.one()
|
||||||
|
|> Repo.delete()
|
||||||
|
end
|
||||||
|
end
|
|
@ -1068,6 +1068,13 @@ defp maybe_preload_bookmarks(query, opts) do
|
||||||
|> Activity.with_preloaded_bookmark(opts["user"])
|
|> Activity.with_preloaded_bookmark(opts["user"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_preload_report_notes(query, %{"preload_report_notes" => true}) do
|
||||||
|
query
|
||||||
|
|> Activity.with_preloaded_report_notes()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp maybe_preload_report_notes(query, _), do: query
|
||||||
|
|
||||||
defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query
|
defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query
|
||||||
|
|
||||||
defp maybe_set_thread_muted_field(query, opts) do
|
defp maybe_set_thread_muted_field(query, opts) do
|
||||||
|
@ -1121,6 +1128,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
Activity
|
Activity
|
||||||
|> maybe_preload_objects(opts)
|
|> maybe_preload_objects(opts)
|
||||||
|> maybe_preload_bookmarks(opts)
|
|> maybe_preload_bookmarks(opts)
|
||||||
|
|> maybe_preload_report_notes(opts)
|
||||||
|> maybe_set_thread_muted_field(opts)
|
|> maybe_set_thread_muted_field(opts)
|
||||||
|> maybe_order(opts)
|
|> maybe_order(opts)
|
||||||
|> restrict_recipients(recipients, opts["user"])
|
|> restrict_recipients(recipients, opts["user"])
|
||||||
|
|
|
@ -787,6 +787,7 @@ def get_reports(params, page, page_size) do
|
||||||
params
|
params
|
||||||
|> Map.put("type", "Flag")
|
|> Map.put("type", "Flag")
|
||||||
|> Map.put("skip_preload", true)
|
|> Map.put("skip_preload", true)
|
||||||
|
|> Map.put("preload_report_notes", true)
|
||||||
|> Map.put("total", true)
|
|> Map.put("total", true)
|
||||||
|> Map.put("limit", page_size)
|
|> Map.put("limit", page_size)
|
||||||
|> Map.put("offset", (page - 1) * page_size)
|
|> Map.put("offset", (page - 1) * page_size)
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.ModerationLog
|
alias Pleroma.ModerationLog
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
alias Pleroma.ReportNote
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.UserInviteToken
|
alias Pleroma.UserInviteToken
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
@ -643,9 +644,11 @@ def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nic
|
||||||
def list_reports(conn, params) do
|
def list_reports(conn, params) do
|
||||||
{page, page_size} = page_params(params)
|
{page, page_size} = page_params(params)
|
||||||
|
|
||||||
|
reports = Utils.get_reports(params, page, page_size)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(ReportView)
|
|> put_view(ReportView)
|
||||||
|> render("index.json", %{reports: Utils.get_reports(params, page, page_size)})
|
|> render("index.json", %{reports: reports})
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_grouped_reports(conn, _params) do
|
def list_grouped_reports(conn, _params) do
|
||||||
|
@ -689,32 +692,39 @@ def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) d
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
|
def report_notes_create(%{assigns: %{user: user}} = conn, %{
|
||||||
with false <- is_nil(params["status"]),
|
"id" => report_id,
|
||||||
%Activity{} <- Activity.get_by_id(id) do
|
"content" => content
|
||||||
params =
|
}) do
|
||||||
params
|
with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
|
||||||
|> Map.put("in_reply_to_status_id", id)
|
|
||||||
|> Map.put("visibility", "direct")
|
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, params)
|
|
||||||
|
|
||||||
ModerationLog.insert_log(%{
|
ModerationLog.insert_log(%{
|
||||||
action: "report_response",
|
action: "report_note",
|
||||||
actor: user,
|
actor: user,
|
||||||
subject: activity,
|
subject: Activity.get_by_id(report_id),
|
||||||
text: params["status"]
|
text: content
|
||||||
})
|
})
|
||||||
|
|
||||||
conn
|
json_response(conn, :no_content, "")
|
||||||
|> put_view(StatusView)
|
|
||||||
|> render("show.json", %{activity: activity})
|
|
||||||
else
|
else
|
||||||
true ->
|
_ -> json_response(conn, :bad_request, "")
|
||||||
{:param_cast, nil}
|
end
|
||||||
|
end
|
||||||
|
|
||||||
nil ->
|
def report_notes_delete(%{assigns: %{user: user}} = conn, %{
|
||||||
{:error, :not_found}
|
"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
|
end
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,8 @@ def render("show.json", %{report: report, user: user, account: account, statuses
|
||||||
content: content,
|
content: content,
|
||||||
created_at: created_at,
|
created_at: created_at,
|
||||||
statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
|
statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
|
||||||
state: report.data["state"]
|
state: report.data["state"],
|
||||||
|
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,6 +70,28 @@ def render("index_grouped.json", %{groups: groups}) do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render("index_notes.json", %{notes: notes}) when is_list(notes) do
|
||||||
|
Enum.map(notes, &render(__MODULE__, "show_note.json", &1))
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("index_notes.json", _), do: []
|
||||||
|
|
||||||
|
def render("show_note.json", %{
|
||||||
|
id: id,
|
||||||
|
content: content,
|
||||||
|
user_id: user_id,
|
||||||
|
inserted_at: inserted_at
|
||||||
|
}) do
|
||||||
|
user = User.get_by_id(user_id)
|
||||||
|
|
||||||
|
%{
|
||||||
|
id: id,
|
||||||
|
content: content,
|
||||||
|
user: merge_account_views(user),
|
||||||
|
created_at: Utils.to_masto_date(inserted_at)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
defp merge_account_views(%User{} = user) do
|
defp merge_account_views(%User{} = user) do
|
||||||
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|
||||||
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
|
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
|
||||||
|
|
|
@ -187,7 +187,8 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/grouped_reports", AdminAPIController, :list_grouped_reports)
|
get("/grouped_reports", AdminAPIController, :list_grouped_reports)
|
||||||
get("/reports/:id", AdminAPIController, :report_show)
|
get("/reports/:id", AdminAPIController, :report_show)
|
||||||
patch("/reports", AdminAPIController, :reports_update)
|
patch("/reports", AdminAPIController, :reports_update)
|
||||||
post("/reports/:id/respond", AdminAPIController, :report_respond)
|
post("/reports/:id/notes", AdminAPIController, :report_notes_create)
|
||||||
|
delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete)
|
||||||
|
|
||||||
put("/statuses/:id", AdminAPIController, :status_update)
|
put("/statuses/:id", AdminAPIController, :status_update)
|
||||||
delete("/statuses/:id", AdminAPIController, :status_delete)
|
delete("/statuses/:id", AdminAPIController, :status_delete)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.CreateReportNotes do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create_if_not_exists table(:report_notes) do
|
||||||
|
add(:user_id, references(:users, type: :uuid))
|
||||||
|
add(:activity_id, references(:activities, type: :uuid))
|
||||||
|
add(:content, :string)
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -214,7 +214,7 @@ test "logging report response", %{moderator: moderator} do
|
||||||
{:ok, _} =
|
{:ok, _} =
|
||||||
ModerationLog.insert_log(%{
|
ModerationLog.insert_log(%{
|
||||||
actor: moderator,
|
actor: moderator,
|
||||||
action: "report_response",
|
action: "report_note",
|
||||||
subject: report,
|
subject: report,
|
||||||
text: "look at this"
|
text: "look at this"
|
||||||
})
|
})
|
||||||
|
@ -222,7 +222,7 @@ test "logging report response", %{moderator: moderator} do
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert log.data["message"] ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} responded with 'look at this' to report ##{report.id}"
|
"@#{moderator.nickname} added note 'look at this' to report ##{report.id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logging status sensitivity update", %{moderator: moderator} do
|
test "logging status sensitivity update", %{moderator: moderator} do
|
||||||
|
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
alias Pleroma.ModerationLog
|
alias Pleroma.ModerationLog
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.ReportNote
|
||||||
alias Pleroma.Tests.ObanHelpers
|
alias Pleroma.Tests.ObanHelpers
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.UserInviteToken
|
alias Pleroma.UserInviteToken
|
||||||
|
@ -1831,61 +1832,6 @@ test "account not empty if status was deleted", %{
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /api/pleroma/admin/reports/:id/respond" do
|
|
||||||
setup %{conn: conn} do
|
|
||||||
admin = insert(:user, is_admin: true)
|
|
||||||
|
|
||||||
%{conn: assign(conn, :user, admin), admin: admin}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns created dm", %{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]
|
|
||||||
})
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/api/pleroma/admin/reports/#{report_id}/respond", %{
|
|
||||||
"status" => "I will check it out"
|
|
||||||
})
|
|
||||||
|> json_response(:ok)
|
|
||||||
|
|
||||||
recipients = Enum.map(response["mentions"], & &1["username"])
|
|
||||||
|
|
||||||
assert reporter.nickname in recipients
|
|
||||||
assert response["content"] == "I will check it out"
|
|
||||||
assert response["visibility"] == "direct"
|
|
||||||
|
|
||||||
log_entry = Repo.one(ModerationLog)
|
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log_entry) ==
|
|
||||||
"@#{admin.nickname} responded with 'I will check it out' to report ##{
|
|
||||||
response["id"]
|
|
||||||
}"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns 400 when status is missing", %{conn: conn} do
|
|
||||||
conn = post(conn, "/api/pleroma/admin/reports/test/respond")
|
|
||||||
|
|
||||||
assert json_response(conn, :bad_request) == "Invalid parameters"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns 404 when report id is invalid", %{conn: conn} do
|
|
||||||
conn =
|
|
||||||
post(conn, "/api/pleroma/admin/reports/test/respond", %{
|
|
||||||
"status" => "foo"
|
|
||||||
})
|
|
||||||
|
|
||||||
assert json_response(conn, :not_found) == "Not found"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "PUT /api/pleroma/admin/statuses/:id" do
|
describe "PUT /api/pleroma/admin/statuses/:id" do
|
||||||
setup %{conn: conn} do
|
setup %{conn: conn} do
|
||||||
admin = insert(:user, is_admin: true)
|
admin = insert(:user, is_admin: true)
|
||||||
|
@ -3082,6 +3028,77 @@ test "it resend emails for two users", %{admin: admin} do
|
||||||
}"
|
}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "POST /reports/:id/notes" do
|
||||||
|
setup do
|
||||||
|
admin = insert(:user, is_admin: true)
|
||||||
|
[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]
|
||||||
|
})
|
||||||
|
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
|
||||||
|
content: "this is disgusting!"
|
||||||
|
})
|
||||||
|
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
|
||||||
|
content: "this is disgusting2!"
|
||||||
|
})
|
||||||
|
|
||||||
|
%{
|
||||||
|
admin_id: admin.id,
|
||||||
|
report_id: report_id,
|
||||||
|
admin: admin
|
||||||
|
}
|
||||||
|
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", %{admin: admin} do
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> get("/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", %{admin: admin, report_id: report_id} do
|
||||||
|
assert ReportNote |> Repo.all() |> length() == 2
|
||||||
|
|
||||||
|
[note, _] = Repo.all(ReportNote)
|
||||||
|
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> delete("/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
|
||||||
|
|
||||||
|
assert ReportNote |> Repo.all() |> length() == 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Needed for testing
|
# Needed for testing
|
||||||
|
|
|
@ -30,6 +30,7 @@ test "renders a report" do
|
||||||
Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
|
Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
|
||||||
),
|
),
|
||||||
statuses: [],
|
statuses: [],
|
||||||
|
notes: [],
|
||||||
state: "open",
|
state: "open",
|
||||||
id: activity.id
|
id: activity.id
|
||||||
}
|
}
|
||||||
|
@ -65,6 +66,7 @@ test "includes reported statuses" do
|
||||||
),
|
),
|
||||||
statuses: [StatusView.render("show.json", %{activity: activity})],
|
statuses: [StatusView.render("show.json", %{activity: activity})],
|
||||||
state: "open",
|
state: "open",
|
||||||
|
notes: [],
|
||||||
id: report_activity.id
|
id: report_activity.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue