distraction.party/lib/pleroma/moderation_log.ex

555 lines
16 KiB
Elixir
Raw Normal View History

2019-08-25 19:39:37 +00:00
defmodule Pleroma.ModerationLog do
use Ecto.Schema
alias Pleroma.Activity
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.User
import Ecto.Query
schema "moderation_log" do
field(:data, :map)
timestamps()
end
2019-08-27 17:48:16 +00:00
def get_all(params) do
2019-09-01 18:23:30 +00:00
base_query =
get_all_query()
|> maybe_filter_by_date(params)
|> maybe_filter_by_user(params)
|> maybe_filter_by_search(params)
query_with_pagination = base_query |> paginate_query(params)
%{
items: Repo.all(query_with_pagination),
count: Repo.aggregate(base_query, :count, :id)
}
2019-08-27 17:48:16 +00:00
end
defp maybe_filter_by_date(query, %{start_date: nil, end_date: nil}), do: query
defp maybe_filter_by_date(query, %{start_date: start_date, end_date: nil}) do
from(q in query,
where: q.inserted_at >= ^parse_datetime(start_date)
)
end
defp maybe_filter_by_date(query, %{start_date: nil, end_date: end_date}) do
from(q in query,
where: q.inserted_at <= ^parse_datetime(end_date)
)
end
defp maybe_filter_by_date(query, %{start_date: start_date, end_date: end_date}) do
from(q in query,
where: q.inserted_at >= ^parse_datetime(start_date),
where: q.inserted_at <= ^parse_datetime(end_date)
)
end
2019-08-30 21:57:15 +00:00
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
2019-09-01 18:23:30 +00:00
defp paginate_query(query, %{page: page, page_size: page_size}) do
from(q in query,
2019-08-25 19:39:37 +00:00
limit: ^page_size,
offset: ^((page - 1) * page_size)
)
2019-08-27 17:48:16 +00:00
end
2019-09-01 18:23:30 +00:00
defp get_all_query do
from(q in __MODULE__,
order_by: [desc: q.inserted_at]
)
end
2019-08-27 17:48:16 +00:00
defp parse_datetime(datetime) do
{:ok, parsed_datetime, _} = DateTime.from_iso8601(datetime)
parsed_datetime
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, subject: User, action: String.t(), permission: String.t()}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
subject: %User{} = subject,
action: action,
permission: permission
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"subject" => user_to_map(subject),
"action" => action,
"permission" => permission,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
action: "report_update",
subject: %Activity{data: %{"type" => "Flag"}} = subject
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => "report_update",
"subject" => report_to_map(subject),
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
action: "report_response",
subject: %Activity{} = subject,
text: text
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => "report_response",
"subject" => report_to_map(subject),
"text" => text,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{
actor: User,
subject: Activity,
action: String.t(),
sensitive: String.t(),
visibility: String.t()
}) :: {:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
action: "status_update",
subject: %Activity{} = subject,
sensitive: sensitive,
visibility: visibility
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => "status_update",
"subject" => status_to_map(subject),
"sensitive" => sensitive,
"visibility" => visibility,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, action: String.t(), subject_id: String.t()}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
action: "status_delete",
subject_id: subject_id
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => "status_delete",
"subject_id" => subject_id,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
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
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => action,
"subject" => user_to_map(subject),
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
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)
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => action,
"subjects" => subjects,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
followed: %User{} = followed,
follower: %User{} = follower,
action: "follow"
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => "follow",
"followed" => user_to_map(followed),
"follower" => user_to_map(follower),
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
followed: %User{} = followed,
follower: %User{} = follower,
action: "unfollow"
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => "unfollow",
"followed" => user_to_map(followed),
"follower" => user_to_map(follower),
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 22:09:48 +00:00
@spec insert_log(%{
actor: User,
action: String.t(),
nicknames: [String.t()],
tags: [String.t()]
}) :: {:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
nicknames: nicknames,
tags: tags,
action: action
}) do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"nicknames" => nicknames,
"tags" => tags,
"action" => action,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> insert_log_entry_with_message()
2019-08-25 19:39:37 +00:00
end
2019-08-30 21:57:15 +00:00
@spec insert_log(%{actor: User, action: String.t(), target: String.t()}) ::
{:ok, ModerationLog} | {:error, any}
2019-08-25 19:39:37 +00:00
def insert_log(%{
actor: %User{} = actor,
action: action,
target: target
})
when action in ["relay_follow", "relay_unfollow"] do
2019-08-30 21:57:15 +00:00
%ModerationLog{
2019-08-25 19:39:37 +00:00
data: %{
2019-08-30 21:57:15 +00:00
"actor" => user_to_map(actor),
"action" => action,
"target" => target,
"message" => ""
2019-08-25 19:39:37 +00:00
}
2019-08-30 21:57:15 +00:00
}
|> 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()
2019-08-25 19:39:37 +00:00
end
defp user_to_map(%User{} = user) do
user
|> Map.from_struct()
|> Map.take([:id, :nickname])
2019-08-30 21:57:15 +00:00
|> Map.new(fn {k, v} -> {Atom.to_string(k), v} end)
|> Map.put("type", "user")
2019-08-25 19:39:37 +00:00
end
defp report_to_map(%Activity{} = report) do
%{
2019-08-30 21:57:15 +00:00
"type" => "report",
"id" => report.id,
"state" => report.data["state"]
2019-08-25 19:39:37 +00:00
}
end
defp status_to_map(%Activity{} = status) do
%{
2019-08-30 21:57:15 +00:00
"type" => "status",
"id" => status.id
2019-08-25 19:39:37 +00:00
}
end
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => action,
"followed" => %{"nickname" => followed_nickname},
"follower" => %{"nickname" => follower_nickname}
}
}) 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},
"action" => "delete",
"subject" => %{"nickname" => subject_nickname, "type" => "user"}
}
}) do
"@#{actor_nickname} deleted user @#{subject_nickname}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "create",
"subjects" => subjects
}
}) do
nicknames =
subjects
|> Enum.map(&"@#{&1["nickname"]}")
|> Enum.join(", ")
"@#{actor_nickname} created users: #{nicknames}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "activate",
"subject" => %{"nickname" => subject_nickname, "type" => "user"}
}
}) do
"@#{actor_nickname} activated user @#{subject_nickname}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "deactivate",
"subject" => %{"nickname" => subject_nickname, "type" => "user"}
}
}) do
"@#{actor_nickname} deactivated user @#{subject_nickname}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"nicknames" => nicknames,
"tags" => tags,
"action" => "tag"
}
}) do
nicknames_string =
nicknames
|> Enum.map(&"@#{&1}")
|> Enum.join(", ")
tags_string = tags |> Enum.join(", ")
"@#{actor_nickname} added tags: #{tags_string} to users: #{nicknames_string}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"nicknames" => nicknames,
"tags" => tags,
"action" => "untag"
}
}) do
nicknames_string =
nicknames
|> Enum.map(&"@#{&1}")
|> Enum.join(", ")
tags_string = tags |> Enum.join(", ")
"@#{actor_nickname} removed tags: #{tags_string} from users: #{nicknames_string}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "grant",
"subject" => %{"nickname" => subject_nickname},
"permission" => permission
}
}) do
"@#{actor_nickname} made @#{subject_nickname} #{permission}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "revoke",
"subject" => %{"nickname" => subject_nickname},
"permission" => permission
}
}) do
"@#{actor_nickname} revoked #{permission} role from @#{subject_nickname}"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "relay_follow",
"target" => target
}
}) 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},
"action" => "relay_unfollow",
"target" => target
}
}) do
"@#{actor_nickname} unfollowed relay: #{target}"
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"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "report_response",
"subject" => %{"id" => subject_id, "type" => "report"},
"text" => text
}
}) do
"@#{actor_nickname} responded with '#{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" => "status_update",
"subject" => %{"id" => subject_id, "type" => "status"},
"sensitive" => nil,
"visibility" => visibility
}
}) 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},
"action" => "status_update",
"subject" => %{"id" => subject_id, "type" => "status"},
"sensitive" => sensitive,
"visibility" => nil
}
}) 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},
"action" => "status_update",
"subject" => %{"id" => subject_id, "type" => "status"},
"sensitive" => sensitive,
"visibility" => visibility
}
}) do
"@#{actor_nickname} updated status ##{subject_id}, set sensitive: '#{sensitive}', visibility: '#{
visibility
}'"
end
@spec get_log_entry_message(ModerationLog) :: String.t()
def get_log_entry_message(%ModerationLog{
data: %{
"actor" => %{"nickname" => actor_nickname},
"action" => "status_delete",
"subject_id" => subject_id
}
}) do
"@#{actor_nickname} deleted status ##{subject_id}"
end
end