Add ability to search moderation logs
authorMaxim Filippov <colixer@gmail.com>
Fri, 30 Aug 2019 21:57:15 +0000 (00:57 +0300)
committerMaxim Filippov <colixer@gmail.com>
Fri, 30 Aug 2019 21:57:15 +0000 (00:57 +0300)
lib/pleroma/moderation_log.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
test/moderation_log_test.exs
test/web/admin_api/admin_api_controller_test.exs

index 2164ecfc2681a2f449798d963a7da4a0fbb19451..c72a413b616bfd9ee51766f35a5ea94bbaa06a5f 100644 (file)
@@ -18,6 +18,8 @@ defmodule Pleroma.ModerationLog do
     params
     |> get_all_query()
     |> maybe_filter_by_date(params)
+    |> maybe_filter_by_user(params)
+    |> maybe_filter_by_search(params)
     |> Repo.all()
   end
 
@@ -42,6 +44,23 @@ defmodule Pleroma.ModerationLog do
     )
   end
 
+  defp maybe_filter_by_user(query, %{user_id: nil}), do: query
+
+  defp maybe_filter_by_user(query, %{user_id: user_id}) do
+    from(q in query,
+      where: fragment("(?)->'actor'->>'id' = ?", q.data, ^user_id)
+    )
+  end
+
+  defp maybe_filter_by_search(query, %{search: search}) when is_nil(search) or search == "",
+    do: query
+
+  defp maybe_filter_by_search(query, %{search: search}) do
+    from(q in query,
+      where: fragment("(?)->>'message' ILIKE ?", q.data, ^"%#{search}%")
+    )
+  end
+
   defp get_all_query(%{page: page, page_size: page_size}) do
     from(q in __MODULE__,
       order_by: [desc: q.inserted_at],
@@ -56,52 +75,71 @@ 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: %User{} = subject,
         action: action,
         permission: permission
       }) do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        subject: user_to_map(subject),
-        action: action,
-        permission: permission
+        "actor" => user_to_map(actor),
+        "subject" => user_to_map(subject),
+        "action" => action,
+        "permission" => permission,
+        "message" => ""
       }
-    })
+    }
+    |> insert_log_entry_with_message()
   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
       }) do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: "report_update",
-        subject: report_to_map(subject)
+        "actor" => user_to_map(actor),
+        "action" => "report_update",
+        "subject" => report_to_map(subject),
+        "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_response",
         subject: %Activity{} = subject,
         text: text
       }) do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: "report_response",
-        subject: report_to_map(subject),
-        text: text
+        "actor" => user_to_map(actor),
+        "action" => "report_response",
+        "subject" => report_to_map(subject),
+        "text" => text,
+        "message" => ""
       }
-    })
+    }
+    |> 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",
@@ -109,41 +147,49 @@ defmodule Pleroma.ModerationLog do
         sensitive: sensitive,
         visibility: visibility
       }) do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: "status_update",
-        subject: status_to_map(subject),
-        sensitive: sensitive,
-        visibility: visibility
+        "actor" => user_to_map(actor),
+        "action" => "status_update",
+        "subject" => status_to_map(subject),
+        "sensitive" => sensitive,
+        "visibility" => visibility,
+        "message" => ""
       }
-    })
+    }
+    |> insert_log_entry_with_message()
   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
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: "status_delete",
-        subject_id: subject_id
+        "actor" => user_to_map(actor),
+        "action" => "status_delete",
+        "subject_id" => subject_id,
+        "message" => ""
       }
-    })
+    }
+    |> insert_log_entry_with_message()
   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
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: action,
-        subject: user_to_map(subject)
+        "actor" => user_to_map(actor),
+        "action" => action,
+        "subject" => user_to_map(subject),
+        "message" => ""
       }
-    })
+    }
+    |> insert_log_entry_with_message()
   end
 
   @spec insert_log(%{actor: User, subjects: [User], action: String.t()}) ::
