Merge branch 'develop' into feature/report-notes
authorMaxim Filippov <colixer@gmail.com>
Wed, 11 Dec 2019 23:16:23 +0000 (02:16 +0300)
committerMaxim Filippov <colixer@gmail.com>
Wed, 11 Dec 2019 23:16:23 +0000 (02:16 +0300)
15 files changed:
CHANGELOG.md
docs/API/admin_api.md
lib/pleroma/activity.ex
lib/pleroma/moderation_log.ex
lib/pleroma/pagination.ex
lib/pleroma/report_note.ex [new file with mode: 0644]
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/admin_api/views/report_view.ex
lib/pleroma/web/router.ex
priv/repo/migrations/20191203043610_create_report_notes.exs [new file with mode: 0644]
test/moderation_log_test.exs
test/web/admin_api/admin_api_controller_test.exs
test/web/admin_api/views/report_view_test.exs

index 21374254513f557c8931108dba67f05704e2535e..37b8b0be7d1d8c1217332a981e7d000ce16ce5fd 100644 (file)
@@ -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: `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
index b19793150226d8ad0d06013d4b9bac78655cde44..d98a78af025c10c31216eea87fb04a0501d0005b 100644 (file)
@@ -614,78 +614,29 @@ 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 report note
 
 - Params:
-  - `id`
-  - `status`: required, the message
+  - `id`: required, report id
+  - `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
+  - On success: `204`, empty response
 
-```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"
-}
-```
+## `POST /api/pleroma/admin/reports/:report_id/notes/:id`
+
+### Delete report note
+
+- Params:
+  - `report_id`: required, report id
+  - `id`: required, note id
+- Response:
+  - On failure:
+    - 400 Bad Request `"Invalid parameters"` when `status` is missing
+  - On success: `204`, empty response
 
 ## `PUT /api/pleroma/admin/statuses/:id`
 
index 480b261cfdae0e2615e612b675d3022aaef43d7e..510d3273c1bb9c9244701498145de730530eef1e 100644 (file)
@@ -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
 
@@ -48,6 +49,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!
@@ -114,6 +117,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,
index 706f089dc044f02c07d10ac2b621db30629bbf81..c81477f481e1737b260f04435f5415599ae0695b 100644 (file)
@@ -128,17 +128,35 @@ defmodule Pleroma.ModerationLog do
           {:ok, ModerationLog} | {:error, any}
   def insert_log(%{
         actor: %User{} = actor,
-        action: "report_response",
+        action: "report_note",
         subject: %Activity{} = subject,
         text: text
       }) do
     %ModerationLog{
       data: %{
         "actor" => user_to_map(actor),
-        "action" => "report_response",
+        "action" => "report_note",
         "subject" => report_to_map(subject),
-        "text" => text,
-        "message" => ""
+        "text" => text
+      }
+    }
+    |> 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()
@@ -556,12 +574,24 @@ defmodule Pleroma.ModerationLog do
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
-          "action" => "report_response",
+          "action" => "report_note",
+          "subject" => %{"id" => subject_id, "type" => "report"},
+          "text" => text
+        }
+      }) do
+    "@#{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} responded with '#{text}' to report ##{subject_id}"
+    "@#{actor_nickname} deleted note '#{text}' from report ##{subject_id}"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
index 6321c26007582d47c539297921ce5505e2a12a90..4535ca7c5c2b65d3d68b9acf469996ccfec8da51 100644 (file)
@@ -38,7 +38,10 @@ defmodule Pleroma.Pagination do
   end
 
   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,
diff --git a/lib/pleroma/report_note.ex b/lib/pleroma/report_note.ex
new file mode 100644 (file)
index 0000000..0db86d1
--- /dev/null
@@ -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
index a579dae5762f5c773632a7f098b48b88836d33fb..16e6b00572257d5c7615c707388e4bd63fe97f4e 100644 (file)
@@ -1068,6 +1068,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
@@ -1121,6 +1128,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"])
index 2ca805c091ab25c9340e05782750844b1ff6d711..e87d09134508ad2ad8a0bc9d94b24a5e565dcb8e 100644 (file)
@@ -787,6 +787,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)
index 0a8a56cd8950b80faff6e88ba4ba54eaf93df99e..7c783f91924d87011712413f1c1d0df90df39189 100644 (file)
@@ -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
@@ -643,9 +644,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
@@ -689,32 +692,39 @@ 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")
+  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
+      })
 
-      {:ok, activity} = CommonAPI.post(user, params)
+      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_response",
+        action: "report_note_delete",
         actor: user,
-        subject: activity,
-        text: params["status"]
+        subject: Activity.get_by_id(report_id),
+        text: note.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
 
index 13602efd9f4d9612b6f6787f3226e8f77c63a5a1..4880d29920fcf51f8037a986a3d685921fb51d57 100644 (file)
@@ -39,7 +39,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
 
@@ -69,6 +70,28 @@ 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", %{
+        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
     Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
     |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
index 78cb703a99a444a43b2daec6bd9ed66e72aef60e..f6c1282832b23de5d5d565a931d950ffbdebd342 100644 (file)
@@ -187,7 +187,8 @@ 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)
+    delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete)
 
     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 (file)
index 0000000..a4f8c09
--- /dev/null
@@ -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
index 4240f6a654b55b8eef529269b1757cb24867c202..f2168b73527b34860c2e57cc3bcc31d9ae3b39e3 100644 (file)
@@ -214,7 +214,7 @@ defmodule Pleroma.ModerationLogTest do
       {:ok, _} =
         ModerationLog.insert_log(%{
           actor: moderator,
-          action: "report_response",
+          action: "report_note",
           subject: report,
           text: "look at this"
         })
@@ -222,7 +222,7 @@ defmodule Pleroma.ModerationLogTest do
       log = Repo.one(ModerationLog)
 
       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
 
     test "logging status sensitivity update", %{moderator: moderator} do
index 23ca7f110d1d41c400e13d0708e55407ca6dea26..49ff005b66fe2002f012e4f955c81129a47e93bc 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   alias Pleroma.HTML
   alias Pleroma.ModerationLog
   alias Pleroma.Repo
+  alias Pleroma.ReportNote
   alias Pleroma.Tests.ObanHelpers
   alias Pleroma.User
   alias Pleroma.UserInviteToken
@@ -1831,61 +1832,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)
@@ -3082,6 +3028,77 @@ 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!"
+      })
+
+      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
 
 # Needed for testing
index ef4a806e4300fdc8300a82323fedecb9a47a2985..a0c6eab3c546f395af031c611780e5f0ba6f45e0 100644 (file)
@@ -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
     }