towerops/lib/towerops/admin.ex

199 lines
4.4 KiB
Elixir

defmodule Towerops.Admin do
@moduledoc """
The Admin context for superuser operations.
Provides functions for managing users, organizations, and audit logging.
"""
import Ecto.Query
alias Towerops.Accounts.User
alias Towerops.Admin.AuditLog
alias Towerops.Organizations.Organization
alias Towerops.Repo
## User Management
@doc """
Lists all users in the system with their organizations.
## Options
* `:limit` - Maximum number of users to return (default: 100)
* `:offset` - Number of users to skip (default: 0)
## Examples
iex> list_all_users()
[%User{}, ...]
iex> list_all_users(limit: 50, offset: 100)
[%User{}, ...]
"""
def list_all_users(opts \\ []) do
limit = Keyword.get(opts, :limit, 100)
offset = Keyword.get(opts, :offset, 0)
User
|> order_by([u], desc: u.inserted_at)
|> limit(^limit)
|> offset(^offset)
|> preload(:organizations)
|> Repo.all()
end
@doc """
Returns the total count of users in the system.
## Examples
iex> count_users()
42
"""
def count_users do
Repo.aggregate(User, :count)
end
@doc """
Deletes a user and creates an audit log entry.
## Examples
iex> delete_user(user_id, superuser_id, "127.0.0.1")
{:ok, %User{}}
iex> delete_user(invalid_id, superuser_id, "127.0.0.1")
** (Ecto.NoResultsError)
"""
def delete_user(user_id, superuser_id, ip_address) do
user = Repo.get!(User, user_id)
Repo.transaction(fn ->
# Create audit log before deletion
create_audit_log(%{
action: "user_delete",
superuser_id: superuser_id,
target_user_id: user_id,
metadata: %{email: user.email},
ip_address: ip_address
})
# Delete user (cascades to memberships and tokens)
Repo.delete!(user)
end)
end
## Organization Management
@doc """
Lists all organizations in the system with their memberships.
## Options
* `:limit` - Maximum number of organizations to return (default: 100)
* `:offset` - Number of organizations to skip (default: 0)
## Examples
iex> list_all_organizations()
[%Organization{}, ...]
iex> list_all_organizations(limit: 50, offset: 100)
[%Organization{}, ...]
"""
def list_all_organizations(opts \\ []) do
limit = Keyword.get(opts, :limit, 100)
offset = Keyword.get(opts, :offset, 0)
Organization
|> order_by([o], desc: o.inserted_at)
|> limit(^limit)
|> offset(^offset)
|> preload(memberships: :user)
|> Repo.all()
end
@doc """
Returns the total count of organizations in the system.
## Examples
iex> count_organizations()
15
"""
def count_organizations do
Repo.aggregate(Organization, :count)
end
@doc """
Deletes an organization and creates an audit log entry.
## Examples
iex> delete_organization(org_id, superuser_id, "127.0.0.1")
{:ok, %Organization{}}
iex> delete_organization(invalid_id, superuser_id, "127.0.0.1")
** (Ecto.NoResultsError)
"""
def delete_organization(org_id, superuser_id, ip_address) do
org = Repo.get!(Organization, org_id)
Repo.transaction(fn ->
# Create audit log before deletion
create_audit_log(%{
action: "org_delete",
superuser_id: superuser_id,
target_user_id: nil,
metadata: %{name: org.name, slug: org.slug},
ip_address: ip_address
})
# Delete organization (cascades to memberships, sites, device)
Repo.delete!(org)
end)
end
## Audit Logging
@doc """
Creates an audit log entry.
## Examples
iex> create_audit_log(%{action: "impersonate_start", superuser_id: superuser_id, target_user_id: user_id})
{:ok, %AuditLog{}}
iex> create_audit_log(%{action: "invalid"})
{:error, %Ecto.Changeset{}}
"""
def create_audit_log(attrs) do
%AuditLog{}
|> AuditLog.changeset(attrs)
|> Repo.insert()
end
@doc """
Lists recent audit logs with associated users.
## Options
* `:limit` - Maximum number of logs to return (default: 100)
## Examples
iex> list_audit_logs()
[%AuditLog{}, ...]
iex> list_audit_logs(limit: 50)
[%AuditLog{}, ...]
"""
def list_audit_logs(opts \\ []) do
limit = Keyword.get(opts, :limit, 100)
AuditLog
|> order_by([a], desc: a.inserted_at)
|> limit(^limit)
|> preload([:superuser, :target_user])
|> Repo.all()
end
end