feat: relate user and member

This commit is contained in:
Moritz 2025-08-05 17:17:28 +02:00
parent b7f0060358
commit d4c7af558d
Signed by: moritz
GPG key ID: 1020A035E5DD0824
8 changed files with 167 additions and 12 deletions

View file

@ -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

View file

@ -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,16 @@ defmodule Mv.Accounts.User do
defaults [:read, :create, :destroy, :update]
create :create_user do
accept [:email]
accept [:email, :member_id]
argument :member, :map
change manage_relationship(:member, type: :create)
end
update :update_user do
accept [:email]
require_atomic? false
accept [:email, :member_id]
argument :member, :map
change manage_relationship(:member, on_match: :update, on_no_match: :create)
end
# Admin action for direct password changes in admin panel
@ -152,6 +158,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

View file

@ -0,0 +1,43 @@
defmodule Mv.Accounts.User.MemberCreationNotifier do
@moduledoc """
Notifier that automatically creates a member for users who don't have one.
This ensures that every user has an associated member profile.
"""
use Ash.Notifier
def notify(%Ash.Notifier.Notification{
action: %{name: action_name},
resource: Mv.Accounts.User,
data: user
})
when action_name in [:create_user, :register_with_password] do
# Only create member if user doesn't have one
if is_nil(user.member_id) do
create_member_for_user(user)
else
:ok
end
end
def notify(_), do: :ok
defp create_member_for_user(user) do
member_attrs = %{
first_name: "User",
last_name: "Generated",
member_email: user.email
}
case Mv.Membership.create_member(member_attrs) do
{:ok, member} ->
# Update the user with the new member_id
Mv.Accounts.update_user(user, %{member_id: member.id})
{:error, _error} ->
# Log error but don't fail the user creation
# In a real application, you might want to handle this differently
:ok
end
end
end