@@ -151,97 +197,124 @@ defmodule Pleroma.ModerationLog do
   def insert_log(%{actor: %User{} = actor, subjects: subjects, action: action}) do
     subjects = Enum.map(subjects, &user_to_map/1)
 
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: action,
-        subjects: subjects
+        "actor" => user_to_map(actor),
+        "action" => action,
+        "subjects" => subjects,
+        "message" => ""
       }
-    })
+    }
+    |> insert_log_entry_with_message()
   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
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: "follow",
-        followed: user_to_map(followed),
-        follower: user_to_map(follower)
+        "actor" => user_to_map(actor),
+        "action" => "follow",
+        "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(), followed: User, follower: User}) ::
+          {:ok, ModerationLog} | {:error, any}
   def insert_log(%{
         actor: %User{} = actor,
         followed: %User{} = followed,
         follower: %User{} = follower,
         action: "unfollow"
       }) do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: "unfollow",
-        followed: user_to_map(followed),
-        follower: user_to_map(follower)
+        "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,
         tags: tags,
         action: action
       }) do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        nicknames: nicknames,
-        tags: tags,
-        action: action
+        "actor" => user_to_map(actor),
+        "nicknames" => nicknames,
+        "tags" => tags,
+        "action" => action,
+        "message" => ""
       }
-    })
+    }
+    |> 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
       })
       when action in ["relay_follow", "relay_unfollow"] do
-    Repo.insert(%ModerationLog{
+    %ModerationLog{
       data: %{
-        actor: user_to_map(actor),
-        action: action,
-        target: target
+        "actor" => user_to_map(actor),
+        "action" => action,
+        "target" => target,
+        "message" => ""
       }
-    })
+    }
+    |> insert_log_entry_with_message()
+  end
+
+  @spec insert_log_entry_with_message(ModerationLog) :: {:ok, ModerationLog} | {:error, any}
+
+  defp insert_log_entry_with_message(entry) do
+    entry.data["message"]
+    |> put_in(get_log_entry_message(entry))
+    |> Repo.insert()
   end
 
   defp user_to_map(%User{} = user) do
     user
     |> Map.from_struct()
     |> Map.take([:id, :nickname])
-    |> Map.put(:type, "user")
+    |> Map.new(fn {k, v} -> {Atom.to_string(k), v} end)
+    |> Map.put("type", "user")
   end
 
   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
 
index 065394a24b331615c532f1180e7def6184d399b0..135c6ae87f7bdee264d31ce3aca329d5ff281187 100644 (file)
@@ -544,7 +544,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
         page: page,
         page_size: page_size,
         start_date: params["start_date"],
-        end_date: params["end_date"]
+        end_date: params["end_date"],
+        user_id: params["user_id"],
+        search: params["search"]
       })
 
     conn
index c7870847186f9c16a7970ffe7cab20a9728f709d..a39a00e0221ff2b3e8265540da28ab53980ec4a1 100644 (file)
@@ -30,8 +30,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
-               "@#{moderator.nickname} deleted user @#{subject1.nickname}"
+      assert log.data["message"] == "@#{moderator.nickname} deleted user @#{subject1.nickname}"
     end
 
     test "logging user creation by moderator", %{
@@ -48,7 +47,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} created users: @#{subject1.nickname}, @#{subject2.nickname}"
     end
 
@@ -63,7 +62,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{admin.nickname} made @#{subject2.nickname} follow @#{subject1.nickname}"
     end
 
@@ -78,7 +77,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{admin.nickname} made @#{subject2.nickname} unfollow @#{subject1.nickname}"
     end
 
@@ -100,8 +99,7 @@ defmodule Pleroma.ModerationLogTest do
 
       tags = ["foo", "bar"] |> Enum.join(", ")
 
-      assert ModerationLog.get_log_entry_message(log) ==
-               "@#{admin.nickname} added tags: #{tags} to users: #{users}"
+      assert log.data["message"] == "@#{admin.nickname} added tags: #{tags} to users: #{users}"
     end
 
     test "logging user untagged by admin", %{admin: admin, subject1: subject1, subject2: subject2} do
