diff --git a/app/controllers/email_confirmations_controller.rb b/app/controllers/email_confirmations_controller.rb index 6671553..96dc96b 100644 --- a/app/controllers/email_confirmations_controller.rb +++ b/app/controllers/email_confirmations_controller.rb @@ -1,5 +1,19 @@ class EmailConfirmationsController < ApplicationController - allow_unauthenticated_access only: :show + allow_unauthenticated_access only: %i[ new create show ] + rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_email_confirmation_path, alert: "Try again later." } + + def new + end + + def create + user = User.find_by(email_address: params[:email_address]) + + if user && !user.confirmed? + RegistrationMailer.confirmation(user, Current.organization).deliver_later + end + + redirect_to new_session_path, notice: "Confirmation instructions sent (if an unconfirmed account with that email address exists)." + end def show if user = User.find_by_token_for(:email_confirmation, params[:token]) diff --git a/app/views/email_confirmations/new.html.erb b/app/views/email_confirmations/new.html.erb new file mode 100644 index 0000000..890d1f6 --- /dev/null +++ b/app/views/email_confirmations/new.html.erb @@ -0,0 +1,15 @@ +
+
+

Resend confirmation email

+ + <%= form_with url: email_confirmation_path, class: "contents" do |form| %> +
+ <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], class: "block shadow-sm rounded-md border border-line bg-surface px-3 py-2 mt-2 w-full focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/10" %> +
+ +
+ <%= form.submit "Email confirmation instructions", class: "w-full sm:w-auto text-center rounded-md px-3.5 py-2.5 bg-accent hover:bg-[#444] text-white inline-block font-medium cursor-pointer transition" %> +
+ <% end %> +
+
diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 3dfb024..5e84305 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -20,6 +20,8 @@ <%= link_to "Sign up", new_registration_path, class: "text-ink hover:text-brand underline" %> · <%= link_to "Forgot password?", new_password_path, class: "text-ink hover:text-brand underline" %> + · + <%= link_to "Resend confirmation", new_email_confirmation_path, class: "text-ink hover:text-brand underline" %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 92341a8..a4b6a72 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,7 @@ resource :home resources :passwords, param: :token resource :registration, only: %i[ new create ] - resource :email_confirmation, only: :show + resource :email_confirmation, only: %i[ new create show ] resource :session resources :scenarios do diff --git a/test/controllers/email_confirmations_controller_test.rb b/test/controllers/email_confirmations_controller_test.rb index c8bc226..64c587f 100644 --- a/test/controllers/email_confirmations_controller_test.rb +++ b/test/controllers/email_confirmations_controller_test.rb @@ -6,6 +6,38 @@ class EmailConfirmationsControllerTest < ActionDispatch::IntegrationTest @user = users(:unconfirmed) end + test "new" do + get new_email_confirmation_path + assert_response :success + end + + test "create for an unconfirmed user enqueues a confirmation email" do + post email_confirmation_path, params: { email_address: @user.email_address } + assert_enqueued_email_with RegistrationMailer, :confirmation, args: [ @user, organizations(:arlington) ] + assert_redirected_to new_session_path + + follow_redirect! + assert_notice "Confirmation instructions sent" + end + + test "create for an already-confirmed user sends no mail" do + post email_confirmation_path, params: { email_address: users(:one).email_address } + assert_enqueued_emails 0 + assert_redirected_to new_session_path + + follow_redirect! + assert_notice "Confirmation instructions sent" + end + + test "create for an unknown email sends no mail and reveals nothing" do + post email_confirmation_path, params: { email_address: "missing-user@example.com" } + assert_enqueued_emails 0 + assert_redirected_to new_session_path + + follow_redirect! + assert_notice "Confirmation instructions sent" + end + test "show with a valid token confirms the user and signs them in" do token = @user.generate_token_for(:email_confirmation) @@ -33,4 +65,9 @@ class EmailConfirmationsControllerTest < ActionDispatch::IntegrationTest assert_redirected_to new_session_path assert_nil cookies[:session_id] end + + private + def assert_notice(text) + assert_select "div", /#{text}/ + end end