diff --git a/app/controllers/devise_overrides/confirmations_controller.rb b/app/controllers/devise_overrides/confirmations_controller.rb index 057e77b12..0cb71f0d9 100644 --- a/app/controllers/devise_overrides/confirmations_controller.rb +++ b/app/controllers/devise_overrides/confirmations_controller.rb @@ -4,22 +4,34 @@ class DeviseOverrides::ConfirmationsController < Devise::ConfirmationsController def create @confirmable = User.find_by(confirmation_token: params[:confirmation_token]) - if @confirmable - if @confirmable.confirm || (@confirmable.confirmed_at && @confirmable.reset_password_token) - # confirmed now or already confirmed but quit before setting a password - render json: { "message": 'Success', "redirect_url": create_reset_token_link(@confirmable) }, status: :ok - elsif @confirmable.confirmed_at - render json: { "message": 'Already confirmed', "redirect_url": '/' }, status: 422 - else - render json: { "message": 'Failure', "redirect_url": '/' }, status: 422 - end + + if confirm + render_confirmation_success else - render json: { "message": 'Invalid token', "redirect_url": '/' }, status: 422 + render_confirmation_error end end protected + def confirm + @confirmable&.confirm || (@confirmable&.confirmed_at && @confirmable&.reset_password_token) + end + + def render_confirmation_success + render json: { "message": 'Success', "redirect_url": create_reset_token_link(@confirmable) }, status: :ok + end + + def render_confirmation_error + if @confirmable.blank? + render json: { "message": 'Invalid token', "redirect_url": '/' }, status: 422 + elsif @confirmable.confirmed_at + render json: { "message": 'Already confirmed', "redirect_url": '/' }, status: 422 + else + render json: { "message": 'Failure', "redirect_url": '/' }, status: 422 + end + end + def create_reset_token_link(user) raw, enc = Devise.token_generator.generate(user.class, :reset_password_token) user.reset_password_token = enc diff --git a/spec/controllers/devise/confirmations_controller_spec.rb b/spec/controllers/devise/confirmations_controller_spec.rb new file mode 100644 index 000000000..6970b5777 --- /dev/null +++ b/spec/controllers/devise/confirmations_controller_spec.rb @@ -0,0 +1,56 @@ +require 'rails_helper' + +RSpec.describe 'Token Confirmation', type: :request do + describe 'POST /auth/confirmation' do + let(:response_json) { JSON.parse(response.body, symbolize_names: true) } + + before do + create(:user, email: 'john.doe@gmail.com', **user_attributes) + + post user_confirmation_url, params: { confirmation_token: confirmation_token } + end + + context 'when token is valid' do + let(:user_attributes) { { confirmation_token: '12345', skip_confirmation: false } } + let(:confirmation_token) { '12345' } + + it 'has status 200' do + expect(response.status).to eq 200 + end + + it 'returns message "Success"' do + expect(response_json[:message]).to eq 'Success' + end + + it 'returns "redirect_url"' do + expect(response_json[:redirect_url]).to include '/app/auth/password/edit?config=default&redirect_url=&reset_password_token' + end + end + + context 'when token is invalid' do + let(:user_attributes) { { confirmation_token: '12345' } } + let(:confirmation_token) { '' } + + it 'has status 422' do + expect(response.status).to eq 422 + end + + it 'returns message "Invalid token"' do + expect(response_json).to eq({ message: 'Invalid token', redirect_url: '/' }) + end + end + + context 'when user had already been confirmed' do + let(:user_attributes) { { confirmation_token: '12345' } } + let(:confirmation_token) { '12345' } + + it 'has status 422' do + expect(response.status).to eq 422 + end + + it 'returns message "Already confirmed"' do + expect(response_json).to eq({ message: 'Already confirmed', redirect_url: '/' }) + end + end + end +end