Remove redundant action_type check since validation already runs only on destroy actions. Add field to error for better error handling.
139 lines
3.6 KiB
Elixir
139 lines
3.6 KiB
Elixir
defmodule Mv.Authorization.Role do
|
|
@moduledoc """
|
|
Represents a user role that references a permission set.
|
|
|
|
Roles are stored in the database and link users to permission sets.
|
|
Each role has a `permission_set_name` that references one of the four
|
|
hardcoded permission sets defined in `Mv.Authorization.PermissionSets`.
|
|
|
|
## Fields
|
|
|
|
- `name` - Unique role name (e.g., "Vorstand", "Admin")
|
|
- `description` - Human-readable description of the role
|
|
- `permission_set_name` - Must be one of: "own_data", "read_only", "normal_user", "admin"
|
|
- `is_system_role` - If true, role cannot be deleted (protects critical roles like "Mitglied")
|
|
|
|
## Relationships
|
|
|
|
- `has_many :users` - Users assigned to this role
|
|
|
|
## Validations
|
|
|
|
- `permission_set_name` must be a valid permission set (checked against PermissionSets.all_permission_sets/0)
|
|
- `name` must be unique
|
|
- System roles cannot be deleted (enforced via validation)
|
|
|
|
## Examples
|
|
|
|
# Create a new role
|
|
{:ok, role} = Mv.Authorization.create_role(%{
|
|
name: "Vorstand",
|
|
description: "Board member with read access",
|
|
permission_set_name: "read_only"
|
|
})
|
|
|
|
# List all roles
|
|
{:ok, roles} = Mv.Authorization.list_roles()
|
|
"""
|
|
use Ash.Resource,
|
|
domain: Mv.Authorization,
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
postgres do
|
|
table "roles"
|
|
repo Mv.Repo
|
|
|
|
references do
|
|
# Prevent deletion of roles that are assigned to users
|
|
reference :users, on_delete: :restrict
|
|
end
|
|
end
|
|
|
|
code_interface do
|
|
define :create_role
|
|
define :list_roles, action: :read
|
|
define :update_role
|
|
define :destroy_role, action: :destroy
|
|
end
|
|
|
|
actions do
|
|
defaults [:read]
|
|
|
|
create :create_role do
|
|
primary? true
|
|
accept [:name, :description, :permission_set_name, :is_system_role]
|
|
# Note: In Ash 3.0, require_atomic? is not available for create actions
|
|
# Custom validations will still work
|
|
end
|
|
|
|
update :update_role do
|
|
primary? true
|
|
accept [:name, :description, :permission_set_name, :is_system_role]
|
|
# Required because custom validation functions cannot be executed atomically
|
|
require_atomic? false
|
|
end
|
|
|
|
destroy :destroy do
|
|
# Required because custom validation functions cannot be executed atomically
|
|
require_atomic? false
|
|
end
|
|
end
|
|
|
|
validations do
|
|
validate one_of(
|
|
:permission_set_name,
|
|
Mv.Authorization.PermissionSets.all_permission_sets()
|
|
|> Enum.map(&Atom.to_string/1)
|
|
),
|
|
message: "must be one of: own_data, read_only, normal_user, admin"
|
|
|
|
validate fn changeset, _context ->
|
|
if changeset.data.is_system_role do
|
|
{:error,
|
|
field: :is_system_role,
|
|
message:
|
|
"Cannot delete system role. System roles are required for the application to function."}
|
|
else
|
|
:ok
|
|
end
|
|
end,
|
|
on: [:destroy]
|
|
end
|
|
|
|
attributes do
|
|
uuid_v7_primary_key :id
|
|
|
|
attribute :name, :string do
|
|
allow_nil? false
|
|
public? true
|
|
end
|
|
|
|
attribute :description, :string do
|
|
allow_nil? true
|
|
public? true
|
|
end
|
|
|
|
attribute :permission_set_name, :string do
|
|
allow_nil? false
|
|
public? true
|
|
end
|
|
|
|
attribute :is_system_role, :boolean do
|
|
allow_nil? false
|
|
default false
|
|
public? true
|
|
end
|
|
|
|
timestamps()
|
|
end
|
|
|
|
relationships do
|
|
has_many :users, Mv.Accounts.User do
|
|
destination_attribute :role_id
|
|
end
|
|
end
|
|
|
|
identities do
|
|
identity :unique_name, [:name]
|
|
end
|
|
end
|