Skip to content

Commit f591fb7

Browse files
committed
Add reset password mutation
1 parent 16984dc commit f591fb7

12 files changed

Lines changed: 199 additions & 9 deletions

File tree

app/graphql/graphql_devise/mutations/base.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ def raise_user_error(message)
99
raise GraphqlDevise::UserError, message
1010
end
1111

12+
def raise_user_error_list(message, errors:)
13+
raise GraphqlDevise::DetailedUserError.new(message, errors: errors)
14+
end
15+
1216
def remove_resource
1317
controller.resource = nil
1418
controller.client_id = nil
@@ -31,6 +35,10 @@ def resource_class
3135
context[:resource_class]
3236
end
3337

38+
def recoverable_enabled?
39+
resource_class.devise_modules.include?(:recoverable)
40+
end
41+
3442
def current_resource
3543
context[:current_resource]
3644
end

app/graphql/graphql_devise/mutations/login.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def resolve(email:, password:)
1717

1818
yield resource if block_given?
1919

20-
{ success: true, authenticable: resource, errors: [] }
20+
{ authenticable: resource}
2121
elsif resource && !active_for_authentication?(resource)
2222
if locked?(resource)
2323
raise_user_error(I18n.t('graphql_devise.mailer.unlock_instructions.account_lock_msg'))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module GraphqlDevise
2+
module Mutations
3+
class UpdatePassword < Base
4+
argument :password, String, required: true
5+
argument :password_confirmation, String, required: true
6+
argument :current_password, String, required: false
7+
8+
def resolve(current_password: nil, **attrs)
9+
if current_resource.blank?
10+
raise_user_error(I18n.t('graphql_devise.not_authenticated'))
11+
elsif current_resource.provider != 'email'
12+
raise_user_error(
13+
I18n.t('graphql_devise.passwords.password_not_required', provider: current_resource.provider.humanize)
14+
)
15+
end
16+
17+
if update_cresource_password(current_password, attrs)
18+
current_resource.allow_password_change = false if recoverable_enabled?
19+
current_resource.save!
20+
21+
yield current_resource if block_given?
22+
23+
{ authenticable: current_resource }
24+
else
25+
raise_user_error_list(
26+
I18n.t('graphql_devise.passwords.update_password_error'),
27+
errors: current_resource.errors.full_messages
28+
)
29+
end
30+
end
31+
32+
private
33+
34+
def update_cresource_password(current_password, attrs)
35+
allow_password_change = recoverable_enabled? && current_resource.allow_password_change == true
36+
if DeviseTokenAuth.check_current_password_before_update == false || allow_password_change
37+
current_resource.public_send(:update, attrs)
38+
else
39+
current_resource.public_send(:update_with_password, attrs.merge(current_password: current_password))
40+
end
41+
end
42+
end
43+
end
44+
end

config/locales/en.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
en:
22
graphql_devise:
3+
not_authenticated: "User is not logged in."
34
user_not_found: "User was not found or was not logged in."
5+
passwords:
6+
update_password_error: "Unable to update user password"
7+
missing_passwords: "You must fill out the fields labeled 'Password' and 'Password confirmation'."
8+
password_not_required: "This account does not require a password. Sign in using your '%{provider}' account instead."
49
sessions:
510
bad_credentials: "Invalid login credentials. Please try again."
611
not_confirmed: "A confirmation email was sent to your account at '%{email}'. You must follow the instructions in the email before your account can be activated"

lib/graphql_devise.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ class Error < StandardError; end
99
end
1010

1111
require 'graphql_devise/user_error'
12+
require 'graphql_devise/detailed_user_error'
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module GraphqlDevise
2+
class DetailedUserError < GraphQL::ExecutionError
3+
def initialize(message, errors:)
4+
@message = message
5+
@errors = errors
6+
7+
super(message)
8+
end
9+
10+
def to_h
11+
super.merge(extensions: { code: 'USER_ERROR', detailed_errors: @errors })
12+
end
13+
end
14+
end

lib/graphql_devise/rails/routes.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@ def mount_graphql_devise_for(resource, opts = {})
1919
GraphqlDevise::Types::AuthenticableType
2020

2121
default_mutations = {
22-
login: GraphqlDevise::Mutations::Login,
23-
logout: GraphqlDevise::Mutations::Logout
22+
login: GraphqlDevise::Mutations::Login,
23+
logout: GraphqlDevise::Mutations::Logout,
24+
update_password: GraphqlDevise::Mutations::UpdatePassword
2425
}.freeze
2526

2627
default_mutations.each do |action, mutation|
2728
used_mutation = if mutation_options[action].present?
2829
mutation_options[action]
2930
else
3031
new_mutation = Class.new(mutation)
31-
new_mutation.graphql_name("#{resource}#{action.to_s.titleize}")
32+
new_mutation.graphql_name("#{resource}#{action.to_s.camelize(:upper)}")
3233
new_mutation.field(:authenticable, authenticable_type, null: true)
3334

3435
new_mutation

spec/dummy/config/initializers/devise_token_auth.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# client is responsible for keeping track of the changing tokens. Change
66
# this to false to prevent the Authorization header from changing after
77
# each request.
8-
# config.change_headers_on_each_request = true
8+
config.change_headers_on_each_request = false
99

1010
# By default, users will need to re-authenticate after 2 weeks. This setting
1111
# determines how long tokens will remain valid after they are issued.
@@ -35,7 +35,7 @@
3535
# Uncomment to enforce current_password param to be checked before all
3636
# attribute updates. Set it to :password if you want it to be checked only if
3737
# password is updated.
38-
# config.check_current_password_before_update = :attributes
38+
config.check_current_password_before_update = :password
3939

4040
# By default we will use callbacks for single omniauth.
4141
# It depends on fields like email, provider and uid.

spec/requests/mutations/login_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
GRAPHQL
1919
end
2020

21-
before { post '/api/v1/graphql_auth', *graphql_params }
21+
before { post_request }
2222

2323
context 'when user is able to login' do
2424
context 'when credentials are valid' do

spec/requests/mutations/logout_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
let(:query) do
88
<<-GRAPHQL
99
mutation {
10-
userLogout{
10+
userLogout {
1111
authenticable { email }
1212
}
1313
}
1414
GRAPHQL
1515
end
1616

17-
before { post '/api/v1/graphql_auth', *graphql_params }
17+
before { post_request }
1818

1919
context 'when user is logged in' do
2020
let(:headers) { user.create_new_auth_token }

0 commit comments

Comments
 (0)