Skip to content

Commit

Permalink
Merge pull request #235 from unboxed/add-password-reset-configuration
Browse files Browse the repository at this point in the history
Configure Devise's password recovery feature
  • Loading branch information
pixeltrix authored Nov 11, 2024
2 parents a5cb772 + 38b60c5 commit 95c1607
Show file tree
Hide file tree
Showing 17 changed files with 145 additions and 12 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ gem 'jbuilder'
gem 'jsbundling-rails'
gem 'pg', '< 1.5'
gem 'puma'
gem 'mail-notify'
gem 'notifications-ruby-client'
gem 'sprockets-rails'
gem 'stimulus-rails'
Expand Down
8 changes: 8 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ GEM
net-imap
net-pop
net-smtp
mail-notify (1.2.0)
actionmailer (>= 5.2.4.6)
actionpack (>= 5.2.7.1)
actionview (>= 5.2.7.1)
activesupport (>= 5.2.4.6)
notifications-ruby-client (~> 5.1)
rack (>= 2.1.4.1)
marcel (1.0.4)
matrix (0.4.2)
method_source (1.1.0)
Expand Down Expand Up @@ -391,6 +398,7 @@ DEPENDENCIES
jbuilder
jsbundling-rails
listen
mail-notify
notifications-ruby-client
pg (< 1.5)
pry
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/admin/passwords_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Admin
class PasswordsController < Devise::PasswordsController
end
end
14 changes: 14 additions & 0 deletions app/mailers/admin/mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Admin
class Mailer < Devise::Mailer
def devise_mail(record, action, opts = {})
initialize_from_record(record)
view_mail(template_id, headers_for(action, opts))
end

private

def template_id
ENV.fetch("NOTIFY_DEVISE_TEMPLATE_ID")
end
end
end
4 changes: 2 additions & 2 deletions app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: '[email protected]'
class ApplicationMailer < Mail::Notify::Mailer
default from: '[email protected]'
layout 'mailer'
end
6 changes: 5 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
class User < ApplicationRecord
devise :database_authenticatable, :rememberable, :validatable
devise :database_authenticatable, :rememberable, :validatable, :recoverable

def first_name
name.to_s.split(/\s+/).first
end
end
3 changes: 3 additions & 0 deletions app/views/admin/mailer/password_change.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Hello <%= @resource.first_name %>,

We're contacting you to notify you that your password has been changed.
9 changes: 9 additions & 0 deletions app/views/admin/mailer/reset_password_instructions.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Hello <%= @resource.first_name %>,

Someone has requested a link to change your password. You can do this through the link below.

[Change my password](<%= edit_password_url(@resource, reset_password_token: @token) %>)

If you didn't request this, please ignore this email.

Your password won't change until you access the link above and create a new one.
31 changes: 31 additions & 0 deletions app/views/admin/passwords/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<%= form_for(resource, as: resource_name, url: password_path(resource_name), method: :put) do |f| %>
<%= error_summary resource %>

<%= f.hidden_field :reset_password_token %>

<div class="govuk-form-group">
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
<h1 class="govuk-fieldset__heading">Change your password</h1>
</legend>

<div class="govuk-form-group">
<%= f.label :password, "New password", class: "govuk-label" %>
<%= f.password_field :password, class: "govuk-input govuk-input--width-30", autofocus: true, autocomplete: "new-password" %>
</div>

<div class="govuk-form-group">
<%= f.label :password_confirmation, "Confirm new password", class: "govuk-label" %>
<%= f.password_field :password_confirmation, class: "govuk-input govuk-input--width-30", autofocus: true, autocomplete: "new-password" %>
</div>

<div class="actions">
<%= f.submit "Change my password", class: "govuk-button", data: { module: "govuk-button" } %>
</div>

<p class="govuk-body">
<%= link_to "Sign in", new_session_path(resource_name), class: "govuk-link" %>
</p>
</fieldset>
</div>
<% end %>
39 changes: 39 additions & 0 deletions app/views/admin/passwords/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<% if flash[:alert] %>
<div class="govuk-error-summary" aria-labelledby="error-summary-title" role="alert" tabindex="-1" data-module="govuk-error-summary">
<h2 class="govuk-error-summary__title" id="error-summary-title">
There was a problem recovering your password
</h2>
<div class="govuk-error-summary__body">
<ul class="govuk-list govuk-error-summary__list">
<li>
<a href="#admin_email"><%= alert %></a>
</li>
</ul>
</div>
</div>
<% end %>

<%= form_for(resource, as: resource_name, url: password_path(resource_name)) do |f| %>
<%= error_summary resource %>

<div class="govuk-form-group">
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--l">
<h1 class="govuk-fieldset__heading">Forgot your password?</h1>
</legend>

