From 66f411fba0ecb350a2cd80293aabdecf402abaf9 Mon Sep 17 00:00:00 2001
From: Maksim Pechnikov <parallel588@gmail.com>
Date: Thu, 19 Nov 2020 22:13:45 +0300
Subject: [PATCH 1/2] added subject actor to moderation log

---
 lib/pleroma/activity.ex                       |  13 ++
 lib/pleroma/moderation_log.ex                 | 122 +++++++++++-------
 .../controllers/report_controller.ex          |  17 ++-
 test/pleroma/activity_test.exs                |   7 +
 test/pleroma/moderation_log_test.exs          |  33 +++--
 .../controllers/report_controller_test.exs    |  18 +--
 .../views/moderation_log_view_test.exs        |  98 ++++++++++++++
 7 files changed, 240 insertions(+), 68 deletions(-)
 create mode 100644 test/pleroma/web/admin_api/views/moderation_log_view_test.exs

diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 553834da0..d2066f7a0 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -194,6 +194,19 @@ defmodule Pleroma.Activity do
     end
   end
 
+  def get_by_id_with_user_actor(id) do
+    case FlakeId.flake_id?(id) do
+      true ->
+        Activity
+        |> where([a], a.id == ^id)
+        |> with_preloaded_user_actor()
+        |> Repo.one()
+
+      _ ->
+        nil
+    end
+  end
+
   def get_by_id_with_object(id) do
     Activity
     |> where(id: ^id)
diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex
index 142dd8e0a..0a701127f 100644
--- a/lib/pleroma/moderation_log.ex
+++ b/lib/pleroma/moderation_log.ex
@@ -112,16 +112,19 @@ defmodule Pleroma.ModerationLog do
 
   @spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
           {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        action: "report_update",
-        subject: %Activity{data: %{"type" => "Flag"}} = subject
-      }) do
+  def insert_log(
+        %{
+          actor: %User{} = actor,
+          action: "report_update",
+          subject: %Activity{data: %{"type" => "Flag"}} = subject
+        } = attrs
+      ) do
     %ModerationLog{
       data: %{
         "actor" => user_to_map(actor),
         "action" => "report_update",
         "subject" => report_to_map(subject),
+        "subject_actor" => user_to_map(attrs[:subject_actor]),
         "message" => ""
       }
     }
@@ -130,17 +133,20 @@ defmodule Pleroma.ModerationLog do
 
   @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",
-        subject: %Activity{} = subject,
-        text: text
-      }) do
+  def insert_log(
+        %{
+          actor: %User{} = actor,
+          action: "report_note",
+          subject: %Activity{} = subject,
+          text: text
+        } = attrs
+      ) do
     %ModerationLog{
       data: %{
         "actor" => user_to_map(actor),
         "action" => "report_note",
         "subject" => report_to_map(subject),
+        "subject_actor" => user_to_map(attrs[:subject_actor]),
         "text" => text
       }
     }
@@ -149,17 +155,20 @@ defmodule Pleroma.ModerationLog do
 
   @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
+  def insert_log(
+        %{
+          actor: %User{} = actor,
+          action: "report_note_delete",
+          subject: %Activity{} = subject,
+          text: text
+        } = attrs
+      ) do
     %ModerationLog{
       data: %{
         "actor" => user_to_map(actor),
         "action" => "report_note_delete",
         "subject" => report_to_map(subject),
+        "subject_actor" => user_to_map(attrs[:subject_actor]),
         "text" => text
       }
     }
@@ -345,17 +354,18 @@ defmodule Pleroma.ModerationLog do
   end
 
   defp user_to_map(users) when is_list(users) do
-    users |> Enum.map(&user_to_map/1)
+    Enum.map(users, &user_to_map/1)
   end
 
   defp user_to_map(%User{} = user) do
     user
-    |> Map.from_struct()
     |> Map.take([:id, :nickname])
     |> Map.new(fn {k, v} -> {Atom.to_string(k), v} end)
     |> Map.put("type", "user")
   end
 
