WIP feat: member user relation
This commit is contained in:
parent
ba79261d1d
commit
0dddeeb7a6
35 changed files with 1208 additions and 192 deletions
|
|
@ -21,4 +21,15 @@ defmodule Mv.Accounts do
|
|||
|
||||
resource Mv.Accounts.Token
|
||||
end
|
||||
|
||||
@doc """
|
||||
Register a new user with password using AshAuthentication's standard action.
|
||||
This creates a user and the notifier will automatically create a member.
|
||||
"""
|
||||
def register_with_password(params) do
|
||||
# Use AshAuthentication's standard register_with_password action
|
||||
Mv.Accounts.User
|
||||
|> Ash.Changeset.for_create(:register_with_password, params)
|
||||
|> Ash.create(domain: __MODULE__)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ defmodule Mv.Accounts.User do
|
|||
use Ash.Resource,
|
||||
domain: Mv.Accounts,
|
||||
data_layer: AshPostgres.DataLayer,
|
||||
extensions: [AshAuthentication]
|
||||
extensions: [AshAuthentication],
|
||||
notifiers: [Mv.Accounts.User.MemberCreationNotifier]
|
||||
|
||||
# authorizers: [Ash.Policy.Authorizer]
|
||||
|
||||
|
|
@ -64,11 +65,11 @@ defmodule Mv.Accounts.User do
|
|||
defaults [:read, :create, :destroy, :update]
|
||||
|
||||
create :create_user do
|
||||
accept [:email]
|
||||
accept [:email, :member_id]
|
||||
end
|
||||
|
||||
update :update_user do
|
||||
accept [:email]
|
||||
accept [:email, :member_id]
|
||||
end
|
||||
|
||||
# Admin action for direct password changes in admin panel
|
||||
|
|
@ -121,9 +122,16 @@ defmodule Mv.Accounts.User do
|
|||
|
||||
# Global validations - applied to all relevant actions
|
||||
validations do
|
||||
# Password strength policy: minimum 8 characters for all password-related actions
|
||||
# Password strength policy: minimum 8 characters
|
||||
# Note: register_with_password has built-in AshAuthentication validation, but admin_set_password doesn't
|
||||
validate string_length(:password, min: 8) do
|
||||
where action_is([:register_with_password, :admin_set_password])
|
||||
# Only needed for admin actions, AshAuthentication handles register_with_password
|
||||
where action_is([:admin_set_password])
|
||||
end
|
||||
|
||||
# Email uniqueness for registration actions
|
||||
validate attribute_does_not_equal(:email, nil) do
|
||||
where action_is([:register_with_password, :register_with_rauthy])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -143,6 +151,7 @@ defmodule Mv.Accounts.User do
|
|||
attribute :email, :ci_string, allow_nil?: false, public?: true
|
||||
attribute :hashed_password, :string, sensitive?: true, allow_nil?: true
|
||||
attribute :oidc_id, :string, allow_nil?: true
|
||||
attribute :admin?, :boolean, allow_nil?: false, default: false, public?: true
|
||||
end
|
||||
|
||||
relationships do
|
||||
|
|
@ -152,6 +161,7 @@ defmodule Mv.Accounts.User do
|
|||
identities do
|
||||
identity :unique_email, [:email]
|
||||
identity :unique_oidc_id, [:oidc_id]
|
||||
identity :unique_member_id, [:member_id]
|
||||
end
|
||||
|
||||
# You can customize this if you wish, but this is a safe default that
|
||||
|
|
|
|||
71
lib/accounts/user/member_creation_notifier.ex
Normal file
71
lib/accounts/user/member_creation_notifier.ex
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
defmodule Mv.Accounts.User.MemberCreationNotifier do
|
||||
@moduledoc """
|
||||
Notifier that automatically creates a member for newly registered users.
|
||||
|
||||
This runs after user creation/registration and ensures every user has an associated member.
|
||||
It's designed to work with AshAuthentication without interfering with LiveView integration.
|
||||
"""
|
||||
use Ash.Notifier
|
||||
|
||||
require Logger
|
||||
|
||||
@impl Ash.Notifier
|
||||
def notify(%Ash.Notifier.Notification{
|
||||
action: %{name: action_name},
|
||||
resource: Mv.Accounts.User,
|
||||
data: user
|
||||
})
|
||||
when action_name in [:register_with_password, :register_with_rauthy, :create_user] do
|
||||
# Only create member if user doesn't already have one
|
||||
if should_create_member?(user) do
|
||||
create_member_for_user(user)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
@impl Ash.Notifier
|
||||
def notify(_), do: :ok
|
||||
|
||||
defp should_create_member?(user) do
|
||||
# Check if user has a member_id and if that member actually exists
|
||||
case user.member_id do
|
||||
nil ->
|
||||
true
|
||||
|
||||
member_id ->
|
||||
case Ash.get(Mv.Membership.Member, member_id, domain: Mv.Membership) do
|
||||
{:ok, _member} -> false
|
||||
{:error, _} -> true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp create_member_for_user(user) do
|
||||
member_params = %{
|
||||
email: to_string(user.email),
|
||||
first_name: "User",
|
||||
last_name: "Generated"
|
||||
}
|
||||
|
||||
case Mv.Membership.create_member(member_params) do
|
||||
{:ok, member} ->
|
||||
# Update user with member_id
|
||||
case Ash.Changeset.for_update(user, :update_user, %{member_id: member.id})
|
||||
|> Ash.update(domain: Mv.Accounts) do
|
||||
{:ok, _updated_user} ->
|
||||
Logger.info(
|
||||
"Successfully created and assigned member #{member.id} to user #{user.id}"
|
||||
)
|
||||
|
||||
{:error, error} ->
|
||||
Logger.warning(
|
||||
"Failed to assign member #{member.id} to user #{user.id}: #{inspect(error)}"
|
||||
)
|
||||
end
|
||||
|
||||
{:error, error} ->
|
||||
Logger.warning("Failed to create member for user #{user.id}: #{inspect(error)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue