Merge branch 'feature/moderation-log-filters' into 'develop'
Moderation log filters See merge request pleroma/pleroma!1607
This commit is contained in:
commit
cb282f2ccd
|
@ -111,6 +111,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Web response cache (currently, enabled for ActivityPub)
|
- Web response cache (currently, enabled for ActivityPub)
|
||||||
- Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`)
|
- Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`)
|
||||||
- ActivityPub: Add ActivityPub actor's `discoverable` parameter.
|
- ActivityPub: Add ActivityPub actor's `discoverable` parameter.
|
||||||
|
- Admin API: Added moderation log filters (user/start date/end date/search/pagination)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
||||||
|
|
|
@ -731,7 +731,11 @@ Compile time settings (need instance reboot):
|
||||||
- Method `GET`
|
- Method `GET`
|
||||||
- Params:
|
- Params:
|
||||||
- *optional* `page`: **integer** page number
|
- *optional* `page`: **integer** page number
|
||||||
- *optional* `page_size`: **integer** number of users per page (default is `50`)
|
- *optional* `page_size`: **integer** number of log entries per page (default is `50`)
|
||||||
|
- *optional* `start_date`: **datetime (ISO 8601)** filter logs by creation date, start from `start_date`. Accepts datetime in ISO 8601 format (YYYY-MM-DDThh:mm:ss), e.g. `2005-08-09T18:31:42`
|
||||||
|
- *optional* `end_date`: **datetime (ISO 8601)** filter logs by creation date, end by from `end_date`. Accepts datetime in ISO 8601 format (YYYY-MM-DDThh:mm:ss), e.g. 2005-08-09T18:31:42
|
||||||
|
- *optional* `user_id`: **integer** filter logs by actor's id
|
||||||
|
- *optional* `search`: **string** search logs by the log message
|
||||||
- Response:
|
- Response:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
|
@ -14,61 +14,143 @@ defmodule Pleroma.ModerationLog do
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_all(page, page_size) do
|
def get_all(params) do
|
||||||
from(q in __MODULE__,
|
base_query =
|
||||||
order_by: [desc: q.inserted_at],
|
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)
|
||||||
|
}
|
||||||
|
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 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 paginate_query(query, %{page: page, page_size: page_size}) do
|
||||||
|
from(q in query,
|
||||||
limit: ^page_size,
|
limit: ^page_size,
|
||||||
offset: ^((page - 1) * page_size)
|
offset: ^((page - 1) * page_size)
|
||||||
)
|
)
|
||||||
|> Repo.all()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp get_all_query do
|
||||||
|
from(q in __MODULE__,
|
||||||
|
order_by: [desc: q.inserted_at]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse_datetime(datetime) do
|
||||||
|
{:ok, parsed_datetime, _} = DateTime.from_iso8601(datetime)
|
||||||
|
|
||||||
|
parsed_datetime
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, subject: User, action: String.t(), permission: String.t()}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
subject: %User{} = subject,
|
subject: %User{} = subject,
|
||||||
action: action,
|
action: action,
|
||||||
permission: permission
|
permission: permission
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
subject: user_to_map(subject),
|
"subject" => user_to_map(subject),
|
||||||
action: action,
|
"action" => action,
|
||||||
permission: permission
|
"permission" => permission,
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
action: "report_update",
|
action: "report_update",
|
||||||
subject: %Activity{data: %{"type" => "Flag"}} = subject
|
subject: %Activity{data: %{"type" => "Flag"}} = subject
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: "report_update",
|
"action" => "report_update",
|
||||||
subject: report_to_map(subject)
|
"subject" => report_to_map(subject),
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
action: "report_response",
|
action: "report_response",
|
||||||
subject: %Activity{} = subject,
|
subject: %Activity{} = subject,
|
||||||
text: text
|
text: text
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: "report_response",
|
"action" => "report_response",
|
||||||
subject: report_to_map(subject),
|
"subject" => report_to_map(subject),
|
||||||
text: text
|
"text" => text,
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{
|
||||||
|
actor: User,
|
||||||
|
subject: Activity,
|
||||||
|
action: String.t(),
|
||||||
|
sensitive: String.t(),
|
||||||
|
visibility: String.t()
|
||||||
|
}) :: {:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
action: "status_update",
|
action: "status_update",
|
||||||
|
@ -76,41 +158,49 @@ def insert_log(%{
|
||||||
sensitive: sensitive,
|
sensitive: sensitive,
|
||||||
visibility: visibility
|
visibility: visibility
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: "status_update",
|
"action" => "status_update",
|
||||||
subject: status_to_map(subject),
|
"subject" => status_to_map(subject),
|
||||||
sensitive: sensitive,
|
"sensitive" => sensitive,
|
||||||
visibility: visibility
|
"visibility" => visibility,
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, action: String.t(), subject_id: String.t()}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
action: "status_delete",
|
action: "status_delete",
|
||||||
subject_id: subject_id
|
subject_id: subject_id
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: "status_delete",
|
"action" => "status_delete",
|
||||||
subject_id: subject_id
|
"subject_id" => subject_id,
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
|
@spec insert_log(%{actor: User, subject: User, action: String.t()}) ::
|
||||||
{:ok, ModerationLog} | {:error, any}
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{actor: %User{} = actor, subject: subject, action: action}) do
|
def insert_log(%{actor: %User{} = actor, subject: subject, action: action}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: action,
|
"action" => action,
|
||||||
subject: user_to_map(subject)
|
"subject" => user_to_map(subject),
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec insert_log(%{actor: User, subjects: [User], action: String.t()}) ::
|
@spec insert_log(%{actor: User, subjects: [User], action: String.t()}) ::
|
||||||
|
@ -118,97 +208,128 @@ def insert_log(%{actor: %User{} = actor, subject: subject, action: action}) do
|
||||||
def insert_log(%{actor: %User{} = actor, subjects: subjects, action: action}) do
|
def insert_log(%{actor: %User{} = actor, subjects: subjects, action: action}) do
|
||||||
subjects = Enum.map(subjects, &user_to_map/1)
|
subjects = Enum.map(subjects, &user_to_map/1)
|
||||||
|
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: action,
|
"action" => action,
|
||||||
subjects: subjects
|
"subjects" => subjects,
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
followed: %User{} = followed,
|
followed: %User{} = followed,
|
||||||
follower: %User{} = follower,
|
follower: %User{} = follower,
|
||||||
action: "follow"
|
action: "follow"
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: "follow",
|
"action" => "follow",
|
||||||
followed: user_to_map(followed),
|
"followed" => user_to_map(followed),
|
||||||
follower: user_to_map(follower)
|
"follower" => user_to_map(follower),
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, action: String.t(), followed: User, follower: User}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
followed: %User{} = followed,
|
followed: %User{} = followed,
|
||||||
follower: %User{} = follower,
|
follower: %User{} = follower,
|
||||||
action: "unfollow"
|
action: "unfollow"
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: "unfollow",
|
"action" => "unfollow",
|
||||||
followed: user_to_map(followed),
|
"followed" => user_to_map(followed),
|
||||||
follower: user_to_map(follower)
|
"follower" => user_to_map(follower),
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{
|
||||||
|
actor: User,
|
||||||
|
action: String.t(),
|
||||||
|
nicknames: [String.t()],
|
||||||
|
tags: [String.t()]
|
||||||
|
}) :: {:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
nicknames: nicknames,
|
nicknames: nicknames,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
action: action
|
action: action
|
||||||
}) do
|
}) do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
nicknames: nicknames,
|
"nicknames" => nicknames,
|
||||||
tags: tags,
|
"tags" => tags,
|
||||||
action: action
|
"action" => action,
|
||||||
|
"message" => ""
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|> insert_log_entry_with_message()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec insert_log(%{actor: User, action: String.t(), target: String.t()}) ::
|
||||||
|
{:ok, ModerationLog} | {:error, any}
|
||||||
def insert_log(%{
|
def insert_log(%{
|
||||||
actor: %User{} = actor,
|
actor: %User{} = actor,
|
||||||
action: action,
|
action: action,
|
||||||
target: target
|
target: target
|
||||||
})
|
})
|
||||||
when action in ["relay_follow", "relay_unfollow"] do
|
when action in ["relay_follow", "relay_unfollow"] do
|
||||||
Repo.insert(%ModerationLog{
|
%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
actor: user_to_map(actor),
|
"actor" => user_to_map(actor),
|
||||||
action: action,
|
"action" => action,
|
||||||
target: target
|
"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
|
end
|
||||||
|
|
||||||
defp user_to_map(%User{} = user) do
|
defp user_to_map(%User{} = user) do
|
||||||
user
|
user
|
||||||
|> Map.from_struct()
|
|> Map.from_struct()
|
||||||
|> Map.take([:id, :nickname])
|
|> Map.take([:id, :nickname])
|
||||||
|> Map.put(:type, "user")
|
|> Map.new(fn {k, v} -> {Atom.to_string(k), v} end)
|
||||||
|
|> Map.put("type", "user")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp report_to_map(%Activity{} = report) do
|
defp report_to_map(%Activity{} = report) do
|
||||||
%{
|
%{
|
||||||
type: "report",
|
"type" => "report",
|
||||||
id: report.id,
|
"id" => report.id,
|
||||||
state: report.data["state"]
|
"state" => report.data["state"]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp status_to_map(%Activity{} = status) do
|
defp status_to_map(%Activity{} = status) do
|
||||||
%{
|
%{
|
||||||
type: "status",
|
"type" => "status",
|
||||||
id: status.id
|
"id" => status.id
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -338,9 +338,7 @@ defp valid_field?(%{"name" => name, "value" => value}) do
|
||||||
name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255)
|
name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255)
|
||||||
value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255)
|
value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255)
|
||||||
|
|
||||||
is_binary(name) &&
|
is_binary(name) && is_binary(value) && String.length(name) <= name_limit &&
|
||||||
is_binary(value) &&
|
|
||||||
String.length(name) <= name_limit &&
|
|
||||||
String.length(value) <= value_limit
|
String.length(value) <= value_limit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -556,7 +556,15 @@ def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
def list_log(conn, params) do
|
def list_log(conn, params) do
|
||||||
{page, page_size} = page_params(params)
|
{page, page_size} = page_params(params)
|
||||||
|
|
||||||
log = ModerationLog.get_all(page, page_size)
|
log =
|
||||||
|
ModerationLog.get_all(%{
|
||||||
|
page: page,
|
||||||
|
page_size: page_size,
|
||||||
|
start_date: params["start_date"],
|
||||||
|
end_date: params["end_date"],
|
||||||
|
user_id: params["user_id"],
|
||||||
|
search: params["search"]
|
||||||
|
})
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(ModerationLogView)
|
|> put_view(ModerationLogView)
|
||||||
|
|
|
@ -8,7 +8,10 @@ defmodule Pleroma.Web.AdminAPI.ModerationLogView do
|
||||||
alias Pleroma.ModerationLog
|
alias Pleroma.ModerationLog
|
||||||
|
|
||||||
def render("index.json", %{log: log}) do
|
def render("index.json", %{log: log}) do
|
||||||
render_many(log, __MODULE__, "show.json", as: :log_entry)
|
%{
|
||||||
|
items: render_many(log.items, __MODULE__, "show.json", as: :log_entry),
|
||||||
|
total: log.count
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("show.json", %{log_entry: log_entry}) do
|
def render("show.json", %{log_entry: log_entry}) do
|
||||||
|
|
|
@ -30,8 +30,7 @@ test "logging user deletion by moderator", %{moderator: moderator, subject1: sub
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] == "@#{moderator.nickname} deleted user @#{subject1.nickname}"
|
||||||
"@#{moderator.nickname} deleted user @#{subject1.nickname}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logging user creation by moderator", %{
|
test "logging user creation by moderator", %{
|
||||||
|
@ -48,7 +47,7 @@ test "logging user creation by moderator", %{
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} created users: @#{subject1.nickname}, @#{subject2.nickname}"
|
"@#{moderator.nickname} created users: @#{subject1.nickname}, @#{subject2.nickname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,7 +62,7 @@ test "logging user follow by admin", %{admin: admin, subject1: subject1, subject
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{admin.nickname} made @#{subject2.nickname} follow @#{subject1.nickname}"
|
"@#{admin.nickname} made @#{subject2.nickname} follow @#{subject1.nickname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -78,7 +77,7 @@ test "logging user unfollow by admin", %{admin: admin, subject1: subject1, subje
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{admin.nickname} made @#{subject2.nickname} unfollow @#{subject1.nickname}"
|
"@#{admin.nickname} made @#{subject2.nickname} unfollow @#{subject1.nickname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -100,8 +99,7 @@ test "logging user tagged by admin", %{admin: admin, subject1: subject1, subject
|
||||||
|
|
||||||
tags = ["foo", "bar"] |> Enum.join(", ")
|
tags = ["foo", "bar"] |> Enum.join(", ")
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] == "@#{admin.nickname} added tags: #{tags} to users: #{users}"
|
||||||
"@#{admin.nickname} added tags: #{tags} to users: #{users}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logging user untagged by admin", %{admin: admin, subject1: subject1, subject2: subject2} do
|
test "logging user untagged by admin", %{admin: admin, subject1: subject1, subject2: subject2} do
|
||||||
|
@ -122,7 +120,7 @@ test "logging user untagged by admin", %{admin: admin, subject1: subject1, subje
|
||||||
|
|
||||||
tags = ["foo", "bar"] |> Enum.join(", ")
|
tags = ["foo", "bar"] |> Enum.join(", ")
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{admin.nickname} removed tags: #{tags} from users: #{users}"
|
"@#{admin.nickname} removed tags: #{tags} from users: #{users}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,8 +135,7 @@ test "logging user grant by moderator", %{moderator: moderator, subject1: subjec
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] == "@#{moderator.nickname} made @#{subject1.nickname} moderator"
|
||||||
"@#{moderator.nickname} made @#{subject1.nickname} moderator"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logging user revoke by moderator", %{moderator: moderator, subject1: subject1} do
|
test "logging user revoke by moderator", %{moderator: moderator, subject1: subject1} do
|
||||||
|
@ -152,7 +149,7 @@ test "logging user revoke by moderator", %{moderator: moderator, subject1: subje
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} revoked moderator role from @#{subject1.nickname}"
|
"@#{moderator.nickname} revoked moderator role from @#{subject1.nickname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -166,7 +163,7 @@ test "logging relay follow", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} followed relay: https://example.org/relay"
|
"@#{moderator.nickname} followed relay: https://example.org/relay"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -180,7 +177,7 @@ test "logging relay unfollow", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} unfollowed relay: https://example.org/relay"
|
"@#{moderator.nickname} unfollowed relay: https://example.org/relay"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -202,7 +199,7 @@ test "logging report update", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} updated report ##{report.id} with 'resolved' state"
|
"@#{moderator.nickname} updated report ##{report.id} with 'resolved' state"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -224,7 +221,7 @@ test "logging report response", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
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}"
|
"@#{moderator.nickname} responded with 'look at this' to report ##{report.id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -242,7 +239,7 @@ test "logging status sensitivity update", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true'"
|
"@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true'"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -260,7 +257,7 @@ test "logging status visibility update", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] ==
|
||||||
"@#{moderator.nickname} updated status ##{note.id}, set visibility: 'private'"
|
"@#{moderator.nickname} updated status ##{note.id}, set visibility: 'private'"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -278,7 +275,7 @@ test "logging status sensitivity & visibility update", %{moderator: moderator} d
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
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'"
|
"@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true', visibility: 'private'"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -294,8 +291,7 @@ test "logging status deletion", %{moderator: moderator} do
|
||||||
|
|
||||||
log = Repo.one(ModerationLog)
|
log = Repo.one(ModerationLog)
|
||||||
|
|
||||||
assert ModerationLog.get_log_entry_message(log) ==
|
assert log.data["message"] == "@#{moderator.nickname} deleted status ##{note.id}"
|
||||||
"@#{moderator.nickname} deleted status ##{note.id}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2257,8 +2257,9 @@ test "returns private statuses with godmode on", %{conn: conn, user: user} do
|
||||||
describe "GET /api/pleroma/admin/moderation_log" do
|
describe "GET /api/pleroma/admin/moderation_log" do
|
||||||
setup %{conn: conn} do
|
setup %{conn: conn} do
|
||||||
admin = insert(:user, info: %{is_admin: true})
|
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
|
end
|
||||||
|
|
||||||
test "returns the log", %{conn: conn, admin: admin} do
|
test "returns the log", %{conn: conn, admin: admin} do
|
||||||
|
@ -2291,9 +2292,9 @@ test "returns the log", %{conn: conn, admin: admin} do
|
||||||
conn = get(conn, "/api/pleroma/admin/moderation_log")
|
conn = get(conn, "/api/pleroma/admin/moderation_log")
|
||||||
|
|
||||||
response = json_response(conn, 200)
|
response = json_response(conn, 200)
|
||||||
[first_entry, second_entry] = response
|
[first_entry, second_entry] = response["items"]
|
||||||
|
|
||||||
assert response |> length() == 2
|
assert response["total"] == 2
|
||||||
assert first_entry["data"]["action"] == "relay_unfollow"
|
assert first_entry["data"]["action"] == "relay_unfollow"
|
||||||
|
|
||||||
assert first_entry["message"] ==
|
assert first_entry["message"] ==
|
||||||
|
@ -2335,9 +2336,10 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do
|
||||||
conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
|
conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
|
||||||
|
|
||||||
response1 = json_response(conn1, 200)
|
response1 = json_response(conn1, 200)
|
||||||
[first_entry] = response1
|
[first_entry] = response1["items"]
|
||||||
|
|
||||||
assert response1 |> length() == 1
|
assert response1["total"] == 2
|
||||||
|
assert response1["items"] |> length() == 1
|
||||||
assert first_entry["data"]["action"] == "relay_unfollow"
|
assert first_entry["data"]["action"] == "relay_unfollow"
|
||||||
|
|
||||||
assert first_entry["message"] ==
|
assert first_entry["message"] ==
|
||||||
|
@ -2346,14 +2348,119 @@ test "returns the log with pagination", %{conn: conn, admin: admin} do
|
||||||
conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
|
conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
|
||||||
|
|
||||||
response2 = json_response(conn2, 200)
|
response2 = json_response(conn2, 200)
|
||||||
[second_entry] = response2
|
[second_entry] = response2["items"]
|
||||||
|
|
||||||
assert response2 |> length() == 1
|
assert response2["total"] == 2
|
||||||
|
assert response2["items"] |> length() == 1
|
||||||
assert second_entry["data"]["action"] == "relay_follow"
|
assert second_entry["data"]["action"] == "relay_follow"
|
||||||
|
|
||||||
assert second_entry["message"] ==
|
assert second_entry["message"] ==
|
||||||
"@#{admin.nickname} followed relay: https://example.org/relay"
|
"@#{admin.nickname} followed relay: https://example.org/relay"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "filters log by date", %{conn: conn, admin: admin} do
|
||||||
|
first_date = "2017-08-15T15:47:06Z"
|
||||||
|
second_date = "2017-08-20T15:47:06Z"
|
||||||
|
|
||||||
|
Repo.insert(%ModerationLog{
|
||||||
|
data: %{
|
||||||
|
actor: %{
|
||||||
|
"id" => admin.id,
|
||||||
|
"nickname" => admin.nickname,
|
||||||
|
"type" => "user"
|
||||||
|
},
|
||||||
|
action: "relay_follow",
|
||||||
|
target: "https://example.org/relay"
|
||||||
|
},
|
||||||
|
inserted_at: NaiveDateTime.from_iso8601!(first_date)
|
||||||
|
})
|
||||||
|
|
||||||
|
Repo.insert(%ModerationLog{
|
||||||
|
data: %{
|
||||||
|
actor: %{
|
||||||
|
"id" => admin.id,
|
||||||
|
"nickname" => admin.nickname,
|
||||||
|
"type" => "user"
|
||||||
|
},
|
||||||
|
action: "relay_unfollow",
|
||||||
|
target: "https://example.org/relay"
|
||||||
|
},
|
||||||
|
inserted_at: NaiveDateTime.from_iso8601!(second_date)
|
||||||
|
})
|
||||||
|
|
||||||
|
conn1 =
|
||||||
|
get(
|
||||||
|
conn,
|
||||||
|
"/api/pleroma/admin/moderation_log?start_date=#{second_date}"
|
||||||
|
)
|
||||||
|
|
||||||
|
response1 = json_response(conn1, 200)
|
||||||
|
[first_entry] = response1["items"]
|
||||||
|
|
||||||
|
assert response1["total"] == 1
|
||||||
|
assert first_entry["data"]["action"] == "relay_unfollow"
|
||||||
|
|
||||||
|
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["items"]
|
||||||
|
|
||||||
|
assert response1["total"] == 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["items"]
|
||||||
|
|
||||||
|
assert response1["total"] == 1
|
||||||
|
|
||||||
|
assert get_in(first_entry, ["data", "message"]) ==
|
||||||
|
"@#{moderator.nickname} unfollowed relay: https://example.org/relay"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "PATCH /users/:nickname/force_password_reset" do
|
describe "PATCH /users/:nickname/force_password_reset" do
|
||||||
|
|
Loading…
Reference in New Issue