Browse Source
* Confirmable * Remove obsolete rake task * Skip confirmation for inactive users * Send beta onboarding template if migrated from Softwire * Default controller * Use correct link * Redirect confirmation to set password * Confirm account within 3 days * Only redirect to set password if not previously set * Rubocop * Confirm factory bot users * Set password condition * Changing email requires reconfirming * No need to explicitly trigger email, devise does that for us now * Remove flash banner * Mock notify * Mock in the right spec * Test redirect and text * User is confirmable * Rubocop * Redirect to url so we don't bypass authenticity token * Update content * Add test for resend invite flow * Update link to resend confirmation email * Rename password reset resend confirmation partial * Expired link error page * Remove resend confirmation link * Update seed * Expory contact * Time zone Co-authored-by: Paul Robert Lloyd <me+git@paulrobertlloyd.com>pull/619/head
27 changed files with 214 additions and 103 deletions
@ -0,0 +1,20 @@
|
||||
class Auth::ConfirmationsController < Devise::ConfirmationsController |
||||
# GET /resource/confirmation?confirmation_token=abcdef |
||||
def show |
||||
self.resource = resource_class.confirm_by_token(params[:confirmation_token]) |
||||
yield resource if block_given? |
||||
|
||||
if resource.errors.empty? |
||||
if resource.sign_in_count.zero? |
||||
token = resource.send(:set_reset_password_token) |
||||
redirect_to "#{edit_user_password_url}?reset_password_token=#{token}&confirmation=true" |
||||
else |
||||
respond_with_navigational(resource) { redirect_to after_confirmation_path_for(resource_name, resource) } |
||||
end |
||||
elsif resource.errors.map(&:type).include?(:confirmation_period_expired) |
||||
render "devise/confirmations/expired" |
||||
else |
||||
respond_with_navigational(resource.errors, status: :unprocessable_entity) { render :new } |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,11 @@
|
||||
<% content_for :title, "Your invitation link has expired" %> |
||||
|
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-two-thirds"> |
||||
<h1 class="govuk-heading-l"> |
||||
<%= content_for(:title) %> |
||||
</h1> |
||||
|
||||
<p class="govuk-body">Contact the helpdesk to request a new one.</p> |
||||
</div> |
||||
</div> |
@ -1,15 +1,32 @@
|
||||
<h2>Resend confirmation instructions</h2> |
||||
<% content_for :title, "Resend invitation link" %> |
||||
|
||||
<% content_for :before_content do %> |
||||
<%= govuk_back_link( |
||||
text: "Back", |
||||
href: :back, |
||||
) %> |
||||
<% end %> |
||||
|
||||
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> |
||||
<%= render "devise/shared/error_messages", resource: resource %> |
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-two-thirds"> |
||||
<%= f.govuk_error_summary %> |
||||
|
||||
<h1 class="govuk-heading-l"> |
||||
<%= content_for(:title) %> |
||||
</h1> |
||||
|
||||
<p class="govuk-body">Enter your email address to get a new invitation link.</p> |
||||
|
||||
<%= f.govuk_email_field :email, |
||||
label: { text: "Email address" }, |
||||
autocomplete: "email", |
||||
spellcheck: "false", |
||||
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> |
||||
<%= f.govuk_email_field :email, |
||||
label: { text: "Email address" }, |
||||
autocomplete: "email", |
||||
spellcheck: "false", |
||||
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> |
||||
|
||||
<%= f.govuk_submit "Resend confirmation instructions" %> |
||||
<%= f.govuk_submit "Send email" %> |
||||
</div> |
||||
</div> |
||||
<% end %> |
||||
|
||||
<%= render "devise/shared/links" %> |
||||
|
@ -0,0 +1,11 @@
|
||||
class AddConfirmableUsers < ActiveRecord::Migration[7.0] |
||||
def change |
||||
change_table :users, bulk: true do |t| |
||||
t.column :confirmation_token, :string |
||||
t.column :confirmed_at, :datetime |
||||
t.column :confirmation_sent_at, :datetime |
||||
t.string :unconfirmed_email |
||||
end |
||||
add_index :users, :confirmation_token, unique: true |
||||
end |
||||
end |
@ -1,22 +0,0 @@
|
||||
namespace :onboarding_emails do |
||||
desc "Send onboarding emails to private beta users" |
||||
task :send, %i[organisation_id] => :environment do |_task, args| |
||||
organisation_id = args[:organisation_id] |
||||
host = ENV["APP_HOST"] |
||||
raise "Organisation id must be provided" unless organisation_id |
||||
raise "Host is not set" unless host |
||||
|
||||
organisation = Organisation.find(organisation_id) |
||||
raise "Organisation #{organisation_id} does not exist" unless organisation |
||||
|
||||
organisation.users.each do |user| |
||||
next unless URI::MailTo::EMAIL_REGEXP.match?(user.email) |
||||
|
||||
onboarding_template_id = "b48bc2cd-5887-4611-8296-d0ab3ed0e7fd".freeze |
||||
token = user.send(:set_reset_password_token) |
||||
url = "#{host}/account/password/edit?reset_password_token=#{token}" |
||||
personalisation = { name: user.name || user.email, link: url } |
||||
DeviseNotifyMailer.new.send_email(user.email, onboarding_template_id, personalisation) |
||||
end |
||||
end |
||||
end |
@ -1,41 +0,0 @@
|
||||
require "rails_helper" |
||||
require "rake" |
||||
|
||||
describe "rake onboarding_emails:send", type: task do |
||||
subject(:task) { Rake::Task["onboarding_emails:send"] } |
||||
|
||||
context "when onboarding a new organisation to private beta" do |
||||
let!(:user) { FactoryBot.create(:user) } |
||||
let(:notify_client) { instance_double(Notifications::Client) } |
||||
let(:devise_notify_mailer) { DeviseNotifyMailer.new } |
||||
let(:reset_password_token) { "MCDH5y6Km-U7CFPgAMVS" } |
||||
let(:host) { "http://localhost:3000" } |
||||
|
||||
before do |
||||
Rake.application.rake_require("tasks/onboarding_emails") |
||||
Rake::Task.define_task(:environment) |
||||
task.reenable |
||||
allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) |
||||
allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) |
||||
allow(notify_client).to receive(:send_email).and_return(true) |
||||
allow(Devise.token_generator).to receive(:generate).and_return(reset_password_token) |
||||
allow(ENV).to receive(:[]) |
||||
allow(ENV).to receive(:[]).with("APP_HOST").and_return(host) |
||||
end |
||||
|
||||
it "can send the onboarding emails" do |
||||
expect(notify_client).to receive(:send_email).with( |
||||
{ |
||||
email_address: user.email, |
||||
template_id: "b48bc2cd-5887-4611-8296-d0ab3ed0e7fd", |
||||
personalisation: { |
||||
name: user.name, |
||||
link: "#{host}/account/password/edit?reset_password_token=#{reset_password_token}", |
||||
}, |
||||
}, |
||||
) |
||||
|
||||
task.invoke(user.organisation.id) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,46 @@
|
||||
require "rails_helper" |
||||
require_relative "../../support/devise" |
||||
|
||||
RSpec.describe Auth::ConfirmationsController, type: :request do |
||||
let(:page) { Capybara::Node::Simple.new(response.body) } |
||||
let(:notify_client) { instance_double(Notifications::Client) } |
||||
let(:devise_notify_mailer) { DeviseNotifyMailer.new } |
||||
let(:user) { FactoryBot.create(:user, :data_provider, sign_in_count: 0, confirmed_at: nil) } |
||||
|
||||
before do |
||||
allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) |
||||
allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) |
||||
allow(notify_client).to receive(:send_email).and_return(true) |
||||
end |
||||
|
||||
context "when a confirmation link is clicked by a new user" do |
||||
before do |
||||
user.send_confirmation_instructions |
||||
get "/account/confirmation?confirmation_token=#{user.confirmation_token}" |
||||
end |
||||
|
||||
it "marks the user as confirmed" do |
||||
expect(user.reload.confirmed_at).to be_a(Time) |
||||
end |
||||
|
||||
it "redirects to the set password page" do |
||||
follow_redirect! |
||||
expect(page).to have_content(I18n.t("user.create_password")) |
||||
end |
||||
end |
||||
|
||||
context "when the token has expired" do |
||||
let(:period) { Devise::TimeInflector.time_ago_in_words(User.confirm_within.ago) } |
||||
|
||||
before do |
||||
user.send_confirmation_instructions |
||||
allow(User).to receive(:find_first_by_auth_conditions).and_return(user) |
||||
allow(user).to receive(:confirmation_period_expired?).and_return(true) |
||||
get "/account/confirmation?confirmation_token=#{user.confirmation_token}" |
||||
end |
||||
|
||||
it "shows the error page" do |
||||
expect(page).to have_content("Your invitation link has expired") |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue