mirror of
https://github.com/ClaperCo/Claper.git
synced 2026-07-09 20:09:55 +02:00
* Add audit log * Update translation files * Improve Audit queries * Improve Audit.Log schema * Make user auth audit logs async * Relax Flop and Flop Phoenix dep specs * Make Flop.validate!/2 call more robust * Improve a11y and UI for audit log live view * Improve audit_logs indexes * Fix formatting * Fix async_log_action and tests * Add remote_ip * Update translation files
126 lines
2.5 KiB
Elixir
126 lines
2.5 KiB
Elixir
defmodule Claper.Audit do
|
|
@moduledoc """
|
|
The Audit context for tracking actions in the system.
|
|
"""
|
|
|
|
import Ecto.Query, only: [from: 2]
|
|
|
|
alias Claper.{Accounts, Repo}
|
|
alias Claper.Audit.Log
|
|
|
|
@doc """
|
|
Logs an action.
|
|
|
|
## Examples
|
|
|
|
iex> log_action(user, "user.login", %{ip_address: "127.0.0.1"})
|
|
{:ok, %Log{}}
|
|
|
|
iex> log_action(nil, "system.startup", %{})
|
|
{:ok, %Log{}}
|
|
|
|
"""
|
|
def log_action(user, action, metadata \\ %{})
|
|
|
|
def log_action(%Accounts.User{} = user, action, metadata) do
|
|
create_log(%{
|
|
user_id: user.id,
|
|
action: action,
|
|
metadata: metadata
|
|
})
|
|
end
|
|
|
|
def log_action(nil, action, metadata) do
|
|
create_log(%{
|
|
action: action,
|
|
metadata: metadata
|
|
})
|
|
end
|
|
|
|
@doc """
|
|
Logs an action related to a specific resource.
|
|
|
|
## Examples
|
|
|
|
iex> log_resource_action(user, "event.create", "event", 123, %{})
|
|
{:ok, %Log{}}
|
|
|
|
"""
|
|
def log_resource_action(
|
|
%Accounts.User{} = user,
|
|
action,
|
|
resource_type,
|
|
resource_id,
|
|
metadata \\ %{}
|
|
) do
|
|
create_log(%{
|
|
user_id: user.id,
|
|
action: action,
|
|
resource_type: resource_type,
|
|
resource_id: resource_id,
|
|
metadata: metadata
|
|
})
|
|
end
|
|
|
|
@doc """
|
|
Returns a paginated, optionally filtered and sorted, list of audit logs.
|
|
"""
|
|
def list_logs(params \\ %{}) do
|
|
query = from l in Log, left_join: u in assoc(l, :user), as: :user, preload: [user: u]
|
|
Flop.validate_and_run!(query, params, for: Log, replace_invalid_params: true)
|
|
end
|
|
|
|
@doc """
|
|
Returns a list of distinct action types for filtering.
|
|
"""
|
|
def list_action_types do
|
|
from(l in Log,
|
|
distinct: true,
|
|
select: l.action,
|
|
order_by: l.action
|
|
)
|
|
|> Repo.all()
|
|
end
|
|
|
|
@doc """
|
|
Gets a single log.
|
|
|
|
Raises `Ecto.NoResultsError` if the Log does not exist.
|
|
|
|
## Examples
|
|
|
|
iex> get_log!(123)
|
|
%Log{}
|
|
|
|
iex> get_log!(456)
|
|
** (Ecto.NoResultsError)
|
|
|
|
"""
|
|
def get_log!(id) do
|
|
Repo.one!(
|
|
from l in Log, left_join: u in assoc(l, :user), where: l.id == ^id, preload: [user: u]
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Creates a log entry.
|
|
|
|
This is a simple wrapper over a low-level insert. You likely want to use
|
|
`log_action/3` and `log_resource_action/5` instead.
|
|
|
|
## Examples
|
|
|
|
iex> create_log(%{action: "user.login"})
|
|
{:ok, %Log{}}
|
|
|
|
iex> create_log(%{action: nil})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def create_log(attrs \\ %{}) do
|
|
%Log{}
|
|
|> Log.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
end
|