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.action_type == :destroy do if changeset.data.is_system_role do {:error, message: "Cannot delete system role. System roles are required for the application to function."} else :ok end 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