diff options
| author | Maxim Filippov <colixer@gmail.com> | 2019-12-03 23:54:07 +0900 | 
|---|---|---|
| committer | Maxim Filippov <colixer@gmail.com> | 2019-12-04 00:26:37 +0900 | 
| commit | 4b60d41db9d10e971ee91202389991da294c72de (patch) | |
| tree | c5923b3f14d7a630ea4babb51925b8e0f692ee9b | |
| parent | d468cba2d56f60a41b0372a381b1017a8d2d046b (diff) | |
| download | pleroma-4b60d41db9d10e971ee91202389991da294c72de.tar.gz pleroma-4b60d41db9d10e971ee91202389991da294c72de.zip | |
Add report notes
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | docs/API/admin_api.md | 69 | ||||
| -rw-r--r-- | lib/pleroma/activity.ex | 13 | ||||
| -rw-r--r-- | lib/pleroma/report_note.ex | 46 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/admin_api/admin_api_controller.ex | 34 | ||||
| -rw-r--r-- | lib/pleroma/web/admin_api/views/report_view.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 2 | ||||
| -rw-r--r-- | priv/repo/migrations/20191203043610_create_report_notes.exs | 13 | ||||
| -rw-r--r-- | test/web/admin_api/admin_api_controller_test.exs | 104 | ||||
| -rw-r--r-- | test/web/admin_api/views/report_view_test.exs | 2 | 
12 files changed, 168 insertions, 143 deletions
| diff --git a/CHANGELOG.md b/CHANGELOG.md index e44c892ab..a62222cda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,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: `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** 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  - 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 diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md index 2cac317de..e51fad2cb 100644 --- a/docs/API/admin_api.md +++ b/docs/API/admin_api.md @@ -607,78 +607,17 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret    - On success: `204`, empty response -## `POST /api/pleroma/admin/reports/:id/respond` +## `POST /api/pleroma/admin/reports/:id/notes` -### Respond to a report +### Create a report note  - Params:    - `id` -  - `status`: required, the message +  - `content`: required, the message  - Response:    - On failure:      - 400 Bad Request `"Invalid parameters"` when `status` is missing -    - 403 Forbidden `{"error": "error_msg"}` -    - 404 Not Found `"Not found"` -  - On success: JSON, created Mastodon Status entity - -```json -{ -  "account": { ... }, -  "application": { -    "name": "Web", -    "website": null -  }, -  "bookmarked": false, -  "card": null, -  "content": "Your claim is going to be closed", -  "created_at": "2019-05-11T17:13:03.000Z", -  "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" -} -``` +  - On success: `204`, empty response  ## `PUT /api/pleroma/admin/statuses/:id` diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index cd7a5aae9..37b2c041e 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Activity do    alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.Repo +  alias Pleroma.ReportNote    alias Pleroma.ThreadMute    alias Pleroma.User @@ -47,6 +48,8 @@ defmodule Pleroma.Activity do      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      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)      # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! @@ -113,6 +116,16 @@ defmodule Pleroma.Activity do    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      from([a] in query,        left_join: tm in ThreadMute, diff --git a/lib/pleroma/report_note.ex b/lib/pleroma/report_note.ex new file mode 100644 index 000000000..91102696b --- /dev/null +++ b/lib/pleroma/report_note.ex @@ -0,0 +1,46 @@ +# 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 + +  def get_all_for_status(status_id) do +    ReportNote +    |> where(activity_id: ^status_id) +    |> Repo.all() +  end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f32d04175..5c6cdfcf1 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1018,6 +1018,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> Activity.with_preloaded_bookmark(opts["user"])    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, opts) do @@ -1045,6 +1052,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      Activity      |> maybe_preload_objects(opts)      |> maybe_preload_bookmarks(opts) +    |> maybe_preload_report_notes(opts)      |> maybe_set_thread_muted_field(opts)      |> maybe_order(opts)      |> restrict_recipients(recipients, opts["user"]) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 01aacbde3..079d458ba 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -781,6 +781,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do        params        |> Map.put("type", "Flag")        |> Map.put("skip_preload", true) +      |> Map.put("preload_report_notes", true)        |> Map.put("total", true)        |> Map.put("limit", page_size)        |> Map.put("offset", (page - 1) * page_size) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 24fdc3c82..ee32bac45 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do    alias Pleroma.Activity    alias Pleroma.ModerationLog    alias Pleroma.Plugs.OAuthScopesPlug +  alias Pleroma.ReportNote    alias Pleroma.User    alias Pleroma.UserInviteToken    alias Pleroma.Web.ActivityPub.ActivityPub @@ -641,9 +642,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do    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: Utils.get_reports(params, page, page_size)}) +    |> render("index.json", %{reports: reports})    end    def list_grouped_reports(conn, _params) do @@ -687,32 +690,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do      end    end -  def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do -    with false <- is_nil(params["status"]), -         %Activity{} <- Activity.get_by_id(id) do -      params = -        params -        |> Map.put("in_reply_to_status_id", id) -        |> Map.put("visibility", "direct") - -      {:ok, activity} = CommonAPI.post(user, params) - +  def report_notes_create(%{assigns: %{user: user}} = conn, %{ +        "id" => status_id, +        "content" => content +      }) do +    with {:ok, _} <- ReportNote.create(user.id, status_id, content) do        ModerationLog.insert_log(%{          action: "report_response",          actor: user, -        subject: activity, -        text: params["status"] +        subject: Activity.get_by_id(status_id), +        text: content        }) -      conn -      |> put_view(StatusView) -      |> render("show.json", %{activity: activity}) +      json_response(conn, :no_content, "")      else -      true -> -        {:param_cast, nil} - -      nil -> -        {:error, :not_found} +      _ -> json_response(conn, :bad_request, "")      end    end diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index ca88595c7..80ca62691 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -38,7 +38,8 @@ defmodule Pleroma.Web.AdminAPI.ReportView do        content: content,        created_at: created_at,        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 @@ -62,6 +63,21 @@ defmodule Pleroma.Web.AdminAPI.ReportView do      }    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", %{content: content, user_id: user_id}) do +    user = User.get_by_id(user_id) + +    %{ +      content: content, +      user: merge_account_views(user) +    } +  end +    defp merge_account_views(%User{} = user) do      Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})      |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e6c4f6f14..af220a98b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -187,7 +187,7 @@ defmodule Pleroma.Web.Router do      get("/grouped_reports", AdminAPIController, :list_grouped_reports)      get("/reports/:id", AdminAPIController, :report_show)      patch("/reports", AdminAPIController, :reports_update) -    post("/reports/:id/respond", AdminAPIController, :report_respond) +    post("/reports/:id/notes", AdminAPIController, :report_notes_create)      put("/statuses/:id", AdminAPIController, :status_update)      delete("/statuses/:id", AdminAPIController, :status_delete) diff --git a/priv/repo/migrations/20191203043610_create_report_notes.exs b/priv/repo/migrations/20191203043610_create_report_notes.exs new file mode 100644 index 000000000..a4f8c096d --- /dev/null +++ b/priv/repo/migrations/20191203043610_create_report_notes.exs @@ -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 diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 32577afee..44557ea45 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1710,61 +1710,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      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      setup %{conn: conn} do        admin = insert(:user, is_admin: true) @@ -2961,6 +2906,55 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 }"      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!" +      }) + +      %{ +        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 +      assert %{ +               activity_id: ^report_id, +               content: "this is disgusting!", +               user_id: ^admin_id +             } = Repo.one(Pleroma.ReportNote) +    end + +    test "it returns reports with notes", %{admin: admin} do +      conn = +        build_conn() +        |> assign(:user, admin) +        |> get("/api/pleroma/admin/reports") + +      reponse = json_response(conn, 200) +      notes = hd(reponse["reports"])["notes"] +      [note] = notes + +      assert note["user"]["nickname"] == admin.nickname +      assert note["content"] == "this is disgusting!" +    end +  end  end  # Needed for testing diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs index ef4a806e4..a0c6eab3c 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/web/admin_api/views/report_view_test.exs @@ -30,6 +30,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do            Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})          ),        statuses: [], +      notes: [],        state: "open",        id: activity.id      } @@ -65,6 +66,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do          ),        statuses: [StatusView.render("show.json", %{activity: activity})],        state: "open", +      notes: [],        id: report_activity.id      } | 
