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)
@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" => ""
}
}
@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
}
}
@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
}
}
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",
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()
|> 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
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
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
})
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
})
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)
id: "9m9I1F4p8ftrTP6QTI",
data: %{
"type" => "Flag",
- "state" => "resolved"
+ "state" => "resolved",
+ "actor" => "http://localhost:4000/users/max"
}
}
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
})
|> 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
})
|> 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
})
|> 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
--- /dev/null
+# 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