Skip to content

Commit

Permalink
Fix unconfirmed_email confirmation. Ignore devise reconfirmable config.
Browse files Browse the repository at this point in the history
  • Loading branch information
mcelicalderon committed Aug 13, 2020
1 parent d24a270 commit 84bf204
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 45 deletions.
6 changes: 6 additions & 0 deletions app/models/graphql_devise/concerns/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ module Concerns
def update_with_email(attributes = {})
GraphqlDevise::Model::WithEmailUpdater.new(self, attributes).call
end

private

def pending_reconfirmation?
devise_modules.include?(:confirmable) && try(:unconfirmed_email).present?
end
end
end
end
13 changes: 13 additions & 0 deletions spec/dummy/app/graphql/resolvers/confirm_admin_account.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module Resolvers
class ConfirmAdminAccount < GraphqlDevise::Resolvers::ConfirmAccount
type Types::AdminType, null: false

def resolve(confirmation_token:, redirect_url:)
super do |admin|
controller.sign_in(admin)
end
end
end
end
8 changes: 8 additions & 0 deletions spec/dummy/app/graphql/types/admin_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

module Types
class AdminType < GraphQL::Schema::Object
field :id, Int, null: false
field :email, String, null: false
end
end
2 changes: 1 addition & 1 deletion spec/dummy/config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field (see migrations). Until confirmed, new email is stored in
# unconfirmed_email column, and copied to email column on successful confirmation.
config.reconfirmable = true
config.reconfirmable = false

# Defines which key will be used when confirming an account
# config.confirmation_keys = [:email]
Expand Down
3 changes: 3 additions & 0 deletions spec/dummy/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
'Admin',
authenticatable_type: Types::CustomAdminType,
skip: [:sign_up, :check_password_token],
operations: {
confirm_account: Resolvers::ConfirmAdminAccount
},
at: '/api/v1/admin/graphql_auth'
)

Expand Down
2 changes: 0 additions & 2 deletions spec/dummy/db/schema.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# frozen_string_literal: true

# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
Expand Down
142 changes: 100 additions & 42 deletions spec/requests/queries/confirm_account_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,118 @@
RSpec.describe 'Account confirmation' do
include_context 'with graphql query request'

let(:user) { create(:user, confirmed_at: nil) }
let(:redirect) { Faker::Internet.url }
let(:query) do
<<-GRAPHQL
{
userConfirmAccount(
confirmationToken: "#{token}"
redirectUrl: "#{redirect}"
) {
email
name
context 'when using the user model' do
let(:user) { create(:user, confirmed_at: nil) }
let(:redirect) { Faker::Internet.url }
let(:query) do
<<-GRAPHQL
{
userConfirmAccount(
confirmationToken: "#{token}"
redirectUrl: "#{redirect}"
) {
email
name
}
}
}
GRAPHQL
end
GRAPHQL
end

context 'when confirmation token is correct' do
let(:token) { user.confirmation_token }

before do
user.send_confirmation_instructions(
template_path: ['graphql_devise/mailer'],
controller: 'graphql_devise/graphql',
schema_url: 'http://not-using-this-value.com/gql'
)
end

it 'confirms the resource and redirects to the sent url' do
expect do
get_request
user.reload
end.to(change(user, :confirmed_at).from(nil))

expect(response).to redirect_to("#{redirect}?account_confirmation_success=true")
expect(user).to be_active_for_authentication
end

context 'when unconfirmed_email is present' do
let(:user) { create(:user, :confirmed, unconfirmed_email: 'vvega@wallaceinc.com') }

context 'when confirmation token is correct' do
let(:token) { user.confirmation_token }
it 'confirms the unconfirmed email and redirects' do
expect do
get_request
user.reload
end.to change(user, :email).from(user.email).to('vvega@wallaceinc.com').and(
change(user, :unconfirmed_email).from('vvega@wallaceinc.com').to(nil)
)

before do
user.send_confirmation_instructions(
template_path: ['graphql_devise/mailer'],
controller: 'graphql_devise/graphql',
schema_url: 'http://not-using-this-value.com/gql'
)
expect(response).to redirect_to("#{redirect}?account_confirmation_success=true")
end
end
end

it 'confirms the resource and redirects to the sent url' do
expect do
get_request
user.reload
end.to(change(user, :confirmed_at).from(nil))
context 'when reset password token is not found' do
let(:token) { "#{user.confirmation_token}-invalid" }

expect(response).to redirect_to "#{redirect}?account_confirmation_success=true"
expect(user).to be_active_for_authentication
it 'does *NOT* confirm the user nor does the redirection' do
expect do
get_request
user.reload
end.not_to(change(user, :confirmed_at).from(nil))

expect(response).not_to be_redirect
expect(json_response[:errors]).to contain_exactly(
hash_including(
message: 'Invalid confirmation token. Please try again',
extensions: { code: 'USER_ERROR' }
)
)
end
end
end

context 'when reset password token is not found' do
let(:token) { "#{user.confirmation_token}-invalid" }
context 'when using the admin model' do
let(:admin) { create(:admin, confirmed_at: nil) }
let(:redirect) { Faker::Internet.url }
let(:query) do
<<-GRAPHQL
{
adminConfirmAccount(
confirmationToken: "#{token}"
redirectUrl: "#{redirect}"
) {
email
}
}
GRAPHQL
end

it 'does *NOT* confirm the user nor does the redirection' do
expect do
get_request
user.reload
end.not_to(change(user, :confirmed_at).from(nil))
context 'when confirmation token is correct' do
let(:token) { admin.confirmation_token }

expect(response).not_to be_redirect
expect(json_response[:errors]).to contain_exactly(
hash_including(
message: 'Invalid confirmation token. Please try again',
extensions: { code: 'USER_ERROR' }
before do
admin.send_confirmation_instructions(
template_path: ['graphql_devise/mailer'],
controller: 'graphql_devise/graphql',
schema_url: 'http://not-using-this-value.com/gql'
)
)
end

it 'confirms the resource, persists credentials on the DB and redirects to the sent url' do
expect do
get_request
admin.reload
end.to change(admin, :confirmed_at).from(nil).and(
change { admin.tokens.keys.count }.from(0).to(1)
)

expect(response).to redirect_to(/\A#{redirect}.+access\-token=/)
expect(admin).to be_active_for_authentication
end
end
end
end

0 comments on commit 84bf204

Please sign in to comment.