graphql_devise 0.12.1 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +12 -18
- data/app/controllers/graphql_devise/concerns/set_user_by_token.rb +6 -4
- data/app/views/graphql_devise/mailer/confirmation_instructions.html.erb +1 -1
- data/app/views/graphql_devise/mailer/reset_password_instructions.html.erb +1 -1
- data/lib/graphql_devise/mutations/resend_confirmation.rb +2 -1
- data/lib/graphql_devise/mutations/send_password_reset.rb +2 -1
- data/lib/graphql_devise/mutations/sign_up.rb +2 -1
- data/lib/graphql_devise/schema_plugin.rb +22 -3
- data/lib/graphql_devise/version.rb +1 -1
- data/spec/dummy/app/controllers/api/v1/graphql_controller.rb +33 -4
- data/spec/dummy/app/graphql/dummy_schema.rb +10 -1
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/requests/mutations/resend_confirmation_spec.rb +43 -16
- data/spec/requests/mutations/send_password_reset_spec.rb +35 -12
- data/spec/requests/queries/confirm_account_spec.rb +7 -1
- data/spec/requests/user_controller_spec.rb +9 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce5d1b0155098a6df8da7563448cb688b00cac2bdff8b039ed201b3cfae6f189
|
4
|
+
data.tar.gz: d9c09f2ba1418aa4b1e75f744ae29bc9d8bc767544c8d6f2e705a59f2e444bfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53b3ca8e55ddb9264fe1091e4767ee955f4c5c20664cbacdad850fc460582f5ed3e5633eedcaa7e1b7c7bfcfaf70eee792fd133ba2390c784867521bc9922acd
|
7
|
+
data.tar.gz: 6320f6ec2568659db16b80d03c8dce7275237f36865078fb724578b73e5f5879f90a221b87d7dd062e798016f329264b2ba48d23db67506b05e3746f1b0bc474
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.12.2](https://github.com/graphql-devise/graphql_devise/tree/v0.12.2) (2020-06-17)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v0.12.1...v0.12.2)
|
6
|
+
|
7
|
+
**Breaking changes:**
|
8
|
+
|
9
|
+
- Fix set\_resource\_by\_token no mapping error in no eager load envs [\#107](https://github.com/graphql-devise/graphql_devise/pull/107) ([mcelicalderon](https://github.com/mcelicalderon))
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- Separate endpoint url for mailers even if mounting the gem in your own schema [\#105](https://github.com/graphql-devise/graphql_devise/issues/105)
|
14
|
+
- Devise mapping error [\#103](https://github.com/graphql-devise/graphql_devise/issues/103)
|
15
|
+
- Use the url where the schema is mounted in emails links [\#106](https://github.com/graphql-devise/graphql_devise/pull/106) ([00dav00](https://github.com/00dav00))
|
16
|
+
|
3
17
|
## [v0.12.1](https://github.com/graphql-devise/graphql_devise/tree/v0.12.1) (2020-06-12)
|
4
18
|
|
5
19
|
[Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v0.12.0...v0.12.1)
|
data/README.md
CHANGED
@@ -343,8 +343,7 @@ and an error is returned in a REST format as the request never reaches your GQL
|
|
343
343
|
|
344
344
|
#### Authenticate in Your GQL Schema
|
345
345
|
For this you will need to add the `GraphqlDevise::SchemaPlugin` to your schema as described
|
346
|
-
[here](#mounting-operations-into-your-own-schema)
|
347
|
-
in a `before_action` hook.
|
346
|
+
[here](#mounting-operations-into-your-own-schema).
|
348
347
|
|
349
348
|
```ruby
|
350
349
|
# app/controllers/my_controller.rb
|
@@ -352,29 +351,24 @@ in a `before_action` hook.
|
|
352
351
|
class MyController < ApplicationController
|
353
352
|
include GraphqlDevise::Concerns::SetUserByToken
|
354
353
|
|
355
|
-
before_action -> { set_resource_by_token(:user) }
|
356
|
-
|
357
354
|
def my_action
|
358
|
-
render json: DummySchema.execute(params[:query], context: graphql_context)
|
355
|
+
render json: DummySchema.execute(params[:query], context: graphql_context(:user))
|
359
356
|
end
|
360
357
|
end
|
361
|
-
|
362
|
-
# @resource.to_s.underscore.tr('/', '_').to_sym
|
363
358
|
```
|
364
|
-
The `
|
359
|
+
The `graphql_context` method receives a symbol identifying the resource you are trying
|
365
360
|
to authenticate. So if you mounted the `'User'` resource, the symbol is `:user`. You can use
|
366
361
|
this snippet to find the symbol for more complex scenarios
|
367
|
-
`resource_klass.to_s.underscore.tr('/', '_').to_sym`.
|
362
|
+
`resource_klass.to_s.underscore.tr('/', '_').to_sym`. `graphql_context` can also take an
|
363
|
+
array of resources if you mounted more than one into your schema. The gem will try to
|
364
|
+
authenticate a resource for each element on the array until it finds one.
|
368
365
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
the provided authentication headers are valid. If authentication fails, resource will be `nil`
|
376
|
-
and this is how `GraphqlDevise::SchemaPlugin` knows if a user is authenticated or not in
|
377
|
-
each query.
|
366
|
+
Internally in your own mutations and queries a key `current_resource` will be available in
|
367
|
+
the context if a resource was successfully authenticated or `nil` otherwise.
|
368
|
+
|
369
|
+
Keep in mind that sending multiple values to the `graphql_context` method means that depending
|
370
|
+
on who makes the request, the context value `current_resource` might contain instances of the
|
371
|
+
different models you might have mounted into the schema.
|
378
372
|
|
379
373
|
Please note that by using this mechanism your GQL schema will be in control of what queries are
|
380
374
|
restricted to authenticated users and you can only do this at the root level fields of your GQL
|
@@ -5,12 +5,14 @@ module GraphqlDevise
|
|
5
5
|
SetUserByToken.module_eval do
|
6
6
|
attr_accessor :client_id, :token, :resource
|
7
7
|
|
8
|
-
|
8
|
+
def set_resource_by_token(resource)
|
9
|
+
set_user_by_token(resource)
|
10
|
+
end
|
9
11
|
|
10
|
-
def graphql_context
|
12
|
+
def graphql_context(resource_name)
|
11
13
|
{
|
12
|
-
|
13
|
-
controller:
|
14
|
+
resource_name: resource_name,
|
15
|
+
controller: self
|
14
16
|
}
|
15
17
|
end
|
16
18
|
|
@@ -2,4 +2,4 @@
|
|
2
2
|
|
3
3
|
<p><%= t('.confirm_link_msg') %></p>
|
4
4
|
|
5
|
-
<p><%= link_to t('.confirm_account_link'), url_for(controller: '
|
5
|
+
<p><%= link_to t('.confirm_account_link'), url_for(controller: message['controller'], action: message['action'], **confirmation_query(resource_name: @resource.class.to_s, redirect_url: message['redirect-url'], token: @token)) %></p>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
<p><%= t('.request_reset_link_msg') %></p>
|
4
4
|
|
5
|
-
<p><%= link_to t('.password_change_link'), url_for(controller: '
|
5
|
+
<p><%= link_to t('.password_change_link'), url_for(controller: message['controller'], action: message['action'], **password_reset_query(token: @token, redirect_url: message['redirect-url'], resource_name: @resource.class.to_s)) %></p>
|
6
6
|
|
7
7
|
<p><%= t('.ignore_mail_msg') %></p>
|
8
8
|
<p><%= t('.no_changes_msg') %></p>
|
@@ -19,7 +19,8 @@ module GraphqlDevise
|
|
19
19
|
|
20
20
|
resource.send_confirmation_instructions(
|
21
21
|
redirect_url: redirect_url,
|
22
|
-
template_path: ['graphql_devise/mailer']
|
22
|
+
template_path: ['graphql_devise/mailer'],
|
23
|
+
**controller.params.permit('controller', 'action').to_h.symbolize_keys
|
23
24
|
)
|
24
25
|
|
25
26
|
{ message: I18n.t('graphql_devise.confirmations.send_instructions', email: email) }
|
@@ -16,7 +16,8 @@ module GraphqlDevise
|
|
16
16
|
email: email,
|
17
17
|
provider: 'email',
|
18
18
|
redirect_url: redirect_url,
|
19
|
-
template_path: ['graphql_devise/mailer']
|
19
|
+
template_path: ['graphql_devise/mailer'],
|
20
|
+
**controller.params.permit('controller', 'action').to_h.symbolize_keys
|
20
21
|
)
|
21
22
|
|
22
23
|
if resource.errors.empty?
|
@@ -27,7 +27,8 @@ module GraphqlDevise
|
|
27
27
|
unless resource.confirmed?
|
28
28
|
resource.send_confirmation_instructions(
|
29
29
|
redirect_url: confirm_success_url,
|
30
|
-
template_path: ['graphql_devise/mailer']
|
30
|
+
template_path: ['graphql_devise/mailer'],
|
31
|
+
**controller.params.permit('controller', 'action').to_h.symbolize_keys
|
31
32
|
)
|
32
33
|
end
|
33
34
|
|
@@ -23,11 +23,12 @@ module GraphqlDevise
|
|
23
23
|
|
24
24
|
field = traced_field(trace_data)
|
25
25
|
provided_value = authenticate_option(field, trace_data)
|
26
|
+
context = set_current_resource(context_from_data(trace_data))
|
26
27
|
|
27
28
|
if !provided_value.nil?
|
28
|
-
raise_on_missing_resource(context
|
29
|
+
raise_on_missing_resource(context, field) if provided_value
|
29
30
|
elsif @authenticate_default
|
30
|
-
raise_on_missing_resource(context
|
31
|
+
raise_on_missing_resource(context, field)
|
31
32
|
end
|
32
33
|
|
33
34
|
yield
|
@@ -35,11 +36,29 @@ module GraphqlDevise
|
|
35
36
|
|
36
37
|
private
|
37
38
|
|
39
|
+
def set_current_resource(context)
|
40
|
+
controller = context[:controller]
|
41
|
+
resource_names = Array(context[:resource_name])
|
42
|
+
context[:current_resource] = resource_names.find do |resource_name|
|
43
|
+
unless Devise.mappings.key?(resource_name)
|
44
|
+
raise(
|
45
|
+
GraphqlDevise::Error,
|
46
|
+
"Invalid resource_name `#{resource_name}` provided to `graphql_context`. Possible values are: #{Devise.mappings.keys}."
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
found = controller.set_resource_by_token(resource_name)
|
51
|
+
break found if found
|
52
|
+
end
|
53
|
+
|
54
|
+
context
|
55
|
+
end
|
56
|
+
|
38
57
|
def raise_on_missing_resource(context, field)
|
39
58
|
@unauthenticated_proc.call(field.name) if context[:current_resource].blank?
|
40
59
|
end
|
41
60
|
|
42
|
-
def
|
61
|
+
def context_from_data(trace_data)
|
43
62
|
query = if trace_data[:context]
|
44
63
|
trace_data[:context].query
|
45
64
|
else
|
@@ -3,18 +3,47 @@ module Api
|
|
3
3
|
class GraphqlController < ApplicationController
|
4
4
|
include GraphqlDevise::Concerns::SetUserByToken
|
5
5
|
|
6
|
-
before_action -> { set_resource_by_token(:user) }
|
7
|
-
|
8
6
|
def graphql
|
9
|
-
|
7
|
+
result = DummySchema.execute(params[:query], execute_params(params))
|
8
|
+
|
9
|
+
render json: result unless performed?
|
10
10
|
end
|
11
11
|
|
12
12
|
def interpreter
|
13
|
-
render json: InterpreterSchema.execute(params[:query],
|
13
|
+
render json: InterpreterSchema.execute(params[:query], execute_params(params))
|
14
|
+
end
|
15
|
+
|
16
|
+
def failing_resource_name
|
17
|
+
render json: DummySchema.execute(params[:query], context: graphql_context([:user, :fail]))
|
14
18
|
end
|
15
19
|
|
16
20
|
private
|
17
21
|
|
22
|
+
def execute_params(item)
|
23
|
+
{
|
24
|
+
operation_name: item[:operationName],
|
25
|
+
variables: ensure_hash(item[:variables]),
|
26
|
+
context: graphql_context(:user)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def ensure_hash(ambiguous_param)
|
31
|
+
case ambiguous_param
|
32
|
+
when String
|
33
|
+
if ambiguous_param.present?
|
34
|
+
ensure_hash(JSON.parse(ambiguous_param))
|
35
|
+
else
|
36
|
+
{}
|
37
|
+
end
|
38
|
+
when Hash, ActionController::Parameters
|
39
|
+
ambiguous_param
|
40
|
+
when nil
|
41
|
+
{}
|
42
|
+
else
|
43
|
+
raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
18
47
|
def verify_authenticity_token
|
19
48
|
end
|
20
49
|
end
|
@@ -3,7 +3,16 @@ class DummySchema < GraphQL::Schema
|
|
3
3
|
query: Types::QueryType,
|
4
4
|
mutation: Types::MutationType,
|
5
5
|
resource_loaders: [
|
6
|
-
GraphqlDevise::ResourceLoader.new(
|
6
|
+
GraphqlDevise::ResourceLoader.new(
|
7
|
+
'User',
|
8
|
+
only: [
|
9
|
+
:login,
|
10
|
+
:confirm_account,
|
11
|
+
:send_password_reset,
|
12
|
+
:resend_confirmation,
|
13
|
+
:check_password_token
|
14
|
+
]
|
15
|
+
),
|
7
16
|
GraphqlDevise::ResourceLoader.new('Guest', only: [:logout])
|
8
17
|
]
|
9
18
|
)
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -27,6 +27,8 @@ Rails.application.routes.draw do
|
|
27
27
|
at: '/api/v1/user_customer/graphql_auth'
|
28
28
|
)
|
29
29
|
|
30
|
+
get '/api/v1/graphql', to: 'api/v1/graphql#graphql'
|
30
31
|
post '/api/v1/graphql', to: 'api/v1/graphql#graphql'
|
31
32
|
post '/api/v1/interpreter', to: 'api/v1/graphql#interpreter'
|
33
|
+
post '/api/v1/failing', to: 'api/v1/graphql#failing_resource_name'
|
32
34
|
end
|
@@ -21,25 +21,52 @@ RSpec.describe 'Resend confirmation' do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
context 'when params are correct' do
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
context 'when using the gem schema' do
|
25
|
+
it 'sends an email to the user with confirmation url and returns a success message' do
|
26
|
+
expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
|
27
|
+
expect(json_response[:data][:userResendConfirmation]).to include(
|
28
|
+
message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.'
|
29
|
+
)
|
30
|
+
|
31
|
+
email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
|
32
|
+
link = email.css('a').first
|
33
|
+
confirm_link_msg_text = email.css('p')[1].inner_html
|
34
|
+
confirm_account_link_text = link.inner_html
|
35
|
+
|
36
|
+
expect(link['href']).to include('/api/v1/graphql_auth?')
|
37
|
+
expect(confirm_link_msg_text).to eq('You can confirm your account email through the link below:')
|
38
|
+
expect(confirm_account_link_text).to eq('Confirm my account')
|
39
|
+
|
40
|
+
expect do
|
41
|
+
get link['href']
|
42
|
+
user.reload
|
43
|
+
end.to change(user, :confirmed_at).from(NilClass).to(ActiveSupport::TimeWithZone)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when using a custom schema' do
|
48
|
+
let(:custom_path) { '/api/v1/graphql' }
|
49
|
+
|
50
|
+
it 'sends an email to the user with confirmation url and returns a success message' do
|
51
|
+
expect { post_request(custom_path) }.to change(ActionMailer::Base.deliveries, :count).by(1)
|
52
|
+
expect(json_response[:data][:userResendConfirmation]).to include(
|
53
|
+
message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.'
|
54
|
+
)
|
29
55
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
56
|
+
email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
|
57
|
+
link = email.css('a').first
|
58
|
+
confirm_link_msg_text = email.css('p')[1].inner_html
|
59
|
+
confirm_account_link_text = link.inner_html
|
34
60
|
|
35
|
-
|
36
|
-
|
61
|
+
expect(link['href']).to include("#{custom_path}?")
|
62
|
+
expect(confirm_link_msg_text).to eq('You can confirm your account email through the link below:')
|
63
|
+
expect(confirm_account_link_text).to eq('Confirm my account')
|
37
64
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
user.
|
42
|
-
end
|
65
|
+
expect do
|
66
|
+
get link['href']
|
67
|
+
user.reload
|
68
|
+
end.to change(user, :confirmed_at).from(NilClass).to(ActiveSupport::TimeWithZone)
|
69
|
+
end
|
43
70
|
end
|
44
71
|
|
45
72
|
context 'when email address uses different casing' do
|
@@ -20,21 +20,44 @@ RSpec.describe 'Send Password Reset Requests' do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'when params are correct' do
|
23
|
-
|
24
|
-
|
23
|
+
context 'when using the gem schema' do
|
24
|
+
it 'sends password reset email' do
|
25
|
+
expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
expect(json_response[:data][:userSendPasswordReset]).to include(
|
28
|
+
message: 'You will receive an email with instructions on how to reset your password in a few minutes.'
|
29
|
+
)
|
30
|
+
|
31
|
+
email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
|
32
|
+
link = email.css('a').first
|
33
|
+
expect(link['href']).to include('/api/v1/graphql_auth?')
|
34
|
+
|
35
|
+
expect do
|
36
|
+
get link['href']
|
37
|
+
user.reload
|
38
|
+
end.to change(user, :allow_password_change).from(false).to(true)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when using a custom schema' do
|
43
|
+
let(:custom_path) { '/api/v1/graphql' }
|
44
|
+
|
45
|
+
it 'sends password reset email' do
|
46
|
+
expect { post_request(custom_path) }.to change(ActionMailer::Base.deliveries, :count).by(1)
|
47
|
+
|
48
|
+
expect(json_response[:data][:userSendPasswordReset]).to include(
|
49
|
+
message: 'You will receive an email with instructions on how to reset your password in a few minutes.'
|
50
|
+
)
|
29
51
|
|
30
|
-
|
31
|
-
|
52
|
+
email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
|
53
|
+
link = email.css('a').first
|
54
|
+
expect(link['href']).to include("#{custom_path}?")
|
32
55
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
user.
|
37
|
-
end
|
56
|
+
expect do
|
57
|
+
get link['href']
|
58
|
+
user.reload
|
59
|
+
end.to change(user, :allow_password_change).from(false).to(true)
|
60
|
+
end
|
38
61
|
end
|
39
62
|
end
|
40
63
|
|
@@ -22,7 +22,13 @@ RSpec.describe 'Account confirmation' do
|
|
22
22
|
context 'when confirmation token is correct' do
|
23
23
|
let(:token) { user.confirmation_token }
|
24
24
|
|
25
|
-
before
|
25
|
+
before do
|
26
|
+
user.send_confirmation_instructions(
|
27
|
+
template_path: ['graphql_devise/mailer'],
|
28
|
+
controller: 'graphql_devise/graphql',
|
29
|
+
action: 'auth'
|
30
|
+
)
|
31
|
+
end
|
26
32
|
|
27
33
|
it 'confirms the resource and redirects to the sent url' do
|
28
34
|
expect do
|
@@ -29,6 +29,15 @@ RSpec.describe "Integrations with the user's controller" do
|
|
29
29
|
expect(json_response[:data][:publicField]).to eq('Field does not require authentication')
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
context 'when using the failing route' do
|
34
|
+
it 'raises an invalid resource_name error' do
|
35
|
+
expect { post_request('/api/v1/failing') }.to raise_error(
|
36
|
+
GraphqlDevise::Error,
|
37
|
+
'Invalid resource_name `fail` provided to `graphql_context`. Possible values are: [:user, :admin, :guest, :users_customer].'
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
32
41
|
end
|
33
42
|
|
34
43
|
describe 'privateField' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_devise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mario Celi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-06-
|
12
|
+
date: 2020-06-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: devise_token_auth
|