Seed Data - Roles and Default Assignment closes #365 #368
1 changed files with 46 additions and 14 deletions
|
|
@ -68,12 +68,9 @@ defmodule Mv.Accounts.User do
|
||||||
hash_provider AshAuthentication.BcryptProvider
|
hash_provider AshAuthentication.BcryptProvider
|
||||||
confirmation_required? false
|
confirmation_required? false
|
||||||
|
|
||||||
# NOTE: The auto-generated :register_with_password action does NOT assign a default role.
|
resettable do
|
||||||
# This is intentional because:
|
sender Mv.Accounts.User.Senders.SendPasswordResetEmail
|
||||||
# - In production, users are created via OIDC (:register_with_rauthy), which DOES assign roles
|
end
|
||||||
# - Manual user creation via :create_user DOES assign roles
|
|
||||||
# - Tests that need a role can use :create_user or manually assign via fixtures
|
|
||||||
# - The migration ensures existing users without roles get the "Mitglied" role
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -122,8 +119,7 @@ defmodule Mv.Accounts.User do
|
||||||
argument :member, :map, allow_nil?: true
|
argument :member, :map, allow_nil?: true
|
||||||
upsert? true
|
upsert? true
|
||||||
|
|
||||||
# Assign default "Mitglied" role to new users
|
# Note: Default role is automatically assigned via attribute default (see attributes block)
|
||||||
change Mv.Accounts.User.Changes.AssignDefaultRole
|
|
||||||
|
|
||||||
# Manage the member relationship during user creation
|
# Manage the member relationship during user creation
|
||||||
change manage_relationship(:member, :member,
|
change manage_relationship(:member, :member,
|
||||||
|
|
@ -273,9 +269,8 @@ defmodule Mv.Accounts.User do
|
||||||
# - The LinkOidcAccountLive will auto-link passwordless users without password prompt
|
# - The LinkOidcAccountLive will auto-link passwordless users without password prompt
|
||||||
validate Mv.Accounts.User.Validations.OidcEmailCollision
|
validate Mv.Accounts.User.Validations.OidcEmailCollision
|
||||||
|
|
||||||
# Assign default "Mitglied" role to new OIDC users
|
# Note: Default role is automatically assigned via attribute default (see attributes block)
|
||||||
# Note: upsert_fields [:email] ensures this doesn't overwrite existing users' roles
|
# upsert_fields [:email] ensures existing users' roles are preserved during upserts
|
||||||
change Mv.Accounts.User.Changes.AssignDefaultRole
|
|
||||||
|
|
||||||
# Sync user email to member when linking (User → Member)
|
# Sync user email to member when linking (User → Member)
|
||||||
change Mv.EmailSync.Changes.SyncUserEmailToMember
|
change Mv.EmailSync.Changes.SyncUserEmailToMember
|
||||||
|
|
@ -395,6 +390,15 @@ defmodule Mv.Accounts.User do
|
||||||
|
|
||||||
attribute :hashed_password, :string, sensitive?: true, allow_nil?: true
|
attribute :hashed_password, :string, sensitive?: true, allow_nil?: true
|
||||||
attribute :oidc_id, :string, allow_nil?: true
|
attribute :oidc_id, :string, allow_nil?: true
|
||||||
|
|
||||||
|
# Role assignment: Explicitly defined to enforce default value
|
||||||
|
# This ensures every user has a role, regardless of creation path
|
||||||
|
# (register_with_password, create_user, seeds, etc.)
|
||||||
|
attribute :role_id, :uuid do
|
||||||
|
allow_nil? false
|
||||||
|
default &__MODULE__.default_role_id/0
|
||||||
|
public? false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
relationships do
|
relationships do
|
||||||
|
|
@ -404,10 +408,13 @@ defmodule Mv.Accounts.User do
|
||||||
belongs_to :member, Mv.Membership.Member
|
belongs_to :member, Mv.Membership.Member
|
||||||
|
|
||||||
# 1:1 relationship - User belongs to a Role
|
# 1:1 relationship - User belongs to a Role
|
||||||
# This automatically creates a `role_id` attribute in the User table
|
# We define role_id ourselves (above in attributes) to control default value
|
||||||
# The relationship is optional (allow_nil? true by default)
|
|
||||||
# Foreign key constraint: on_delete: :restrict (prevents deleting roles assigned to users)
|
# Foreign key constraint: on_delete: :restrict (prevents deleting roles assigned to users)
|
||||||
belongs_to :role, Mv.Authorization.Role
|
belongs_to :role, Mv.Authorization.Role do
|
||||||
|
define_attribute? false
|
||||||
|
source_attribute :role_id
|
||||||
|
allow_nil? false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
identities do
|
identities do
|
||||||
|
|
@ -427,4 +434,29 @@ defmodule Mv.Accounts.User do
|
||||||
# forbid_if(always())
|
# forbid_if(always())
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the default role ID for new users.
|
||||||
|
|
||||||
|
This function is called automatically when creating a user without an explicit role_id.
|
||||||
|
It fetches the "Mitglied" role from the database without authorization checks
|
||||||
|
(safe during user creation bootstrap phase).
|
||||||
|
|
||||||
|
## Returns
|
||||||
|
|
||||||
|
- UUID of the "Mitglied" role if it exists
|
||||||
|
- `nil` if the role doesn't exist (will cause validation error due to `allow_nil? false`)
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> Mv.Accounts.User.default_role_id()
|
||||||
|
"019bf2e2-873a-7712-a7ce-a5a1f90c5f4f"
|
||||||
|
"""
|
||||||
|
@spec default_role_id() :: Ecto.UUID.t() | nil
|
||||||
|
def default_role_id do
|
||||||
|
case Mv.Authorization.Role.get_mitglied_role() do
|
||||||
|
{:ok, %Mv.Authorization.Role{id: role_id}} -> role_id
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue