graphql_devise 0.15.0 → 0.16.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f90be997c50518d79c6b3fdaee2f896aeec557ca5084a6bac7059a518dd8ec3
4
- data.tar.gz: e25b07dee790cd64a48a07970974c6ae3e2a567c9a75321f7af69c693140a342
3
+ metadata.gz: 12c52068c8c538bc35dc67deb2d697101e1fa001419ccdbff23183e854f5f404
4
+ data.tar.gz: 65afe18384fb742e8dbc300d19b227815ebe166997147031bbabd63742738205
5
5
  SHA512:
6
- metadata.gz: 8453243ec0816b2fc828c13f1033b70e97ae71d68c2938af469a435f99a1b26369f0482a4abcda50fbf61c1a9d1fbde12b47a51f6fa42fdbb29afe5aa7f8760e
7
- data.tar.gz: 0fb0ef651e1be37157948ce48e24690ec741e543abf5771ad85f6380a640efb9b772195b16132685887cef9eb8f03d923a12406c99877100c6f13408a70280d8
6
+ metadata.gz: fcf10385aeb27e02f283fa5b5d140f51352508d4a9973dd374edfe78b67a64cfa9b4183e39a8065af5a9697569fac4ed9c21aa007df26fd271b6739c2f9cd5a9
7
+ data.tar.gz: d3f45d87972e29a325375c1868fced4ef377effcfba6be182c7d8c0b34bdfd6032db66097f0304416ff5966b532fea994d135be0ee48a070c2369668acc3beb2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.16.0](https://github.com/graphql-devise/graphql_devise/tree/v0.16.0) (2021-05-20)
4
+
5
+ [Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v0.15.0...v0.16.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Allow checking of authenticaded resource via callable object [\#180](https://github.com/graphql-devise/graphql_devise/pull/180) ([mcelicalderon](https://github.com/mcelicalderon))
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Document authenticate with callable [\#181](https://github.com/graphql-devise/graphql_devise/pull/181) ([mcelicalderon](https://github.com/mcelicalderon))
14
+
3
15
  ## [v0.15.0](https://github.com/graphql-devise/graphql_devise/tree/v0.15.0) (2021-05-09)
4
16
 
5
17
  [Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v0.14.3...v0.15.0)
data/README.md CHANGED
@@ -28,8 +28,10 @@ GraphQL interface on top of the [Devise Token Auth](https://github.com/lynndylan
28
28
  * [I18n](#i18n)
29
29
  * [Authenticating Controller Actions](#authenticating-controller-actions)
30
30
  * [Authenticate Resource in the Controller (>= v0.15.0)](#authenticate-resource-in-the-controller--v0150)
31
+ * [Authentication Options](#authentication-options)
31
32
  * [Authenticate Before Reaching Your GQL Schema (Deprecated)](#authenticate-before-reaching-your-gql-schema-deprecated)
32
33
  * [Authenticate in Your GQL Schema (Deprecated)](#authenticate-in-your-gql-schema-deprecated)
34
+ * [Authentication Options](#authentication-options-1)
33
35
  * [Important](#important-2)
34
36
  * [Making Requests](#making-requests)
35
37
  * [Introspection query](#introspection-query)
@@ -45,7 +47,7 @@ GraphQL interface on top of the [Devise Token Auth](https://github.com/lynndylan
45
47
  * [Contributing](#contributing)
46
48
  * [License](#license)
47
49
 
48
- <!-- Added by: mcelicalderon, at: Sat May 8 12:32:03 -05 2021 -->
50
+ <!-- Added by: mcelicalderon, at: Wed May 19 21:25:22 -05 2021 -->
49
51
 
50
52
  <!--te-->
51
53
 
@@ -432,7 +434,13 @@ restricted to authenticated users and you can only do this at the root level fie
432
434
  schema. Configure the plugin as explained [here](#mounting-operations-into-your-own-schema)
433
435
  so this can work.
434
436
 
435
- In you main app's schema this is how you might specify if a field needs to be authenticated or not:
437
+ ##### Authentication Options
438
+ Wether you setup authentications as a default in the plugin, or you do it at the field level,
439
+ these are the options you can use:
440
+ 1. **Any truthy value:** If `current_resource` is not `.present?`, query will return an authentication error.
441
+ 1. **A callable object:** Provided object will be called with `current_resource` as the only argument if `current_resource` is `.present?`. If return value of the callable object is false, query will return an authentication error.
442
+
443
+ In your main app's schema this is how you might specify if a field needs to be authenticated or not:
436
444
  ```ruby
437
445
  module Types
438
446
  class QueryType < Types::BaseObject
@@ -442,13 +450,11 @@ module Types
442
450
  field :public_field, String, null: false, authenticate: false
443
451
  # this field requires authentication
444
452
  field :private_field, String, null: false, authenticate: true
453
+ # this field requires authenticated users to also be admins
454
+ field :admin_field, String, null: false, authenticate: ->(user) { user.admin? }
445
455
  end
446
456
  end
447
457
  ```
448
- **Important:** Currently, the only check the plugin does to see if the user is authenticated or not when executing
449
- the query, is verifying that `context[:current_resource].present?` in the GraphQL context.
450
- So, be careful not to populate that key of the context with values other than what `gql_devise_context`
451
- returns. The option to do more complex verifications will be added in the future.
452
458
 
453
459
  #### Authenticate Before Reaching Your GQL Schema (Deprecated)
454
460
  For this you will need to call `authenticate_<model>!` in a `before_action` controller hook.
@@ -506,7 +512,13 @@ restricted to authenticated users and you can only do this at the root level fie
506
512
  schema. Configure the plugin as explained [here](#mounting-operations-into-your-own-schema)
507
513
  so this can work.
508
514
 
509
- In you main app's schema this is how you might specify if a field needs to be authenticated or not:
515
+ ##### Authentication Options
516
+ Wether you setup authentications as a default in the plugin, or you do it at the field level,
517
+ these are the options you can use:
518
+ 1. **Any truthy value:** If `current_resource` is not `.present?`, query will return an authentication error.
519
+ 1. **A callable object:** Provided object will be called with `current_resource` as the only argument if `current_resource` is `.present?`. If return value of the callable object is false, query will return an authentication error.
520
+
521
+ In your main app's schema this is how you might specify if a field needs to be authenticated or not:
510
522
  ```ruby
511
523
  module Types
512
524
  class QueryType < Types::BaseObject
@@ -516,6 +528,8 @@ module Types
516
528
  field :public_field, String, null: false, authenticate: false
517
529
  # this field requires authentication
518
530
  field :private_field, String, null: false, authenticate: true
531
+ # this field requires authenticated users to also be admins
532
+ field :admin_field, String, null: false, authenticate: ->(user) { user.admin? }
519
533
  end
520
534
  end
521
535
  ```
@@ -46,7 +46,7 @@ module GraphqlDevise
46
46
 
47
47
  if auth_required && !(public_introspection && introspection_field?(field))
48
48
  context = set_current_resource(context)
49
- raise_on_missing_resource(context, field)
49
+ raise_on_missing_resource(context, field, auth_required)
50
50
  end
51
51
 
52
52
  yield
@@ -75,8 +75,12 @@ module GraphqlDevise
75
75
  context
76
76
  end
77
77
 
78
- def raise_on_missing_resource(context, field)
78
+ def raise_on_missing_resource(context, field, auth_required)
79
79
  @unauthenticated_proc.call(field.name) if context[:current_resource].blank?
80
+
81
+ if auth_required.respond_to?(:call) && !auth_required.call(context[:current_resource])
82
+ @unauthenticated_proc.call(field.name)
83
+ end
80
84
  end
81
85
 
82
86
  def context_from_data(trace_data)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphqlDevise
4
- VERSION = '0.15.0'.freeze
4
+ VERSION = '0.16.0'.freeze
5
5
  end
@@ -5,6 +5,7 @@ module Types
5
5
  field :user, resolver: Resolvers::UserShow
6
6
  field :public_field, String, null: false, authenticate: false
7
7
  field :private_field, String, null: false, authenticate: true
8
+ field :vip_field, String, null: false, authenticate: ->(user) { user.is_a?(User) && user.vip? }
8
9
 
9
10
  def public_field
10
11
  'Field does not require authentication'
@@ -13,5 +14,9 @@ module Types
13
14
  def private_field
14
15
  'Field will always require authentication'
15
16
  end
17
+
18
+ def vip_field
19
+ 'Field available only for VIP Users'
20
+ end
16
21
  end
17
22
  end
@@ -0,0 +1,5 @@
1
+ class AddVipToUsers < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :users, :vip, :boolean, null: false, default: false
4
+ end
5
+ end
@@ -2,15 +2,15 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # This file is the source Rails uses to define your schema when running `rails
6
- # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
7
  # be faster and is potentially less error prone than running all of your
8
8
  # migrations from scratch. Old migrations may fail to apply correctly if those
9
9
  # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2020_06_23_003142) do
13
+ ActiveRecord::Schema.define(version: 2021_05_16_211417) do
14
14
 
15
15
  create_table "admins", force: :cascade do |t|
16
16
  t.string "provider", default: "email", null: false
@@ -105,6 +105,7 @@ ActiveRecord::Schema.define(version: 2020_06_23_003142) do
105
105
  t.datetime "created_at", null: false
106
106
  t.datetime "updated_at", null: false
107
107
  t.boolean "auth_available", default: true, null: false
108
+ t.boolean "vip", default: false, null: false
108
109
  t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
109
110
  t.index ["email"], name: "index_users_on_email", unique: true
110
111
  t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
@@ -5,6 +5,14 @@ require 'rails_helper'
5
5
  RSpec.describe "Integrations with the user's controller" do
6
6
  include_context 'with graphql query request'
7
7
 
8
+ shared_examples 'returns a must authenticate error' do |field|
9
+ it 'returns a must sign in error' do
10
+ expect(json_response[:errors]).to contain_exactly(
11
+ hash_including(message: "#{field} field requires authentication", extensions: { code: 'AUTHENTICATION_ERROR' })
12
+ )
13
+ end
14
+ end
15
+
8
16
  let(:user) { create(:user, :confirmed) }
9
17
 
10
18
  describe 'publicField' do
@@ -54,11 +62,7 @@ RSpec.describe "Integrations with the user's controller" do
54
62
  end
55
63
 
56
64
  context 'when user is not authenticated' do
57
- it 'returns a must sign in error' do
58
- expect(json_response[:errors]).to contain_exactly(
59
- hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
60
- )
61
- end
65
+ it_behaves_like 'returns a must authenticate error', 'privateField'
62
66
  end
63
67
  end
64
68
 
@@ -82,11 +86,7 @@ RSpec.describe "Integrations with the user's controller" do
82
86
  end
83
87
 
84
88
  context 'when user is not authenticated' do
85
- it 'returns a must sign in error' do
86
- expect(json_response[:errors]).to contain_exactly(
87
- hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
88
- )
89
- end
89
+ it_behaves_like 'returns a must authenticate error', 'privateField'
90
90
  end
91
91
 
92
92
  context 'when using the failing route' do
@@ -111,11 +111,7 @@ RSpec.describe "Integrations with the user's controller" do
111
111
  end
112
112
 
113
113
  context 'when user is not authenticated' do
114
- it 'returns a must sign in error' do
115
- expect(json_response[:errors]).to contain_exactly(
116
- hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
117
- )
118
- end
114
+ it_behaves_like 'returns a must authenticate error', 'privateField'
119
115
  end
120
116
  end
121
117
  end
@@ -141,11 +137,7 @@ RSpec.describe "Integrations with the user's controller" do
141
137
  end
142
138
 
143
139
  context 'when user is not authenticated' do
144
- it 'returns a must sign in error' do
145
- expect(json_response[:errors]).to contain_exactly(
146
- hash_including(message: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
147
- )
148
- end
140
+ it_behaves_like 'returns a must authenticate error', 'dummyMutation'
149
141
  end
150
142
  end
151
143
 
@@ -161,11 +153,7 @@ RSpec.describe "Integrations with the user's controller" do
161
153
  end
162
154
 
163
155
  context 'when user is not authenticated' do
164
- it 'returns a must sign in error' do
165
- expect(json_response[:errors]).to contain_exactly(
166
- hash_including(message: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
167
- )
168
- end
156
+ it_behaves_like 'returns a must authenticate error', 'dummyMutation'
169
157
  end
170
158
  end
171
159
  end
@@ -199,11 +187,7 @@ RSpec.describe "Integrations with the user's controller" do
199
187
  end
200
188
 
201
189
  context 'when user is not authenticated' do
202
- it 'returns a must sign in error' do
203
- expect(json_response[:errors]).to contain_exactly(
204
- hash_including(message: 'user field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
205
- )
206
- end
190
+ it_behaves_like 'returns a must authenticate error', 'user'
207
191
  end
208
192
  end
209
193
 
@@ -271,4 +255,61 @@ RSpec.describe "Integrations with the user's controller" do
271
255
  )
272
256
  end
273
257
  end
258
+
259
+ describe 'vipField' do
260
+ let(:error_message) { 'Field available only for VIP Users' }
261
+ let(:query) do
262
+ <<-GRAPHQL
263
+ query { vipField }
264
+ GRAPHQL
265
+ end
266
+
267
+ context 'when using a regular schema' do
268
+ before { post_request('/api/v1/graphql') }
269
+
270
+ context 'when user is authenticated' do
271
+ let(:headers) { user.create_new_auth_token }
272
+
273
+ context 'when schema user is VIP' do
274
+ let(:user) { create(:user, :confirmed, vip: true) }
275
+
276
+ it 'allows to perform the query' do
277
+ expect(json_response[:data][:vipField]).to eq(error_message)
278
+ end
279
+ end
280
+
281
+ context 'when schema user is not VIP' do
282
+ it_behaves_like 'returns a must authenticate error', 'vipField'
283
+ end
284
+ end
285
+
286
+ context 'when user is not authenticated' do
287
+ it_behaves_like 'returns a must authenticate error', 'vipField'
288
+ end
289
+ end
290
+
291
+ context 'when using the interpreter schema' do
292
+ before { post_request('/api/v1/interpreter') }
293
+
294
+ context 'when user is authenticated' do
295
+ let(:headers) { user.create_new_auth_token }
296
+
297
+ context 'when schema user is VIP' do
298
+ let(:user) { create(:user, :confirmed, vip: true) }
299
+
300
+ it 'allows to perform the query' do
301
+ expect(json_response[:data][:vipField]).to eq(error_message)
302
+ end
303
+ end
304
+
305
+ context 'when schema user is not VIP' do
306
+ it_behaves_like 'returns a must authenticate error', 'vipField'
307
+ end
308
+ end
309
+
310
+ context 'when user is not authenticated' do
311
+ it_behaves_like 'returns a must authenticate error', 'vipField'
312
+ end
313
+ end
314
+ end
274
315
  end
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.15.0
4
+ version: 0.16.0
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: 2021-05-09 00:00:00.000000000 Z
12
+ date: 2021-05-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: devise_token_auth
@@ -425,6 +425,7 @@ files:
425
425
  - spec/dummy/db/migrate/20200321121807_create_users_customers.rb
426
426
  - spec/dummy/db/migrate/20200621182414_remove_uncofirmed_email_from_admins.rb
427
427
  - spec/dummy/db/migrate/20200623003142_create_schema_users.rb
428
+ - spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb
428
429
  - spec/dummy/db/schema.rb
429
430
  - spec/dummy/db/seeds.rb
430
431
  - spec/dummy/public/robots.txt
@@ -502,7 +503,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
502
503
  - !ruby/object:Gem::Version
503
504
  version: '0'
504
505
  requirements: []
505
- rubygems_version: 3.1.4
506
+ rubygems_version: 3.0.3
506
507
  signing_key:
507
508
  specification_version: 4
508
509
  summary: GraphQL queries and mutations on top of devise_token_auth
@@ -574,6 +575,7 @@ test_files:
574
575
  - spec/dummy/db/migrate/20200321121807_create_users_customers.rb
575
576
  - spec/dummy/db/migrate/20200621182414_remove_uncofirmed_email_from_admins.rb
576
577
  - spec/dummy/db/migrate/20200623003142_create_schema_users.rb
578
+ - spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb
577
579
  - spec/dummy/db/schema.rb
578
580
  - spec/dummy/db/seeds.rb
579
581
  - spec/dummy/public/robots.txt