+  defp user_to_map(_), do: nil
+
   defp report_to_map(%Activity{} = report) do
     %{
       "type" => "report",
@@ -512,38 +522,48 @@ defmodule Pleroma.ModerationLog do
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
-  def get_log_entry_message(%ModerationLog{
-        data: %{
-          "actor" => %{"nickname" => actor_nickname},
-          "action" => "report_update",
-          "subject" => %{"id" => subject_id, "state" => state, "type" => "report"}
-        }
-      }) do
-    "@#{actor_nickname} updated report ##{subject_id} with '#{state}' state"
+  def get_log_entry_message(
+        %ModerationLog{
+          data: %{
+            "actor" => %{"nickname" => actor_nickname},
+            "action" => "report_update",
+            "subject" => %{"id" => subject_id, "state" => state, "type" => "report"}
+          }
+        } = log
+      ) do
+    "@#{actor_nickname} updated report ##{subject_id}" <>
+      subject_actor_nickname(log, " (on user ", ")") <>
+      " with '#{state}' state"
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
-  def get_log_entry_message(%ModerationLog{
-        data: %{
-          "actor" => %{"nickname" => actor_nickname},
-          "action" => "report_note",
-          "subject" => %{"id" => subject_id, "type" => "report"},
-          "text" => text
-        }
-      }) do
-    "@#{actor_nickname} added note '#{text}' to report ##{subject_id}"
+  def get_log_entry_message(
+        %ModerationLog{
+          data: %{
+            "actor" => %{"nickname" => actor_nickname},
+            "action" => "report_note",
+            "subject" => %{"id" => subject_id, "type" => "report"},
+            "text" => text
+          }
+        } = log
+      ) do
+    "@#{actor_nickname} added note '#{text}' to report ##{subject_id}" <>
+      subject_actor_nickname(log, " on user ")
   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}"
+  def get_log_entry_message(
+        %ModerationLog{
+          data: %{
+            "actor" => %{"nickname" => actor_nickname},
+            "action" => "report_note_delete",
+            "subject" => %{"id" => subject_id, "type" => "report"},
+            "text" => text
+          }
+        } = log
+      ) do
+    "@#{actor_nickname} deleted note '#{text}' from report ##{subject_id}" <>
+      subject_actor_nickname(log, " on user ")
   end
 
   @spec get_log_entry_message(ModerationLog) :: String.t()
@@ -676,4 +696,16 @@ defmodule Pleroma.ModerationLog do
     |> Enum.map(&"@#{&1["nickname"]}")
     |> Enum.join(", ")
   end
+
+  defp subject_actor_nickname(%ModerationLog{data: data}, prefix_msg, postfix_msg \\ "") do
+    case data do
+      %{"subject_actor" => %{"nickname" => subject_actor}} ->
+        [prefix_msg, "@#{subject_actor}", postfix_msg]
+        |> Enum.reject(&(&1 == ""))
+        |> Enum.join()
+
+      _ ->
+        ""
+    end
+  end
 end
diff --git a/lib/pleroma/web/admin_api/controllers/report_controller.ex b/lib/pleroma/web/admin_api/controllers/report_controller.ex
index 6a0e56f5f..cc77cbfdf 100644
--- a/lib/pleroma/web/admin_api/controllers/report_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/report_controller.ex
@@ -50,10 +50,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
       Enum.map(reports, fn report ->
         case CommonAPI.update_report_state(report.id, report.state) do
           {:ok, activity} ->
+            report = Activity.get_by_id_with_user_actor(activity.id)
+
             ModerationLog.insert_log(%{
               action: "report_update",
               actor: admin,
-              subject: activity
+              subject: activity,
+              subject_actor: report.user_actor
             })
 
             activity
@@ -73,11 +76,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
   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
+    with {:ok, _} <- ReportNote.create(user.id, report_id, content),
+         report <- Activity.get_by_id_with_user_actor(report_id) do
       ModerationLog.insert_log(%{
         action: "report_note",
         actor: user,
-        subject: Activity.get_by_id(report_id),
+        subject: report,
+        subject_actor: report.user_actor,
         text: content
       })
 
@@ -91,11 +96,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
         id: note_id,
         report_id: report_id
       }) do
-    with {:ok, note} <- ReportNote.destroy(note_id) do
+    with {:ok, note} <- ReportNote.destroy(note_id),
+         report <- Activity.get_by_id_with_user_actor(report_id) do
       ModerationLog.insert_log(%{
         action: "report_note_delete",
         actor: user,
-        subject: Activity.get_by_id(report_id),
+        subject: report,
+        subject_actor: report.user_actor,
         text: note.content
       })
 
diff --git a/test/pleroma/activity_test.exs b/test/pleroma/activity_test.exs
index ee6a99cc3..dfb811d77 100644
--- a/test/pleroma/activity_test.exs
+++ b/test/pleroma/activity_test.exs
@@ -197,6 +197,13 @@ defmodule Pleroma.ActivityTest do
     assert [%{id: ^id1, object: %Object{}}, %{id: ^id2, object: %Object{}}] = activities
   end
 
+  test "get_by_id_with_user_actor/1" do
+    user = insert(:user)
+    activity = insert(:note_activity, note: insert(:note, user: user))
+
+    assert Activity.get_by_id_with_user_actor(activity.id).user_actor == user
+  end
+
   test "get_by_id_with_object/1" do
     %{id: id} = insert(:note_activity)
 
diff --git a/test/pleroma/moderation_log_test.exs b/test/pleroma/moderation_log_test.exs
index 59f4d67f8..fe705def1 100644
--- a/test/pleroma/moderation_log_test.exs
+++ b/test/pleroma/moderation_log_test.exs
@@ -186,7 +186,8 @@ defmodule Pleroma.ModerationLogTest do
         id: "9m9I1F4p8ftrTP6QTI",
         data: %{
           "type" => "Flag",
-          "state" => "resolved"
+          "state" => "resolved",
+          "actor" => "http://localhost:4000/users/max"
         }
       }
 
@@ -204,25 +205,37 @@ defmodule Pleroma.ModerationLogTest do
     end
 
     test "logging report response", %{moderator: moderator} do
+      user = insert(:user)
+
       report = %Activity{
         id: "9m9I1F4p8ftrTP6QTI",
         data: %{
-          "type" => "Note"
+          "type" => "Note",
+          "actor" => user.ap_id
         }
       }
 
-      {:ok, _} =
-        ModerationLog.insert_log(%{
-          actor: moderator,
-          action: "report_note",
-          subject: report,
-          text: "look at this"
-        })
+      attrs = %{
+        actor: moderator,
+        action: "report_note",
+        subject: report,
+        text: "look at this"
+      }
 
-      log = Repo.one(ModerationLog)
+      {:ok, log1} = ModerationLog.insert_log(attrs)
+      log = Repo.get(ModerationLog, log1.id)
 
       assert log.data["message"] ==
                "@#{moderator.nickname} added note 'look at this' to report ##{report.id}"
+
+      {:ok, log2} = ModerationLog.insert_log(Map.merge(attrs, %{subject_actor: user}))
+
+      log = Repo.get(ModerationLog, log2.id)
+
+      assert log.data["message"] ==
+               "@#{moderator.nickname} added note 'look at this' to report ##{report.id} on user @#{
+                 user.nickname
+               }"
     end
 
     test "logging status sensitivity update", %{moderator: moderator} do
diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs
index 958e1d3ab..cbfc2e7b0 100644
--- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs
@@ -122,13 +122,13 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
       })
       |> json_response_and_validate_schema(:no_content)
 
-      activity = Activity.get_by_id(id)
+      activity = Activity.get_by_id_with_user_actor(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"
+               "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state"
     end
 
     test "closes report", %{conn: conn, id: id, admin: admin} do
@@ -141,13 +141,13 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
       })
       |> json_response_and_validate_schema(:no_content)
 
-      activity = Activity.get_by_id(id)
+      activity = Activity.get_by_id_with_user_actor(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"
+               "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'closed' state"
     end
 
     test "returns 400 when state is unknown", %{conn: conn, id: id} do
@@ -193,18 +193,20 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
       })
       |> json_response_and_validate_schema(:no_content)
 
-      activity = Activity.get_by_id(id)
-      second_activity = Activity.get_by_id(second_report_id)
+      activity = Activity.get_by_id_with_user_actor(id)
+      second_activity = Activity.get_by_id_with_user_actor(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"
+               "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state"
 
       assert ModerationLog.get_log_entry_message(second_log_entry) ==
-               "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
+               "@#{admin.nickname} updated report ##{second_report_id} (on user @#{
+                 second_activity.user_actor.nickname
+               }) with 'closed' state"
     end
   end
 
diff --git a/test/pleroma/web/admin_api/views/moderation_log_view_test.exs b/test/pleroma/web/admin_api/views/moderation_log_view_test.exs
new file mode 100644
index 000000000..e6c5aaa7f
--- /dev/null
+++ b/test/pleroma/web/admin_api/views/moderation_log_view_test.exs
@@ -0,0 +1,98 @@
+# 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.ModerationLogViewTest do
+  use Pleroma.DataCase
+
+  alias Pleroma.Web.AdminAPI.ModerationLogView
+
+  describe "renders `report_note_delete` log messages" do
+    setup do
+      log1 = %Pleroma.ModerationLog{
+        data: %{
+          "action" => "report_note_delete",
+          "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+          "message" => "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+          "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+          "subject_actor" => %{"id" => "A1I7G8", "nickname" => "b-612", "type" => "user"},
+          "text" => "mistake"
+        },
+        inserted_at: ~N[2020-11-17 14:13:20]
+      }
+
+      log2 = %Pleroma.ModerationLog{
+        data: %{
+          "action" => "report_note_delete",
+          "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+          "message" => "@admin deleted note 'fake user' from report #A1I7be on user @j-612",
+          "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+          "subject_actor" => %{"id" => "A1I7G8", "nickname" => "j-612", "type" => "user"},
+          "text" => "fake user"
+        },
+        inserted_at: ~N[2020-11-17 14:13:20]
+      }
+
+      {:ok, %{log1: log1, log2: log2}}
+    end
+
+    test "renders `report_note_delete` log messages", %{log1: log1, log2: log2} do
+      assert ModerationLogView.render(
+               "index.json",
+               %{log: %{items: [log1, log2], count: 2}}
+             ) == %{
+               items: [
+                 %{
+                   data: %{
+                     "action" => "report_note_delete",
+                     "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+                     "message" =>
+                       "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+                     "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+                     "subject_actor" => %{
+                       "id" => "A1I7G8",
+                       "nickname" => "b-612",
+                       "type" => "user"
+                     },
+                     "text" => "mistake"
+                   },
+                   message: "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+                   time: 1_605_622_400
+                 },
+                 %{
+                   data: %{
+                     "action" => "report_note_delete",
+                     "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+                     "message" =>
+                       "@admin deleted note 'fake user' from report #A1I7be on user @j-612",
+                     "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+                     "subject_actor" => %{
+                       "id" => "A1I7G8",
+                       "nickname" => "j-612",
+                       "type" => "user"
+                     },
+                     "text" => "fake user"
+                   },
+                   message: "@admin deleted note 'fake user' from report #A1I7be on user @j-612",
+                   time: 1_605_622_400
+                 }
+               ],
+               total: 2
+             }
+    end
+
+    test "renders `report_note_delete` log message", %{log1: log} do
+      assert ModerationLogView.render("show.json", %{log_entry: log}) == %{
+               data: %{
+                 "action" => "report_note_delete",
+                 "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+                 "message" => "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+                 "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+                 "subject_actor" => %{"id" => "A1I7G8", "nickname" => "b-612", "type" => "user"},
+                 "text" => "mistake"
+               },
+               message: "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+               time: 1_605_622_400
+             }
+    end
+  end
+end

From fb72f2034a5d6d434b7fcdc428d559bf9312b163 Mon Sep 17 00:00:00 2001
From: Maksim Pechnikov <parallel588@gmail.com>
Date: Wed, 25 Nov 2020 16:44:11 +0300
Subject: [PATCH 2/2] fix spec

---
 lib/pleroma/moderation_log.ex        | 341 +++++++++------------------
 test/pleroma/moderation_log_test.exs |   9 +-
 2 files changed, 113 insertions(+), 237 deletions(-)

diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex
index 0a701127f..a7f26793d 100644
--- a/lib/pleroma/moderation_log.ex
+++ b/lib/pleroma/moderation_log.ex
@@ -12,6 +12,26 @@ defmodule Pleroma.ModerationLog do
 
   import Ecto.Query
 
+  @type t :: %__MODULE__{}
+  @type log_subject :: Activity.t() | User.t() | list(User.t())
+  @type log_params :: %{
+          required(:actor) => User.t(),
+          required(:action) => String.t(),
+          optional(:subject) => log_subject(),
+          optional(:subject_actor) => User.t(),
+          optional(:subject_id) => String.t(),
+          optional(:subjects) => list(User.t()),
+          optional(:permission) => String.t(),
+          optional(:text) => String.t(),
+          optional(:sensitive) => String.t(),
+          optional(:visibility) => String.t(),
+          optional(:followed) => User.t(),
+          optional(:follower) => User.t(),
+          optional(:nicknames) => list(String.t()),
+          optional(:tags) => list(String.t()),
+          optional(:target) => String.t()
+        }
+
   schema "moderation_log" do
     field(:data, :map)
 
@@ -90,212 +110,105 @@ defmodule Pleroma.ModerationLog do
     parsed_datetime
   end
 
-  @spec insert_log(%{actor: User, subject: [User], action: String.t(), permission: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        subject: subjects,
-        action: action,
-        permission: permission
-      }) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "subject" => user_to_map(subjects),
-        "action" => action,
-        "permission" => permission,
-        "message" => ""
-      }
+  defp prepare_log_data(%{actor: actor, action: action} = attrs) do
+    %{
+      "actor" => user_to_map(actor),
+      "action" => action,
+      "message" => ""
     }
-    |> insert_log_entry_with_message()
+    |> Pleroma.Maps.put_if_present("subject_actor", user_to_map(attrs[:subject_actor]))
   end
 
-  @spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(
-        %{
-          actor: %User{} = actor,
-          action: "report_update",
-          subject: %Activity{data: %{"type" => "Flag"}} = subject
-        } = attrs
-      ) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "report_update",
-        "subject" => report_to_map(subject),
-        "subject_actor" => user_to_map(attrs[:subject_actor]),
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+  defp prepare_log_data(attrs), do: attrs
+
+  @spec insert_log(log_params()) :: {:ok, ModerationLog} | {:error, any}
+  def insert_log(%{actor: %User{}, subject: subjects, permission: permission} = attrs) do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{"subject" => user_to_map(subjects), "permission" => permission})
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
+  end
+
+  def insert_log(%{actor: %User{}, action: action, subject: %Activity{} = subject} = attrs)
+      when action in ["report_note_delete", "report_update", "report_note"] do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Pleroma.Maps.put_if_present("text", attrs[:text])
+      |> Map.merge(%{"subject" => report_to_map(subject)})
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
   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",
+          actor: %User{},
+          action: action,
           subject: %Activity{} = subject,
-          text: text
+          sensitive: sensitive,
+          visibility: visibility
         } = attrs
-      ) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "report_note",
-        "subject" => report_to_map(subject),
-        "subject_actor" => user_to_map(attrs[:subject_actor]),
-        "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
-        } = attrs
-      ) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "report_note_delete",
-        "subject" => report_to_map(subject),
-        "subject_actor" => user_to_map(attrs[:subject_actor]),
-        "text" => text
-      }
-    }
-    |> insert_log_entry_with_message()
-  end
-
-  @spec insert_log(%{
-          actor: User,
-          subject: Activity,
-          action: String.t(),
-          sensitive: String.t(),
-          visibility: String.t()
-        }) :: {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        action: "status_update",
-        subject: %Activity{} = subject,
-        sensitive: sensitive,
-        visibility: visibility
-      }) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "status_update",
+      )
+      when action == "status_update" do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{
         "subject" => status_to_map(subject),
         "sensitive" => sensitive,
-        "visibility" => visibility,
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+        "visibility" => visibility
+      })
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
   end
 
