Fresh repository history for elektrine/tarakan hosted at https://git.elektrine.com/elektrine/tarakan.
112 lines
3.4 KiB
Elixir
112 lines
3.4 KiB
Elixir
defmodule TarakanWeb.AdminLive.Show do
|
|
use TarakanWeb, :live_view
|
|
|
|
alias Tarakan.Accounts
|
|
alias Tarakan.Accounts.Account
|
|
alias Tarakan.Policy
|
|
alias TarakanWeb.AccountAuth
|
|
|
|
@impl true
|
|
def mount(%{"id" => id}, _session, socket) do
|
|
scope = socket.assigns.current_scope
|
|
return_to = ~p"/admin/accounts/#{id}"
|
|
|
|
cond do
|
|
not Policy.allowed?(scope, :administer) ->
|
|
{:ok, unauthorized(socket)}
|
|
|
|
not Accounts.sudo_mode?(scope.account) ->
|
|
{:ok,
|
|
socket
|
|
|> put_flash(:error, "Confirm it's you before changing account authority.")
|
|
|> redirect(to: AccountAuth.reauth_path(return_to))}
|
|
|
|
true ->
|
|
case Accounts.get_account_for_admin(scope, id) do
|
|
{:ok, account} -> {:ok, assign_account(socket, account)}
|
|
{:error, _reason} -> {:ok, unauthorized(socket)}
|
|
end
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("validate", %{"authorization" => params}, socket) do
|
|
form =
|
|
socket.assigns.account
|
|
|> Account.authorization_changeset(params)
|
|
|> Map.put(:action, :validate)
|
|
|> to_form(as: :authorization)
|
|
|
|
{:noreply, assign(socket, :authorization_form, form)}
|
|
end
|
|
|
|
def handle_event("save", %{"authorization" => params}, socket) do
|
|
with_recent_auth(socket, fn ->
|
|
case Accounts.update_authorization(
|
|
socket.assigns.current_scope,
|
|
socket.assigns.account,
|
|
params
|
|
) do
|
|
{:ok, account} ->
|
|
{:noreply,
|
|
socket
|
|
|> assign_account(account)
|
|
|> put_flash(:info, "Authorization updated for @#{account.handle}.")}
|
|
|
|
{:error, :last_admin} ->
|
|
{:noreply,
|
|
socket
|
|
|> assign_invalid_form(params)
|
|
|> put_flash(:error, "The last active administrator cannot be demoted or restricted.")}
|
|
|
|
{:error, %Ecto.Changeset{} = changeset} ->
|
|
{:noreply, assign(socket, :authorization_form, to_form(changeset, as: :authorization))}
|
|
|
|
{:error, _reason} ->
|
|
{:noreply, unauthorized(socket)}
|
|
end
|
|
end)
|
|
end
|
|
|
|
def handle_event(_event, _params, socket), do: {:noreply, socket}
|
|
|
|
# The mount-time sudo check only covers the initial render; a long-lived
|
|
# LiveView can outlast the two-hour window, so mutating events re-check.
|
|
defp with_recent_auth(socket, fun) do
|
|
if Accounts.sudo_mode?(socket.assigns.current_scope.account) do
|
|
fun.()
|
|
else
|
|
return_to = ~p"/admin/accounts/#{socket.assigns.account.id}"
|
|
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:error, "Confirm it's you before changing account authority.")
|
|
|> push_navigate(to: AccountAuth.reauth_path(return_to))}
|
|
end
|
|
end
|
|
|
|
defp assign_account(socket, account) do
|
|
socket
|
|
|> assign(:page_title, "Manage @#{account.handle}")
|
|
|> assign(:account, account)
|
|
|> assign(
|
|
:authorization_form,
|
|
to_form(Account.authorization_changeset(account, %{}), as: :authorization)
|
|
)
|
|
end
|
|
|
|
defp assign_invalid_form(socket, params) do
|
|
changeset =
|
|
socket.assigns.account
|
|
|> Account.authorization_changeset(params)
|
|
|> Ecto.Changeset.add_error(:platform_role, "must leave at least one active administrator")
|
|
|
|
assign(socket, :authorization_form, to_form(changeset, as: :authorization))
|
|
end
|
|
|
|
defp unauthorized(socket) do
|
|
socket
|
|
|> put_flash(:error, "Administrator access is required.")
|
|
|> redirect(to: ~p"/")
|
|
end
|
|
end
|