Skip to content

Commit 39f26bb

Browse files
authored
Merge pull request #15 from pow-auth/resend-email-confirmation-link
Resend email confirmation link guide
2 parents a7e9a55 + 5c750ed commit 39f26bb

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
layout: guide
3+
title: "Resend email confirmation link"
4+
date: 2020-03-07 14:23:00 -0700
5+
author: Dan Schultzer
6+
---
7+
8+
You may wish to add a link to the account edit page so users can manually request the confirmation e-mail to be send again in case they didn't receive it the first time.
9+
10+
First add a controller with an action to resend the confirmation e-mail. Create `WEB_PATH/controllers/registration_controller.ex`:
11+
12+
```elixir
13+
defmodule MyAppWeb.RegistrationController do
14+
use MyAppWeb, :controller
15+
16+
def resend_confirmation_email(conn, _params) do
17+
case PowEmailConfirmation.Plug.pending_email_change?(conn) do
18+
true ->
19+
send_confirmation_email(conn)
20+
21+
conn
22+
|> put_flash(:info, "E-mail sent, please check your inbox.")
23+
|> redirect(to: Routes.pow_registration_path(conn, :edit))
24+
25+
false ->
26+
conn
27+
|> put_flash(:info, "E-mail has already been confirmed.")
28+
|> redirect(to: Routes.pow_registration_path(conn, :edit))
29+
end
30+
end
31+
32+
defp send_confirmation_email(conn) do
33+
user = Pow.Plug.current_user(conn)
34+
35+
PowEmailConfirmation.Phoenix.ControllerCallbacks.send_confirmation_email(user, conn)
36+
end
37+
end
38+
```
39+
40+
Update `WEB_PATH/router.ex` with the route (and it should only accessible for authenticated users):
41+
42+
```elixir
43+
defmodule MyAppWeb.Router do
44+
use MyAppWeb, :router
45+
use Pow.Phoenix.Router
46+
47+
# ... pipelines
48+
49+
pipeline :protected do
50+
plug Pow.Plug.RequireAuthenticated,
51+
error_handler: Pow.Phoenix.PlugErrorHandler
52+
end
53+
54+
scope "/", MyAppWeb do
55+
pipe_through [:browser, :protected]
56+
57+
post "/registration/send-confirmation-email", RegistrationController, :resend_confirmation_email
58+
end
59+
60+
# ...
61+
end
62+
```
63+
64+
Add the following section to your `WEB_PATH/templates/pow/registration/edit.html.eex` template (you may need to generate the templates first) after the `pow_user_id_field` field:
65+
66+
```elixir
67+
<%= if @changeset.data.unconfirmed_email do %>
68+
<div>
69+
<p>Click the link in the confirmation email to change your email to <%= content_tag(:span, @changeset.data.unconfirmed_email) %>. Still haven't received the email? <%= link("Click here to send again", to: Routes.registration_path(@conn, :resend_confirmation_email), method: :post) %>.</p>
70+
</div>
71+
<% end %>
72+
```
73+
74+
That's it!
75+
76+
## Security
77+
78+
As mentioned in the [production checklist](https://hexdocs.pm/pow/production_checklist.html#optional-rate-limit-e-mail-delivery), you should consider adding rate limitation to e-mail delivery. Otherwise the platform may be vulnerable to resource usage attacks.
79+
80+
## Controller test
81+
82+
```elixir
83+
defmodule MyAppWeb.RegistrationControllerTest do
84+
use MyAppWeb.ConnCase
85+
86+
alias MyApp.{Users.User, Repo}
87+
88+
setup %{conn: conn} do
89+
{:ok, user} =
90+
Pow.Ecto.Context.create(%{
91+
92+
password: "secret1234",
93+
password_confirmation: "secret1234"
94+
}, repo: Repo, user: User)
95+
96+
conn = Pow.Plug.assign_current_user(conn, user, otp_app: :my_app)
97+
98+
{:ok, conn: conn, user: user}
99+
end
100+
101+
describe "resend_confirmation_email/2" do
102+
test "sends confirmation email", %{conn: conn} do
103+
conn = post conn, Routes.registration_path(conn, :resend_confirmation_email)
104+
105+
assert redirected_to(conn) == Routes.pow_registration_path(conn, :edit)
106+
assert get_flash(conn, :info) == "E-mail sent, please check your inbox."
107+
end
108+
109+
test "with already confirmed email", %{conn: conn, user: user} do
110+
user = PowEmailConfirmation.Ecto.Context.confirm_email(user, otp_app: :my_app)
111+
112+
conn =
113+
conn
114+
|> Pow.Plug.assign_current_user(user, otp_app: :my_app)
115+
|> post(Routes.registration_path(conn, :resend_confirmation_email))
116+
117+
assert redirected_to(conn) == Routes.pow_registration_path(conn, :edit)
118+
assert get_flash(conn, :info) == "E-mail has already been confirmed."
119+
end
120+
end
121+
end
122+
```

0 commit comments

Comments
 (0)