graphql_devise 0.12.1 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64f2bd00ac9c5edc119bb83326ffa996ab57a5551474887281857ef10ee7abb9
4
- data.tar.gz: a8e1b662d697f4e8f94faf41b3ccbfec9b4ae6eb295ee4ee004c80d0c2b723bb
3
+ metadata.gz: ce5d1b0155098a6df8da7563448cb688b00cac2bdff8b039ed201b3cfae6f189
4
+ data.tar.gz: d9c09f2ba1418aa4b1e75f744ae29bc9d8bc767544c8d6f2e705a59f2e444bfd
5
5
  SHA512:
6
- metadata.gz: c6be77b7524f9a3cbf17b047fc5fbedc5d2cc0158ee343bdb470fe468774d3c3c7b1b0e80f2d529d623e3e74f32bf6d61f1dd220ebc2e66d7863346cedafde25
7
- data.tar.gz: c6264ad438bfbec20b53c77bf9997e0a2a6d4ef184488f0a4830e5cad7c7f8f01112e163ec1fb0b5ed86718e488899373706245f22fc6c754280c74daec8a510
6
+ metadata.gz: 53b3ca8e55ddb9264fe1091e4767ee955f4c5c20664cbacdad850fc460582f5ed3e5633eedcaa7e1b7c7bfcfaf70eee792fd133ba2390c784867521bc9922acd
7
+ data.tar.gz: 6320f6ec2568659db16b80d03c8dce7275237f36865078fb724578b73e5f5879f90a221b87d7dd062e798016f329264b2ba48d23db67506b05e3746f1b0bc474
@@ -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) and also set the authenticated resource
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 `set_resource_by_token` method receives a symbol identifying the resource you are trying
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
- The `graphql_context` method is simply a helper method that returns a hash like this
370
- ```ruby
371
- { current_resource: @resource, controller: self }
372
- ```
373
- These are the two values the gem needs to check if a user is authenticated and to perform
374
- other auth operations. All `set_resource_by_token` does is set the `@resource` variable if
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
- alias_method :set_resource_by_token, :set_user_by_token
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
- current_resource: @resource,
13
- controller: self
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: 'graphql_devise/graphql', action: :auth, **confirmation_query(resource_name: @resource.class.to_s, redirect_url: message['redirect-url'], token: @token)) %></p>
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: 'graphql_devise/graphql', action: :auth, **password_reset_query(token: @token, redirect_url: message['redirect-url'], resource_name: @resource.class.to_s)) %></p>
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(trace_data), field) if provided_value
29
+ raise_on_missing_resource(context, field) if provided_value
29
30
  elsif @authenticate_default
30
- raise_on_missing_resource(context(trace_data), field)
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 context(trace_data)
61
+ def context_from_data(trace_data)
43
62
  query = if trace_data[:context]
44
63
  trace_data[:context].query
45
64
  else
@@ -1,3 +1,3 @@
1
1
  module GraphqlDevise
2
- VERSION = '0.12.1'.freeze
2
+ VERSION = '0.12.2'.freeze
3
3
  end
@@ -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
- render json: DummySchema.execute(params[:query], context: graphql_context)
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], context: graphql_context)
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('User', only: [:login, :confirm_account]),
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
  )
@@ -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
- it 'sends an email to the user with confirmation url and returns a success message' do
25
- expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
26
- expect(json_response[:data][:userResendConfirmation]).to include(
27
- message: 'You will receive an email with instructions for how to confirm your email address in a few minutes.'
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
- email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
31
- link = email.css('a').first
32
- confirm_link_msg_text = email.css('p')[1].inner_html
33
- confirm_account_link_text = link.inner_html
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
- expect(confirm_link_msg_text).to eq('You can confirm your account email through the link below:')
36
- expect(confirm_account_link_text).to eq('Confirm my account')
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
- # TODO: Move to feature spec
39
- expect do
40
- get link['href']
41
- user.reload
42
- end.to change(user, :confirmed_at).from(NilClass).to(ActiveSupport::TimeWithZone)
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
- it 'sends password reset email' do
24
- expect { post_request }.to change(ActionMailer::Base.deliveries, :count).by(1)
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
- expect(json_response[:data][:userSendPasswordReset]).to include(
27
- message: 'You will receive an email with instructions on how to reset your password in a few minutes.'
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
- email = Nokogiri::HTML(ActionMailer::Base.deliveries.last.body.encoded)
31
- link = email.css('a').first
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
- # TODO: Move to feature spec
34
- expect do
35
- get link['href']
36
- user.reload
37
- end.to change(user, :allow_password_change).from(false).to(true)
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 { user.send_confirmation_instructions(template_path: ['graphql_devise/mailer']) }
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.1
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 00:00:00.000000000 Z
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