Skip to content

Commit e441344

Browse files
authored
fix(auth): allow invited users to confirm accounts (#37)
Fixes #36.
1 parent 510b369 commit e441344

2 files changed

Lines changed: 73 additions & 1 deletion

File tree

lib/craftplan_web/router.ex

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ defmodule CraftplanWeb.Router do
88
# Plugs
99
#
1010
# Content Security Policy compatible with LiveView and topbar
11+
alias Craftplan.Accounts.User
12+
1113
@csp Enum.join(
1214
[
1315
"default-src 'self'",
@@ -65,7 +67,17 @@ defmodule CraftplanWeb.Router do
6567
live "/setup", SetupLive, :index
6668

6769
# Authentication Routes
68-
auth_routes AuthController, Craftplan.Accounts.User, path: "/auth"
70+
confirm_route User,
71+
:confirm_new_user,
72+
path: "/auth/user/confirm_new_user",
73+
token_as_route_param?: false,
74+
auth_routes_prefix: "/auth",
75+
overrides: [
76+
CraftplanWeb.AuthOverrides,
77+
Default
78+
]
79+
80+
auth_routes AuthController, User, path: "/auth"
6981
sign_out_route AuthController
7082

7183
sign_in_route register_path: "/register",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
defmodule CraftplanWeb.AuthConfirmationControllerTest do
2+
use CraftplanWeb.ConnCase, async: true
3+
4+
alias Craftplan.Accounts
5+
alias Craftplan.Test.AuthHelpers
6+
7+
for role <- [:staff, :admin] do
8+
@role role
9+
10+
test "invited #{role} users can confirm their accounts from the emailed link", %{conn: conn} do
11+
inviting_admin = AuthHelpers.register_user!(role: :admin)
12+
assert_receive {:email, _inviting_admin_confirmation}
13+
14+
email_address = "invited-#{@role}+#{System.unique_integer([:positive])}@test.com"
15+
16+
assert {:ok, invited_user} =
17+
Accounts.invite_member(
18+
%{email: email_address, role: @role},
19+
actor: inviting_admin
20+
)
21+
22+
assert is_nil(invited_user.confirmed_at)
23+
assert_receive {:email, confirmation_email}
24+
25+
assert [confirmation_url] =
26+
Regex.run(~r/href="([^"]+)"/, confirmation_email.html_body, capture: :all_but_first)
27+
28+
uri = URI.parse(confirmation_url)
29+
confirmation_path = uri.path <> "?" <> uri.query
30+
31+
conn = get(conn, confirmation_path)
32+
document = conn |> html_response(200) |> LazyHTML.from_document()
33+
confirmation_form = LazyHTML.query(document, "form[action='/auth/user/confirm_new_user']")
34+
35+
assert ["post"] = LazyHTML.attribute(confirmation_form, "method")
36+
37+
assert [csrf_token] =
38+
confirmation_form
39+
|> LazyHTML.query("input[name='_csrf_token']")
40+
|> LazyHTML.attribute("value")
41+
42+
assert [confirmation_token] =
43+
confirmation_form
44+
|> LazyHTML.query("input[name='user[confirm]']")
45+
|> LazyHTML.attribute("value")
46+
47+
conn =
48+
post(conn, "/auth/user/confirm_new_user", %{
49+
"_csrf_token" => csrf_token,
50+
"user" => %{"confirm" => confirmation_token}
51+
})
52+
53+
assert redirected_to(conn) == ~p"/manage/overview"
54+
55+
assert {:ok, confirmed_user} = Accounts.get_user_by_email(email_address, authorize?: false)
56+
assert %DateTime{} = confirmed_user.confirmed_at
57+
assert confirmed_user.role == @role
58+
end
59+
end
60+
end

0 commit comments

Comments
 (0)