Merge pull request 'Fix email sync (user->member) when changing password and email' (#380) from fix/email_sync into main
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #380
This commit is contained in:
moritz 2026-01-27 18:08:06 +01:00
commit 4e8e697490
2 changed files with 42 additions and 0 deletions

View file

@ -194,6 +194,11 @@ defmodule Mv.Accounts.User do
# Use the official Ash Authentication password change # Use the official Ash Authentication password change
change AshAuthentication.Strategy.Password.HashPasswordChange change AshAuthentication.Strategy.Password.HashPasswordChange
# Sync email changes to linked member when email is changed (e.g. form changes both)
change Mv.EmailSync.Changes.SyncUserEmailToMember do
where [changing(:email)]
end
end end
# Action to link an OIDC account to an existing password-only user # Action to link an OIDC account to an existing password-only user

View file

@ -120,6 +120,43 @@ defmodule Mv.Accounts.UserEmailSyncTest do
{:ok, member_after_unlink} = Ash.get(Mv.Membership.Member, member.id, actor: actor) {:ok, member_after_unlink} = Ash.get(Mv.Membership.Member, member.id, actor: actor)
assert member_after_unlink.email == "user@example.com" assert member_after_unlink.email == "user@example.com"
end end
test "admin_set_password with email change syncs to linked member", %{actor: actor} do
# Create member and user linked to it (with password so admin_set_password applies)
{:ok, member} = Membership.create_member(@valid_member_attrs, actor: actor)
{:ok, user} =
Mv.Accounts.User
|> Ash.Changeset.for_create(:register_with_password, %{
email: "user@example.com",
password: "initialpass123"
})
|> Ash.create(actor: actor)
{:ok, user} =
user
|> Ash.Changeset.for_update(:update_user, %{member: %{id: member.id}})
|> Ash.update(actor: actor)
assert user.member_id == member.id
{:ok, m} = Ash.get(Mv.Membership.Member, member.id, actor: actor)
assert m.email == "user@example.com"
# Change both email and password via admin_set_password (e.g. user form "Change Password")
{:ok, updated_user} =
user
|> Ash.Changeset.for_update(:admin_set_password, %{
email: "newemail@example.com",
password: "newpassword123"
})
|> Ash.update(actor: actor)
assert to_string(updated_user.email) == "newemail@example.com"
# Member email must be synced (Option A: SyncUserEmailToMember on admin_set_password)
{:ok, synced_member} = Ash.get(Mv.Membership.Member, member.id, actor: actor)
assert synced_member.email == "newemail@example.com"
end
end end
describe "AshAuthentication compatibility" do describe "AshAuthentication compatibility" do