<div class="govuk-form-group">
<%= f.label :email, "Email address", class: "govuk-label" %>
<%= f.text_field :email, class: "govuk-input govuk-input--width-30", spellcheck: false, autofocus: true, inputmode: "email", autocomplete: "email" %>
</div>

<div class="actions">
<%= f.submit "Send me password reset instructions", class: "govuk-button", data: { module: "govuk-button" } %>
</div>

<p class="govuk-body">
<%= link_to "Sign in", new_session_path(resource_name), class: "govuk-link" %>
</p>
</fieldset>
</div>
<% end %>
5 changes: 4 additions & 1 deletion app/views/admin/sessions/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</legend>
<div class="govuk-form-group">
<%= f.label :email, "Email address", class: "govuk-label" %>
<%= f.email_field :email, class: "govuk-input govuk-input--width-30", spellcheck: false, autofocus: true, autocomplete: "email" %>
<%= f.text_field :email, class: "govuk-input govuk-input--width-30", spellcheck: false, autofocus: true, inputmode: "email", autocomplete: "email" %>
</div>
<div class="govuk-form-group">
<%= f.label :password, class: "govuk-label" %>
Expand All @@ -30,6 +30,9 @@
<div class="actions">
<%= f.submit "Sign in", class: "govuk-button", data: { module: "govuk-button" } %>
</div>
<p class="govuk-body">
<%= link_to "Forgot your password?", new_password_path(resource_name), class: "govuk-link" %>
</p>
</fieldset>
</div>
<% end %>
2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class Application < Rails::Application

config.time_zone = "Europe/London"

config.action_mailer.delivery_method = :notify
config.action_mailer.notify_settings = { api_key: ENV.fetch("NOTIFY_API_KEY") }
config.action_view.form_with_generates_remote_forms = false
config.action_view.field_error_proc = ->(html_tag, instance) { html_tag }
config.action_view.prefix_partial_path_with_controller_namespace = false
Expand Down
3 changes: 3 additions & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,7 @@
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker

# Allow web-console connections into docker
config.web_console.permissions = %w[127.0.0.1 ::1 172.16.0.0/12]
end
12 changes: 6 additions & 6 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = '[email protected]'
config.mailer_sender = '[email protected]'

# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
config.mailer = 'Admin::Mailer'

# Configure the parent class responsible to send e-mails.
# config.parent_mailer = 'ActionMailer::Base'
config.parent_mailer = 'ApplicationMailer'

# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
Expand Down Expand Up @@ -90,7 +90,7 @@
# It will change confirmation, password recovery and other workflows
# to behave the same regardless if the e-mail provided was right or wrong.
# Does not affect registerable.
# config.paranoid = true
config.paranoid = true

# By default Devise will store the user in session. You can skip storage for
# particular strategies by setting this option.
Expand Down Expand Up @@ -132,7 +132,7 @@
# config.send_email_changed_notification = false

# Send a notification email when the user's password is changed.
# config.send_password_change_notification = false
config.send_password_change_notification = true

# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
Expand Down Expand Up @@ -228,7 +228,7 @@

# When set to false, does not sign a user in automatically after their password is
# reset. Defaults to true, so a user is signed in automatically after a reset.
# config.sign_in_after_reset_password = true
config.sign_in_after_reset_password = false

# ==> Configuration for :encryptable
# Allow you to use another hashing or encryption algorithm besides bcrypt (default).
Expand Down
2 changes: 1 addition & 1 deletion config/locales/devise.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ en:
last_attempt: "You have one more attempt before your account is locked."
not_found_in_database: "Invalid %{authentication_keys} or password."
timeout: "Your session expired. Please sign in again to continue."
unauthenticated: "You need to sign in or sign up before continuing."
unauthenticated: "You need to sign in before continuing."
unconfirmed: "You have to confirm your email address before continuing."
mailer:
confirmation_instructions:
Expand Down
12 changes: 12 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,15 @@ en:
attributes:
uprn:
blank: "Please enter the UPRN of the building"

user:
attributes:
email:
blank: "Please enter your email address"
not_found: "Sorry, we couldn't find that email address"
password:
blank: "Please enter a new password"
password_confirmation:
confirmation: "The password confirmation does not match the password"
reset_password_token:
blank: "Missing password reset token"
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
delete "/survey", action: "destroy", as: nil
end

devise_for :admin, only: :sessions, class_name: "User", module: "admin"
devise_for :admin, only: %i[sessions passwords], class_name: "User", module: "admin"

namespace :admin do
root to: "buildings#index"
Expand Down

0 comments on commit 95c1607

Please sign in to comment.