-  @spec insert_log(%{actor: User, action: String.t(), subject_id: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        action: "status_delete",
-        subject_id: subject_id
-      }) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "status_delete",
-        "subject_id" => subject_id,
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+  def insert_log(%{actor: %User{}, action: action, subject_id: subject_id} = attrs)
+      when action == "status_delete" do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{"subject_id" => subject_id})
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
   end
 
-  @spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{actor: %User{} = actor, subject: subject, action: action}) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => action,
-        "subject" => user_to_map(subject),
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+  def insert_log(%{actor: %User{}, subject: subject, action: _action} = attrs) do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{"subject" => user_to_map(subject)})
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
   end
 
-  @spec insert_log(%{actor: User, subjects: [User], action: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{actor: %User{} = actor, subjects: subjects, action: action}) do
-    subjects = Enum.map(subjects, &user_to_map/1)
+  def insert_log(%{actor: %User{}, subjects: subjects, action: _action} = attrs) do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{"subjects" => user_to_map(subjects)})
 
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => action,
-        "subjects" => subjects,
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+    insert_log_entry_with_message(%ModerationLog{data: data})
   end
 
-  @spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        followed: %User{} = followed,
-        follower: %User{} = follower,
-        action: "follow"
-      }) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "follow",
-        "followed" => user_to_map(followed),
-        "follower" => user_to_map(follower),
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+  def insert_log(
+        %{
+          actor: %User{},
+          followed: %User{} = followed,
+          follower: %User{} = follower,
+          action: action
+        } = attrs
+      )
+      when action in ["unfollow", "follow"] do
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{"followed" => user_to_map(followed), "follower" => user_to_map(follower)})
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
   end
 
-  @spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        followed: %User{} = followed,
-        follower: %User{} = follower,
-        action: "unfollow"
-      }) do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => "unfollow",
-        "followed" => user_to_map(followed),
-        "follower" => user_to_map(follower),
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
-  end
-
-  @spec insert_log(%{
-          actor: User,
-          action: String.t(),
-          nicknames: [String.t()],
-          tags: [String.t()]
-        }) :: {:ok, ModerationLog} | {:error, any}
   def insert_log(%{
         actor: %User{} = actor,
         nicknames: nicknames,
@@ -314,27 +227,16 @@ defmodule Pleroma.ModerationLog do
     |> insert_log_entry_with_message()
   end
 
-  @spec insert_log(%{actor: User, action: String.t(), target: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
-  def insert_log(%{
-        actor: %User{} = actor,
-        action: action,
-        target: target
-      })
+  def insert_log(%{actor: %User{}, action: action, target: target} = attrs)
       when action in ["relay_follow", "relay_unfollow"] do
-    %ModerationLog{
-      data: %{
-        "actor" => user_to_map(actor),
-        "action" => action,
-        "target" => target,
-        "message" => ""
-      }
-    }
-    |> insert_log_entry_with_message()
+    data =
+      attrs
+      |> prepare_log_data
+      |> Map.merge(%{"target" => target})
+
+    insert_log_entry_with_message(%ModerationLog{data: data})
   end
 
-  @spec insert_log(%{actor: User, action: String.t(), subject_id: String.t()}) ::
-          {:ok, ModerationLog} | {:error, any}
   def insert_log(%{actor: %User{} = actor, action: "chat_message_delete", subject_id: subject_id}) do
     %ModerationLog{
       data: %{
@@ -367,20 +269,14 @@ defmodule Pleroma.ModerationLog do
   defp user_to_map(_), do: nil
 
   defp report_to_map(%Activity{} = report) do
-    %{
-      "type" => "report",
-      "id" => report.id,
-      "state" => report.data["state"]
-    }
+    %{"type" => "report", "id" => report.id, "state" => report.data["state"]}
   end
 
   defp status_to_map(%Activity{} = status) do
-    %{
-      "type" => "status",
-      "id" => status.id
-    }
+    %{"type" => "status", "id" => status.id}
   end
 
+  @spec get_log_entry_message(ModerationLog.t()) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -392,7 +288,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} made @#{follower_nickname} #{action} @#{followed_nickname}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -403,7 +298,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} deleted users: #{users_to_nicknames_string(subjects)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -414,7 +308,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} created users: #{users_to_nicknames_string(subjects)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -425,7 +318,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} activated users: #{users_to_nicknames_string(users)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -436,7 +328,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} deactivated users: #{users_to_nicknames_string(users)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -447,7 +338,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} approved users: #{users_to_nicknames_string(users)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -461,7 +351,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} added tags: #{tags_string} to users: #{nicknames_to_string(nicknames)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -475,7 +364,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} removed tags: #{tags_string} from users: #{nicknames_to_string(nicknames)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -487,7 +375,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} made #{users_to_nicknames_string(users)} #{permission}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -499,7 +386,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} revoked #{permission} role from #{users_to_nicknames_string(users)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -510,7 +396,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} followed relay: #{target}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -521,7 +406,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} unfollowed relay: #{target}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(
         %ModerationLog{
           data: %{
@@ -536,7 +420,6 @@ defmodule Pleroma.ModerationLog do
       " with '#{state}' state"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(
         %ModerationLog{
           data: %{
@@ -551,7 +434,6 @@ defmodule Pleroma.ModerationLog do
       subject_actor_nickname(log, " on user ")
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(
         %ModerationLog{
           data: %{
@@ -566,7 +448,6 @@ defmodule Pleroma.ModerationLog do
       subject_actor_nickname(log, " on user ")
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -579,7 +460,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} updated status ##{subject_id}, set visibility: '#{visibility}'"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -592,7 +472,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} updated status ##{subject_id}, set sensitive: '#{sensitive}'"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -607,7 +486,6 @@ defmodule Pleroma.ModerationLog do
     }'"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -618,7 +496,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} deleted status ##{subject_id}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -629,7 +506,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} forced password reset for users: #{users_to_nicknames_string(subjects)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -640,7 +516,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} confirmed email for users: #{users_to_nicknames_string(subjects)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -653,7 +528,6 @@ defmodule Pleroma.ModerationLog do
     }"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
@@ -664,7 +538,6 @@ defmodule Pleroma.ModerationLog do
     "@#{actor_nickname} updated users: #{users_to_nicknames_string(subjects)}"
   end
 
-  @spec get_log_entry_message(ModerationLog) :: String.t()
   def get_log_entry_message(%ModerationLog{
         data: %{
           "actor" => %{"nickname" => actor_nickname},
diff --git a/test/pleroma/moderation_log_test.exs b/test/pleroma/moderation_log_test.exs
index fe705def1..03b32a060 100644
--- a/test/pleroma/moderation_log_test.exs
+++ b/test/pleroma/moderation_log_test.exs
@@ -182,12 +182,14 @@ defmodule Pleroma.ModerationLogTest do
     end
 
     test "logging report update", %{moderator: moderator} do
+      user = insert(:user)
+
       report = %Activity{
         id: "9m9I1F4p8ftrTP6QTI",
         data: %{
           "type" => "Flag",
           "state" => "resolved",
-          "actor" => "http://localhost:4000/users/max"
+          "actor" => user.ap_id
         }
       }
 
@@ -195,13 +197,14 @@ defmodule Pleroma.ModerationLogTest do
         ModerationLog.insert_log(%{
           actor: moderator,
           action: "report_update",
-          subject: report
+          subject: report,
+          subject_actor: user
         })
 
       log = Repo.one(ModerationLog)
 
       assert log.data["message"] ==
-               "@#{moderator.nickname} updated report ##{report.id} with 'resolved' state"
+               "@#{moderator.nickname} updated report ##{report.id} (on user @#{user.nickname}) with 'resolved' state"
     end
 
     test "logging report response", %{moderator: moderator} do