mitgliederverwaltung/lib/mv_web/live/role_live/index.ex
Moritz 303b81d37d refactor: reduce nesting depth in RoleLive.Index.mount
Extract role loading logic into separate private functions to fix Credo warning about nested function body.
2026-01-06 23:57:57 +01:00

101 lines
2.7 KiB
Elixir

defmodule MvWeb.RoleLive.Index do
@moduledoc """
LiveView for displaying and managing the role list.
## Features
- List all roles with name, description, permission_set_name, is_system_role
- Create new roles
- Navigate to role details and edit forms
- Delete non-system roles
## Events
- `delete` - Remove a role from the database (only non-system roles)
## Security
Only admins can access this page (enforced by authorization).
"""
use MvWeb, :live_view
alias Mv.Authorization
@impl true
def mount(_params, _session, socket) do
socket = ensure_user_role_loaded(socket)
roles = load_roles()
{:ok,
socket
|> assign(:page_title, gettext("Listing Roles"))
|> assign(:roles, roles)}
end
defp ensure_user_role_loaded(socket) do
if socket.assigns[:current_user] do
user = socket.assigns.current_user
user_with_role = load_user_role(user)
assign(socket, :current_user, user_with_role)
else
socket
end
end
defp load_user_role(user) do
case Map.get(user, :role) do
%Ash.NotLoaded{} -> load_role_safely(user)
nil -> load_role_safely(user)
_role -> user
end
end
defp load_role_safely(user) do
case Ash.load(user, :role, domain: Mv.Accounts) do
{:ok, loaded_user} -> loaded_user
{:error, _} -> user
end
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
{:ok, role} = Authorization.get_role(id)
case Authorization.destroy_role(role) do
:ok ->
updated_roles = Enum.reject(socket.assigns.roles, &(&1.id == id))
{:noreply,
socket
|> assign(:roles, updated_roles)
|> put_flash(:info, gettext("Role deleted successfully"))}
{:error, error} ->
error_message = format_error(error)
{:noreply,
put_flash(
socket,
:error,
gettext("Failed to delete role: %{error}", error: error_message)
)}
end
end
defp load_roles do
case Authorization.list_roles() do
{:ok, roles} -> Enum.sort_by(roles, & &1.name)
{:error, _} -> []
end
end
defp format_error(%Ash.Error.Invalid{} = error) do
Enum.map_join(error.errors, ", ", fn e -> e.message end)
end
defp format_error(error) when is_binary(error), do: error
defp format_error(_error), do: gettext("An error occurred")
defp permission_set_badge_class("own_data"), do: "badge badge-neutral badge-sm"
defp permission_set_badge_class("read_only"), do: "badge badge-info badge-sm"
defp permission_set_badge_class("normal_user"), do: "badge badge-success badge-sm"
defp permission_set_badge_class("admin"), do: "badge badge-error badge-sm"
defp permission_set_badge_class(_), do: "badge badge-ghost badge-sm"
end