2019-08-25 13:39:37 -06: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 11:48:16 -06:00
|
|
|
def get_all(params) do
|
|
|
|
params
|
|
|
|
|> get_all_query()
|
|
|
|
|> maybe_filter_by_date(params)
|
|
|
|
|> Repo.all()
|
|
|
|
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
|
|
|
|
|
|
|
|
defp get_all_query(%{page: page, page_size: page_size}) do
|
2019-08-25 13:39:37 -06:00
|
|
|
from(q in __MODULE__,
|
|
|
|
order_by: [desc: q.inserted_at],
|
|
|
|
limit: ^page_size,
|
|
|
|
offset: ^((page - 1) * page_size)
|
|
|
|
)
|
2019-08-27 11:48:16 -06:00
|
|
|
end
|
|
|
|
|
|
|
|
defp parse_datetime(datetime) do
|
|
|
|
{:ok, parsed_datetime, _} = DateTime.from_iso8601(datetime)
|
|
|
|
|
|
|
|
parsed_datetime
|
2019-08-25 13:39:37 -06:00
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
subject: %User{} = subject,
|
|
|
|
action: action,
|
|
|
|
permission: permission
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
subject: user_to_map(subject),
|
|
|
|
action: action,
|
|
|
|
permission: permission
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
action: "report_update",
|
|
|
|
subject: %Activity{data: %{"type" => "Flag"}} = subject
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: "report_update",
|
|
|
|
subject: report_to_map(subject)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
action: "report_response",
|
|
|
|
subject: %Activity{} = subject,
|
|
|
|
text: text
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: "report_response",
|
|
|
|
subject: report_to_map(subject),
|
|
|
|
text: text
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
action: "status_update",
|
|
|
|
subject: %Activity{} = subject,
|
|
|
|
sensitive: sensitive,
|
|
|
|
visibility: visibility
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: "status_update",
|
|
|
|
subject: status_to_map(subject),
|
|
|
|
sensitive: sensitive,
|
|
|
|
visibility: visibility
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
action: "status_delete",
|
|
|
|
subject_id: subject_id
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: "status_delete",
|
|
|
|
subject_id: subject_id
|
|
|
|
}
|
|
|
|
})
|
|
|
|
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{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: action,
|
|
|
|
subject: user_to_map(subject)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
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)
|
|
|
|
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: action,
|
|
|
|
subjects: subjects
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
followed: %User{} = followed,
|
|
|
|
follower: %User{} = follower,
|
|
|
|
action: "follow"
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: "follow",
|
|
|
|
followed: user_to_map(followed),
|
|
|
|
follower: user_to_map(follower)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
followed: %User{} = followed,
|
|
|
|
follower: %User{} = follower,
|
|
|
|
action: "unfollow"
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: "unfollow",
|
|
|
|
followed: user_to_map(followed),
|
|
|
|
follower: user_to_map(follower)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
nicknames: nicknames,
|
|
|
|
tags: tags,
|
|
|
|
action: action
|
|
|
|
}) do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
nicknames: nicknames,
|
|
|
|
tags: tags,
|
|
|
|
action: action
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
def insert_log(%{
|
|
|
|
actor: %User{} = actor,
|
|
|
|
action: action,
|
|
|
|
target: target
|
|
|
|
})
|
|
|
|
when action in ["relay_follow", "relay_unfollow"] do
|
|
|
|
Repo.insert(%ModerationLog{
|
|
|
|
data: %{
|
|
|
|
actor: user_to_map(actor),
|
|
|
|
action: action,
|
|
|
|
target: target
|
|
|
|
}
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
defp user_to_map(%User{} = user) do
|
|
|
|
user
|
|
|
|
|> Map.from_struct()
|
|
|
|
|> Map.take([:id, :nickname])
|
|
|
|
|> Map.put(:type, "user")
|
|
|
|
end
|
|
|
|
|
|
|
|
defp report_to_map(%Activity{} = report) do
|
|
|
|
%{
|
|
|
|
type: "report",
|
|
|
|
id: report.id,
|
|
|
|
state: report.data["state"]
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
defp status_to_map(%Activity{} = status) do
|
|
|
|
%{
|
|
|
|
type: "status",
|
|
|
|
id: status.id
|
|
|
|
}
|
|
|
|
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
|