params
|> get_all_query()
|> maybe_filter_by_date(params)
+ |> maybe_filter_by_user(params)
+ |> maybe_filter_by_search(params)
|> Repo.all()
end
)
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],
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",
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()}) ::
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
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", %{
log = Repo.one(ModerationLog)
- assert ModerationLog.get_log_entry_message(log) ==
+ assert log.data["message"] ==
"@#{moderator.nickname} created users: @#{subject1.nickname}, @#{subject2.nickname}"
end
log = Repo.one(ModerationLog)
- assert ModerationLog.get_log_entry_message(log) ==
+ assert log.data["message"] ==
"@#{admin.nickname} made @#{subject2.nickname} follow @#{subject1.nickname}"
end
log = Repo.one(ModerationLog)
- assert ModerationLog.get_log_entry_message(log) ==
+ assert log.data["message"] ==
"@#{admin.nickname} made @#{subject2.nickname} unfollow @#{subject1.nickname}"
end
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
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
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
log = Repo.one(ModerationLog)
- assert ModerationLog.get_log_entry_message(log) ==
+ assert log.data["message"] ==
"@#{moderator.nickname} revoked moderator role from @#{subject1.nickname}"
end
log = Repo.one(ModerationLog)
- assert ModerationLog.get_log_entry_message(log) ==
+ assert log.data["message"] ==
"@#{moderator.nickname} followed relay: https://example.org/relay"
end
log = Repo.one(ModerationLog)
- assert ModerationLog.get_log_entry_message(log) ==
+ assert log.data["message"] ==
"@#{moderator.nickname} unfollowed relay: https://example.org/relay"
end
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
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
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
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
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
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
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
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