Merge remote-tracking branch 'origin/main' into feature/372-groups-management
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
3eb4cde0b7
17 changed files with 330 additions and 38 deletions
|
|
@ -120,6 +120,43 @@ defmodule Mv.Accounts.UserEmailSyncTest do
|
|||
{:ok, member_after_unlink} = Ash.get(Mv.Membership.Member, member.id, actor: actor)
|
||||
assert member_after_unlink.email == "user@example.com"
|
||||
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
|
||||
|
||||
describe "AshAuthentication compatibility" do
|
||||
|
|
|
|||
|
|
@ -10,6 +10,14 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|
||||
require Ash.Query
|
||||
|
||||
# Deletes a user row directly via SQL, bypassing Ash validations.
|
||||
# Use only in tests when setting up "no system user" / "no users" scenarios;
|
||||
# Ash.destroy! forbids deleting the system actor user.
|
||||
defp delete_user_bypass_ash(user) do
|
||||
id = Ecto.UUID.dump!(user.id)
|
||||
Ecto.Adapters.SQL.query!(Mv.Repo, "DELETE FROM users WHERE id = $1", [id])
|
||||
end
|
||||
|
||||
# Helper function to ensure admin role exists
|
||||
defp ensure_admin_role do
|
||||
case Authorization.list_roles() do
|
||||
|
|
@ -49,7 +57,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.read_one(domain: Mv.Accounts, authorize?: false) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
user
|
||||
|> Ash.Changeset.for_update(:update, %{})
|
||||
|> Ash.Changeset.for_update(:update_internal, %{})
|
||||
|> Ash.Changeset.manage_relationship(:role, admin_role, type: :append_and_remove)
|
||||
|> Ash.update!(authorize?: false)
|
||||
|> Ash.load!(:role, domain: Mv.Accounts, authorize?: false)
|
||||
|
|
@ -60,7 +68,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
upsert_identity: :unique_email,
|
||||
authorize?: false
|
||||
)
|
||||
|> Ash.Changeset.for_update(:update, %{})
|
||||
|> Ash.Changeset.for_update(:update_internal, %{})
|
||||
|> Ash.Changeset.manage_relationship(:role, admin_role, type: :append_and_remove)
|
||||
|> Ash.update!(authorize?: false)
|
||||
|> Ash.load!(:role, domain: Mv.Accounts, authorize?: false)
|
||||
|
|
@ -124,7 +132,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^"system@mila.local")
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -163,7 +171,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^"system@mila.local")
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -177,7 +185,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^admin_email)
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -227,7 +235,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^"system@mila.local")
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -241,7 +249,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^admin_email)
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -275,7 +283,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^"system@mila.local")
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -314,7 +322,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^"system@mila.local")
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -328,7 +336,7 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|> Ash.Query.filter(email == ^admin_email)
|
||||
|> Ash.read_one(domain: Mv.Accounts, actor: system_actor) do
|
||||
{:ok, user} when not is_nil(user) ->
|
||||
Ash.destroy!(user, domain: Mv.Accounts, actor: system_actor)
|
||||
delete_user_bypass_ash(user)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
|
|
@ -365,9 +373,9 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
|
||||
# Assign wrong role to system user
|
||||
# Assign wrong role to system user (use :update_internal so bootstrap-style update is allowed)
|
||||
system_user
|
||||
|> Ash.Changeset.for_update(:update, %{})
|
||||
|> Ash.Changeset.for_update(:update_internal, %{})
|
||||
|> Ash.Changeset.manage_relationship(:role, read_only_role, type: :append_and_remove)
|
||||
|> Ash.update!(actor: system_actor)
|
||||
|
||||
|
|
|
|||
|
|
@ -154,4 +154,14 @@ defmodule MvWeb.UserLive.ShowTest do
|
|||
assert html =~ gettext("Show User") || html =~ to_string(user.email)
|
||||
end
|
||||
end
|
||||
|
||||
describe "system actor user" do
|
||||
test "redirects to user list when viewing system actor user", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
conn = conn_with_oidc_user(conn)
|
||||
|
||||
assert {:error, {:live_redirect, %{to: "/users"}}} =
|
||||
live(conn, ~p"/users/#{system_actor.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -420,4 +420,14 @@ defmodule MvWeb.UserLive.FormTest do
|
|||
assert is_nil(updated_user.member)
|
||||
end
|
||||
end
|
||||
|
||||
describe "system actor user" do
|
||||
test "redirects to user list when editing system actor user", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
conn = conn_with_oidc_user(conn, %{email: "admin@example.com"})
|
||||
|
||||
assert {:error, {:live_redirect, %{to: "/users"}}} =
|
||||
live(conn, "/users/#{system_actor.id}/edit")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -405,6 +405,27 @@ defmodule MvWeb.UserLive.IndexTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "system actor user" do
|
||||
test "does not show system actor user in list", %{conn: conn} do
|
||||
# Ensure system actor exists (e.g. via get_system_actor in conn_with_oidc_user)
|
||||
_system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
system_email = Mv.Helpers.SystemActor.system_user_email()
|
||||
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, _view, html} = live(conn, "/users")
|
||||
|
||||
refute html =~ system_email,
|
||||
"System actor user (#{system_email}) must not appear in the user list"
|
||||
end
|
||||
|
||||
test "destroying system actor user returns error", %{current_user: current_user} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
assert {:error, %Ash.Error.Invalid{}} =
|
||||
Ash.destroy(system_actor, domain: Mv.Accounts, actor: current_user)
|
||||
end
|
||||
end
|
||||
|
||||
describe "member linking display" do
|
||||
test "displays linked member name in user list", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue