diff --git a/.env.example b/.env.example index 94596a0da..d30382d9e 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,4 @@ DB_USERNAME=postgres-user DB_PASSWORD=postgres-password +CORE_EMAIL_USERNAME=email@example.com +CORE_EMAIL_PASSWORD=password123 diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 254cf36bc..c64e3d581 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -100,10 +100,14 @@ jobs: API_USER: ${{ secrets.API_USER }} API_KEY: ${{ secrets.API_KEY }} APP_NAME: dluhc-core + CORE_EMAIL_USERNAME: ${{ secrets.CORE_EMAIL_USERNAME }} + CORE_EMAIL_PASSWORD: ${{ secrets.CORE_EMAIL_PASSWORD }} run: | cf7 api $CF_API_ENDPOINT cf7 auth cf7 target -o $CF_ORG -s $CF_SPACE cf7 set-env $APP_NAME API_USER $API_USER cf7 set-env $APP_NAME API_KEY $API_KEY + cf7 set-env $APP_NAME CORE_EMAIL_USERNAME $CORE_EMAIL_USERNAME + cf7 set-env $APP_NAME CORE_EMAIL_PASSWORD $CORE_EMAIL_PASSWORD cf7 push --strategy rolling diff --git a/Gemfile b/Gemfile index cd22b2eb7..f2895387e 100644 --- a/Gemfile +++ b/Gemfile @@ -33,6 +33,8 @@ gem "chartkick" gem "roo" # Json Schema gem "json-schema" +# Authentication +gem "devise" gem "turbo-rails", "~> 0.8" gem "uk_postcode" diff --git a/Gemfile.lock b/Gemfile.lock index 04961facf..322fcc403 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,6 +122,7 @@ GEM activesupport (>= 3.0.0, < 6.2) ruby2_keywords (>= 0.0.2, < 1.0) ast (2.4.2) + bcrypt (3.1.16) bindex (0.8.1) bootsnap (1.9.1) msgpack (~> 1.0) @@ -146,6 +147,12 @@ GEM database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) deep_merge (1.2.1) + devise (4.8.0) + bcrypt (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 4.1.0) + responders + warden (~> 1.2.3) diff-lcs (1.4.4) discard (1.2.0) activerecord (>= 4.2, < 7) @@ -227,6 +234,7 @@ GEM nio4r (2.5.8) nokogiri (1.12.5-x86_64-linux) racc (~> 1.4) + orm_adapter (0.5.0) overcommit (0.58.0) childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) @@ -365,6 +373,8 @@ GEM view_component (2.39.0) activesupport (>= 5.0.0, < 8.0) method_source (~> 1.0) + warden (1.2.9) + rack (>= 2.0.9) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -383,6 +393,7 @@ GEM zeitwerk (2.5.1) PLATFORMS + x86_64-darwin-20 x86_64-linux DEPENDENCIES @@ -392,6 +403,7 @@ DEPENDENCIES capybara chartkick database_cleaner-active_record + devise discard dotenv-rails factory_bot_rails diff --git a/app/controllers/case_logs_controller.rb b/app/controllers/case_logs_controller.rb index 4d4ed6db3..c2b4edc28 100644 --- a/app/controllers/case_logs_controller.rb +++ b/app/controllers/case_logs_controller.rb @@ -1,6 +1,7 @@ class CaseLogsController < ApplicationController skip_before_action :verify_authenticity_token, if: :json_api_request? before_action :authenticate, if: :json_api_request? + before_action :authenticate_user!, unless: :json_api_request? def index @completed_case_logs = CaseLog.completed diff --git a/app/controllers/users/passwords_controller.rb b/app/controllers/users/passwords_controller.rb new file mode 100644 index 000000000..da3b39158 --- /dev/null +++ b/app/controllers/users/passwords_controller.rb @@ -0,0 +1,20 @@ +class Users::PasswordsController < Devise::PasswordsController + def reset_confirmation + @email = params["email"] + flash[:notice] = "Reset password instructions have been sent to #{@email}" + render "devise/confirmations/reset" + end + + def create + self.resource = resource_class.send_reset_password_instructions(resource_params) + yield resource if block_given? + + respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) + end + +protected + + def after_sending_reset_password_instructions_path_for(_resource) + confirmations_reset_path(email: params.dig("user", "email")) + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 000000000..0ef982f25 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,5 @@ +class User < ApplicationRecord + # Include default devise modules. Others available are: + # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable + devise :database_authenticatable, :recoverable, :rememberable, :validatable +end diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 000000000..b12dd0cbe --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,16 @@ +
We’ve sent a link to reset your password to <%= @email %>.
+You’ll only this receive this link if your email address already exists in our system.
+If you don’t receive the email within 5 minutes, check your spam or junk folders. Try again if you still haven’t received the email.
+Welcome <%= @email %>!
+ +You can confirm your account email through the link below:
+ +<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
diff --git a/app/views/devise/mailer/email_changed.html.erb b/app/views/devise/mailer/email_changed.html.erb new file mode 100644 index 000000000..32f4ba803 --- /dev/null +++ b/app/views/devise/mailer/email_changed.html.erb @@ -0,0 +1,7 @@ +Hello <%= @email %>!
+ +<% if @resource.try(:unconfirmed_email?) %> +We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.
+<% else %> +We're contacting you to notify you that your email has been changed to <%= @resource.email %>.
+<% end %> diff --git a/app/views/devise/mailer/password_change.html.erb b/app/views/devise/mailer/password_change.html.erb new file mode 100644 index 000000000..b41daf476 --- /dev/null +++ b/app/views/devise/mailer/password_change.html.erb @@ -0,0 +1,3 @@ +Hello <%= @resource.email %>!
+ +We're contacting you to notify you that your password has been changed.
diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 000000000..f667dc12f --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +Hello <%= @resource.email %>!
+ +Someone has requested a link to change your password. You can do this through the link below.
+ +<%= link_to '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.
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 000000000..41e148bf2 --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +Hello <%= @resource.email %>!
+ +Your account has been locked due to an excessive number of unsuccessful sign in attempts.
+ +Click the link below to unlock your account:
+ +<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 000000000..0b2bc2067 --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,19 @@ +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> +Enter the email address you used to create your account.
+We’ll email you a link to reset your password. This link will expire in 3 hours.
+ +Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 000000000..d655b66f6 --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,29 @@ +Already have an account? <%= link_to "Sign in", new_session_path(resource_name) %>.
You can <%= link_to "reset your password", new_password_path(resource_name) %> if you've forgotten it.
+<% end %>
+
+<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
+ <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end %>
+
+<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
+ <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end %>
+
+<%- if devise_mapping.omniauthable? %>
+ <%- resource_class.omniauth_providers.each do |provider| %>
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %>
+ <% end %>
+<% end %>
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb
new file mode 100644
index 000000000..ffc34de8d
--- /dev/null
+++ b/app/views/devise/unlocks/new.html.erb
@@ -0,0 +1,16 @@
+
<%= notice %>
+<%= alert %>
<% if Rails.env.development? %>