feat: add approval ui for join requests
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Simon 2026-03-11 02:04:03 +01:00
parent 50433e607f
commit 86d9242d83
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2
22 changed files with 1624 additions and 12 deletions

View file

@ -38,6 +38,7 @@ defmodule Mv.Membership.JoinRequestApprovalDomainTest do
assert member_count() == count_before + 1
request_email = request.email
[member] =
Member
|> Ash.Query.filter(expr(^ref(:email) == ^request_email))
@ -56,6 +57,7 @@ defmodule Mv.Membership.JoinRequestApprovalDomainTest do
# No User should exist with this email from the approval flow
request_email = request.email
users_with_email =
Mv.Accounts.User
|> Ash.Query.filter(expr(^ref(:email) == ^request_email))
@ -99,10 +101,12 @@ defmodule Mv.Membership.JoinRequestApprovalDomainTest do
test "approve when status is pending_confirmation returns error" do
token = "pending-token-#{System.unique_integer([:positive])}"
attrs = %{
email: "pending#{System.unique_integer([:positive])}@example.com",
confirmation_token: token
}
{:ok, request} = Membership.submit_join_request(attrs, actor: nil)
assert request.status == :pending_confirmation
@ -120,6 +124,36 @@ defmodule Mv.Membership.JoinRequestApprovalDomainTest do
end
describe "approve_join_request/2 defaults" do
setup do
# Create a fee type and set it as the default in settings so SetDefaultMembershipFeeType
# can assign it when a member is created from a join request (no fee type in form_data).
actor = SystemActor.get_system_actor()
{:ok, fee_type} =
Ash.create(
Mv.MembershipFees.MembershipFeeType,
%{
name: "Default Test Fee Type #{System.unique_integer([:positive])}",
amount: Decimal.new("50.00"),
interval: :yearly
},
actor: actor,
domain: Mv.MembershipFees
)
{:ok, settings} = Membership.get_settings()
settings
|> Ash.Changeset.for_update(
:update_membership_fee_settings,
%{default_membership_fee_type_id: fee_type.id},
actor: actor
)
|> Ash.update!(actor: actor)
:ok
end
test "created member has join_date and membership_fee_type when not in form_data" do
request = Fixtures.submitted_join_request_fixture()
user = Fixtures.user_with_role_fixture("normal_user")
@ -127,6 +161,7 @@ defmodule Mv.Membership.JoinRequestApprovalDomainTest do
assert {:ok, _} = Membership.approve_join_request(request.id, actor: user)
request_email = request.email
[member] =
Member
|> Ash.Query.filter(expr(^ref(:email) == ^request_email))

View file

@ -59,12 +59,14 @@ defmodule Mv.Membership.JoinRequestApprovalPolicyTest do
test "read_only cannot approve", %{request: request} do
user = Fixtures.user_with_role_fixture("read_only")
assert {:error, %Ash.Error.Forbidden{}} =
Membership.approve_join_request(request.id, actor: user)
end
test "own_data cannot approve", %{request: request} do
user = Fixtures.user_with_role_fixture("own_data")
assert {:error, %Ash.Error.Forbidden{}} =
Membership.approve_join_request(request.id, actor: user)
end
@ -97,12 +99,14 @@ defmodule Mv.Membership.JoinRequestApprovalPolicyTest do
test "read_only cannot reject", %{request: request} do
user = Fixtures.user_with_role_fixture("read_only")
assert {:error, %Ash.Error.Forbidden{}} =
Membership.reject_join_request(request.id, actor: user)
end
test "own_data cannot reject", %{request: request} do
user = Fixtures.user_with_role_fixture("own_data")
assert {:error, %Ash.Error.Forbidden{}} =
Membership.reject_join_request(request.id, actor: user)
end

View file

@ -813,13 +813,21 @@ defmodule MvWeb.Plugs.CheckPagePermissionTest do
end
end
# normal_user (Kassenwart): allowed /, /members, /members/new, /members/:id, /members/:id/edit, /groups, /groups/:slug, /join_requests
# normal_user (Kassenwart): allowed /, /members, /members/new, /members/:id, /members/:id/edit,
# /groups, /groups/:slug, /join_requests (only when join form is enabled in settings)
describe "integration: normal_user (Kassenwart) allowed paths via full router" do
setup %{conn: conn, current_user: current_user} do
member = Mv.Fixtures.member_fixture()
group = Mv.Fixtures.group_fixture()
join_request = Fixtures.submitted_join_request_fixture()
# Enable join form so /join_requests and /join_requests/:id return 200 (not redirect)
{:ok, settings} = Mv.Membership.get_settings()
if settings do
Mv.Membership.update_settings(settings, %{join_form_enabled: true})
end
{:ok,
conn: conn,
current_user: current_user,

View file

@ -323,10 +323,12 @@ defmodule Mv.Fixtures do
"""
def submitted_join_request_fixture(attrs \\ %{}) do
token = "fixture-token-#{System.unique_integer([:positive])}"
base = %{
email: "join#{System.unique_integer([:positive])}@example.com",
confirmation_token: token
}
attrs = base |> Map.merge(attrs) |> Map.put(:confirmation_token, token)
{:ok, _} = Membership.submit_join_request(attrs, actor: nil)