From 1f23402912baa16cbc807935c3fc9c671e470ea4 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Wed, 18 Apr 2018 15:14:21 +0100 Subject: [PATCH] Disable password reset for unconfirmed users --- .../forgot_controller.js.coffee | 11 ++++- .../javascripts/templates/forgot.html.haml | 42 ++++++++++--------- app/controllers/user_passwords_controller.rb | 13 +++++- config/locales/en.yml | 1 + .../user_passwords_controller_spec.rb | 14 +++++-- 5 files changed, 55 insertions(+), 26 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/authentication/forgot_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/authentication/forgot_controller.js.coffee index 85920de958..b2984fd092 100644 --- a/app/assets/javascripts/darkswarm/controllers/authentication/forgot_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/authentication/forgot_controller.js.coffee @@ -6,7 +6,14 @@ Darkswarm.controller "ForgotCtrl", ($scope, $http, $location, AuthenticationServ if $scope.spree_user.email != null $http.post("/user/spree_user/password", {spree_user: $scope.spree_user}).success (data)-> $scope.sent = true - .error (data) -> - $scope.errors = t 'email_not_found' + .error (data, status) -> + $scope.errors = data.error + $scope.user_unconfirmed = (status == 401) else $scope.errors = t 'email_required' + + $scope.resend_confirmation = -> + $http.post("/user/spree_user/confirmation", {spree_user: $scope.spree_user}).success (data)-> + $scope.messages = t('devise.confirmations.send_instructions') + .error (data) -> + $scope.errors = t('devise.confirmations.failed_to_send') diff --git a/app/assets/javascripts/templates/forgot.html.haml b/app/assets/javascripts/templates/forgot.html.haml index 958f1daa39..0157b6fc36 100644 --- a/app/assets/javascripts/templates/forgot.html.haml +++ b/app/assets/javascripts/templates/forgot.html.haml @@ -2,24 +2,28 @@ %form{ ng: { controller: "ForgotCtrl", submit: "submit()" } } .row .large-12.columns - .alert-box.success.radius{"ng-show" => "sent"} - {{'password_reset_sent' | t}} + .alert-box.success{"ng-show" => "sent"} + {{ 'password_reset_sent' | t }} - %div{"ng-show" => "!sent"} - .alert-box.alert{"ng-show" => "errors != null"} - {{ errors }} + .alert-box.success{"ng-show" => "messages != null"} + {{ messages }} - .row - .large-12.columns - %label{for: "email"} {{'signup_email' | t}} - %input.title.input-text{name: "email", - type: "email", - id: "email", - tabindex: 1, - "ng-model" => "spree_user.email"} - .row - .large-12.columns - %input.button.primary{name: "commit", - tabindex: "3", - type: "submit", - value: "{{'reset_password' | t}}"} + .alert-box.alert{"ng-show" => "errors != null"} + {{ errors }} + %a{ng: {show: 'user_unconfirmed', click: 'resend_confirmation()'}} + = t('devise.confirmations.resend_confirmation_email') + + .row + .large-12.columns + %label{for: "email"} {{'signup_email' | t}} + %input.title.input-text{name: "email", + type: "email", + id: "email", + tabindex: 1, + "ng-model" => "spree_user.email"} + .row + .large-12.columns + %input.button.primary{name: "commit", + tabindex: "3", + type: "submit", + value: "{{'reset_password' | t}}"} diff --git a/app/controllers/user_passwords_controller.rb b/app/controllers/user_passwords_controller.rb index 1870cc8859..240837655e 100644 --- a/app/controllers/user_passwords_controller.rb +++ b/app/controllers/user_passwords_controller.rb @@ -4,6 +4,8 @@ class UserPasswordsController < Spree::UserPasswordsController before_filter :set_admin_redirect, only: :edit def create + return if user_unconfirmed? + self.resource = resource_class.send_reset_password_instructions(params[resource_name]) if resource.errors.empty? @@ -15,7 +17,7 @@ class UserPasswordsController < Spree::UserPasswordsController respond_with_navigational(resource) { render :new } end format.js do - render json: resource.errors, status: :unauthorized + render json: { error: t('email_not_found') }, status: :not_found end end end @@ -26,4 +28,13 @@ class UserPasswordsController < Spree::UserPasswordsController def set_admin_redirect session["spree_user_return_to"] = params[:return_to] if params[:return_to] end + + def user_unconfirmed? + user = Spree::User.find_by_email(params[:spree_user][:email]) + if user && !user.confirmed? + render json: { error: t('email_unconfirmed') }, status: :unauthorized + end + + user && !user.confirmed? + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 315ee8960c..4a2ee53afa 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1628,6 +1628,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using november: "November" december: "December" email_not_found: "Email address not found" + email_unconfirmed: "You must confirm your email address before you can reset your password." email_required: "You must provide an email address" logging_in: "Hold on a moment, we're logging you in" signup_email: "Your email" diff --git a/spec/controllers/user_passwords_controller_spec.rb b/spec/controllers/user_passwords_controller_spec.rb index 59a2f16280..42e505e172 100644 --- a/spec/controllers/user_passwords_controller_spec.rb +++ b/spec/controllers/user_passwords_controller_spec.rb @@ -3,6 +3,7 @@ require 'spree/api/testing_support/helpers' describe UserPasswordsController, type: :controller do let(:user) { create(:user) } + let(:unconfirmed_user) { create(:user, confirmed_at: nil) } before do @request.env["devise.mapping"] = Devise.mappings[:spree_user] @@ -44,11 +45,16 @@ describe UserPasswordsController, type: :controller do end describe "via ajax" do - it "returns errors" do + it "returns error when email not found" do xhr :post, :create, spree_user: {}, use_route: :spree - json = JSON.parse(response.body) - response.status.should == 401 - json.should == {"email"=>["can't be blank"]} + expect(response.status).to eq 404 + expect(json_response).to eq 'error' => I18n.t('email_not_found') + end + + it "returns error when user is unconfirmed" do + xhr :post, :create, spree_user: {email: unconfirmed_user.email}, use_route: :spree + expect(response.status).to eq 401 + expect(json_response).to eq 'error' => I18n.t('email_unconfirmed') end end end