@@ -122,7 +120,7 @@ defmodule Pleroma.ModerationLogTest do
 
       tags = ["foo", "bar"] |> Enum.join(", ")
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
     end
 
@@ -137,8 +135,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
-               "@#{moderator.nickname} made @#{subject1.nickname} moderator"
+      assert log.data["message"] == "@#{moderator.nickname} made @#{subject1.nickname} moderator"
     end
 
     test "logging user revoke by moderator", %{moderator: moderator, subject1: subject1} do
@@ -152,7 +149,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} revoked moderator role from @#{subject1.nickname}"
     end
 
@@ -166,7 +163,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} followed relay: https://example.org/relay"
     end
 
@@ -180,7 +177,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
     end
 
@@ -202,7 +199,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} updated report ##{report.id} with 'resolved' state"
     end
 
@@ -224,7 +221,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} responded with 'look at this' to report ##{report.id}"
     end
 
@@ -242,7 +239,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true'"
     end
 
@@ -260,7 +257,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} updated status ##{note.id}, set visibility: 'private'"
     end
 
@@ -278,7 +275,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
+      assert log.data["message"] ==
                "@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true', visibility: 'private'"
     end
 
@@ -294,8 +291,7 @@ defmodule Pleroma.ModerationLogTest do
 
       log = Repo.one(ModerationLog)
 
-      assert ModerationLog.get_log_entry_message(log) ==
-               "@#{moderator.nickname} deleted status ##{note.id}"
+      assert log.data["message"] == "@#{moderator.nickname} deleted status ##{note.id}"
     end
   end
 end
index a7269aee9a35acf251e71e38e94577fab6ce0446..eaf847b2588566307ab1b1aafc9979416498118e 100644 (file)
@@ -2251,8 +2251,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   describe "GET /api/pleroma/admin/moderation_log" do
     setup %{conn: conn} do
       admin = insert(:user, info: %{is_admin: true})
+      moderator = insert(:user, info: %{is_moderator: true})
 
-      %{conn: assign(conn, :user, admin), admin: admin}
+      %{conn: assign(conn, :user, admin), admin: admin, moderator: moderator}
     end
 
     test "returns the log", %{conn: conn, admin: admin} do
@@ -2394,6 +2395,64 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       assert first_entry["message"] ==
                "@#{admin.nickname} unfollowed relay: https://example.org/relay"
     end
+
+    test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
+      Repo.insert(%ModerationLog{
+        data: %{
+          actor: %{
+            "id" => admin.id,
+            "nickname" => admin.nickname,
+            "type" => "user"
+          },
+          action: "relay_follow",
+          target: "https://example.org/relay"
+        }
+      })
+
+      Repo.insert(%ModerationLog{
+        data: %{
+          actor: %{
+            "id" => moderator.id,
+            "nickname" => moderator.nickname,
+            "type" => "user"
+          },
+          action: "relay_unfollow",
+          target: "https://example.org/relay"
+        }
+      })
+
+      conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
+
+      response1 = json_response(conn1, 200)
+      [first_entry] = response1
+
+      assert response1 |> length() == 1
+      assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
+    end
+
+    test "returns log filtered by search", %{conn: conn, moderator: moderator} do
+      ModerationLog.insert_log(%{
+        actor: moderator,
+        action: "relay_follow",
+        target: "https://example.org/relay"
+      })
+
+      ModerationLog.insert_log(%{
+        actor: moderator,
+        action: "relay_unfollow",
+        target: "https://example.org/relay"
+      })
+
+      conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
+
+      response1 = json_response(conn1, 200)
+      [first_entry] = response1
+
+      assert response1 |> length() == 1
+
+      assert get_in(first_entry, ["data", "message"]) ==
+               "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
+    end
   end
 end