graphql_devise 0.18.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +7 -2
- data/.gitignore +3 -0
- data/.rubocop.yml +9 -10
- data/Appraisals +70 -18
- data/CHANGELOG.md +53 -0
- data/README.md +71 -142
- data/app/controllers/graphql_devise/graphql_controller.rb +3 -3
- data/app/views/graphql_devise/mailer/confirmation_instructions.html.erb +1 -5
- data/config/routes.rb +0 -2
- data/graphql_devise.gemspec +7 -5
- data/lib/graphql_devise/concerns/additional_controller_methods.rb +48 -0
- data/lib/graphql_devise/concerns/additional_model_methods.rb +17 -0
- data/lib/graphql_devise/concerns/authenticatable.rb +1 -1
- data/lib/graphql_devise/concerns/controller_methods.rb +70 -93
- data/lib/graphql_devise/concerns/field_authentication.rb +14 -0
- data/lib/graphql_devise/concerns/set_user_by_token.rb +1 -1
- data/lib/graphql_devise/default_operations.rb +16 -0
- data/lib/graphql_devise/engine.rb +0 -2
- data/lib/graphql_devise/model/with_email_updater.rb +5 -30
- data/lib/graphql_devise/mount_method/operation_preparer.rb +0 -7
- data/lib/graphql_devise/mount_method/operation_preparers/custom_operation_preparer.rb +1 -1
- data/lib/graphql_devise/mount_method/operation_preparers/default_operation_preparer.rb +1 -1
- data/lib/graphql_devise/mount_method/operation_sanitizer.rb +0 -12
- data/lib/graphql_devise/mount_method/option_sanitizer.rb +0 -2
- data/lib/graphql_devise/mount_method/option_sanitizers/array_checker.rb +2 -2
- data/lib/graphql_devise/mount_method/option_sanitizers/class_checker.rb +2 -2
- data/lib/graphql_devise/mount_method/option_sanitizers/hash_checker.rb +1 -1
- data/lib/graphql_devise/mount_method/option_sanitizers/string_checker.rb +1 -1
- data/lib/graphql_devise/mount_method/option_validators/provided_operations_validator.rb +0 -2
- data/lib/graphql_devise/mount_method/option_validators/skip_only_validator.rb +1 -1
- data/lib/graphql_devise/mount_method/option_validators/supported_operations_validator.rb +1 -1
- data/lib/graphql_devise/mount_method/options_validator.rb +0 -3
- data/lib/graphql_devise/mount_method/supported_options.rb +0 -5
- data/lib/graphql_devise/mutations/base.rb +1 -1
- data/lib/graphql_devise/mutations/confirm_registration_with_token.rb +1 -1
- data/lib/graphql_devise/mutations/login.rb +1 -1
- data/lib/graphql_devise/mutations/register.rb +1 -1
- data/lib/graphql_devise/mutations/update_password_with_token.rb +1 -1
- data/lib/graphql_devise/resolvers/base.rb +1 -1
- data/lib/graphql_devise/resource_loader.rb +71 -39
- data/lib/graphql_devise/route_mounter.rb +13 -0
- data/lib/graphql_devise/schema_plugin.rb +7 -40
- data/lib/graphql_devise/types/authenticatable_type.rb +1 -1
- data/lib/graphql_devise/types/base_field.rb +9 -0
- data/lib/graphql_devise/types/base_type.rb +8 -0
- data/lib/graphql_devise/types/credential_type.rb +1 -1
- data/lib/graphql_devise/types/mutation_type.rb +1 -0
- data/lib/graphql_devise/types/query_type.rb +1 -0
- data/lib/graphql_devise/version.rb +1 -1
- data/lib/graphql_devise.rb +21 -29
- data/spec/dummy/app/controllers/api/v1/graphql_controller.rb +1 -16
- data/spec/dummy/app/graphql/dummy_schema.rb +1 -5
- data/spec/dummy/app/graphql/interpreter_schema.rb +6 -2
- data/spec/dummy/app/graphql/mutations/base_mutation.rb +6 -0
- data/spec/dummy/app/graphql/mutations/update_user.rb +2 -4
- data/spec/dummy/app/graphql/types/admin_type.rb +1 -1
- data/spec/dummy/app/graphql/types/custom_admin_type.rb +1 -1
- data/spec/dummy/app/graphql/types/mutation_type.rb +3 -1
- data/spec/dummy/app/graphql/types/query_type.rb +3 -1
- data/spec/dummy/app/graphql/types/user_type.rb +1 -1
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/dummy/config/routes.rb +5 -9
- data/spec/graphql_devise/model/with_email_updater_spec.rb +17 -35
- data/spec/rails_helper.rb +5 -5
- data/spec/requests/mutations/resend_confirmation_with_token_spec.rb +2 -3
- data/spec/requests/user_controller_spec.rb +1 -33
- data/spec/services/resource_loader_spec.rb +14 -3
- metadata +55 -48
- data/app/controllers/graphql_devise/concerns/additional_controller_methods.rb +0 -72
- data/app/controllers/graphql_devise/concerns/set_user_by_token.rb +0 -21
- data/app/helpers/graphql_devise/mailer_helper.rb +0 -37
- data/app/models/graphql_devise/concerns/additional_model_methods.rb +0 -21
- data/app/models/graphql_devise/concerns/model.rb +0 -25
- data/lib/graphql_devise/default_operations/mutations.rb +0 -32
- data/lib/graphql_devise/default_operations/resolvers.rb +0 -14
- data/lib/graphql_devise/mutations/resend_confirmation.rb +0 -45
- data/lib/graphql_devise/mutations/send_password_reset.rb +0 -38
- data/lib/graphql_devise/mutations/sign_up.rb +0 -61
- data/lib/graphql_devise/mutations/update_password.rb +0 -46
- data/lib/graphql_devise/rails/routes.rb +0 -15
- data/lib/graphql_devise/resolvers/check_password_token.rb +0 -43
- data/lib/graphql_devise/resolvers/confirm_account.rb +0 -42
- data/spec/dummy/app/graphql/mutations/sign_up.rb +0 -14
- data/spec/dummy/app/graphql/resolvers/confirm_admin_account.rb +0 -13
- data/spec/requests/mutations/resend_confirmation_spec.rb +0 -153
- data/spec/requests/mutations/send_password_reset_spec.rb +0 -103
- data/spec/requests/mutations/sign_up_spec.rb +0 -170
- data/spec/requests/mutations/update_password_spec.rb +0 -116
- data/spec/requests/queries/check_password_token_spec.rb +0 -149
- data/spec/requests/queries/confirm_account_spec.rb +0 -137
data/README.md
CHANGED
@@ -23,31 +23,30 @@ GraphQL interface on top of the [Devise Token Auth](https://github.com/lynndylan
|
|
23
23
|
* [Configuring Model](#configuring-model)
|
24
24
|
* [Email Reconfirmation](#email-reconfirmation)
|
25
25
|
* [Current flow](#current-flow)
|
26
|
-
* [Deprecated flow - Do Not Use](#deprecated-flow---do-not-use)
|
27
26
|
* [Customizing Email Templates](#customizing-email-templates)
|
28
27
|
* [I18n](#i18n)
|
29
28
|
* [Authenticating Controller Actions](#authenticating-controller-actions)
|
30
29
|
* [Authenticate Resource in the Controller (>= v0.15.0)](#authenticate-resource-in-the-controller--v0150)
|
31
30
|
* [Authentication Options](#authentication-options)
|
32
|
-
* [Authenticate Before Reaching Your GQL Schema (Deprecated)](#authenticate-before-reaching-your-gql-schema-deprecated)
|
33
|
-
* [Authenticate in an Existing Schema (Deprecated)](#authenticate-in-an-existing-schema-deprecated)
|
34
|
-
* [Authentication Options](#authentication-options-1)
|
35
|
-
* [Important](#important)
|
36
31
|
* [Making Requests](#making-requests)
|
37
32
|
* [Introspection query](#introspection-query)
|
38
33
|
* [Mutations](#mutations)
|
39
|
-
* [Queries](#queries)
|
40
34
|
* [Reset Password Flow](#reset-password-flow)
|
41
35
|
* [More Configuration Options](#more-configuration-options)
|
42
36
|
* [Devise Token Auth Initializer](#devise-token-auth-initializer)
|
43
37
|
* [Devise Initializer](#devise-initializer)
|
38
|
+
* [GraphQL 2.0 Support (>= v1.0.0)](#graphql-20-support--v100)
|
44
39
|
* [GraphQL Interpreter](#graphql-interpreter)
|
45
40
|
* [Using Alongside Standard Devise](#using-alongside-standard-devise)
|
41
|
+
* [Changelog](#changelog)
|
46
42
|
* [Future Work](#future-work)
|
43
|
+
* [Buy Us a Coffee](#buy-us-a-coffee)
|
44
|
+
* [BTC](#btc)
|
45
|
+
* [ADA](#ada)
|
47
46
|
* [Contributing](#contributing)
|
48
47
|
* [License](#license)
|
49
48
|
|
50
|
-
<!-- Added by:
|
49
|
+
<!-- Added by: mcelicalderon, at: Wed Aug 3 22:04:10 -05 2022 -->
|
51
50
|
|
52
51
|
<!--te-->
|
53
52
|
|
@@ -297,17 +296,11 @@ The following is a list of the symbols you can provide to the `operations`, `ski
|
|
297
296
|
```ruby
|
298
297
|
:login
|
299
298
|
:logout
|
300
|
-
:sign_up (deprecated)
|
301
299
|
:register
|
302
|
-
:update_password (deprecated)
|
303
300
|
:update_password_with_token
|
304
|
-
:send_password_reset (deprecated)
|
305
301
|
:send_password_reset_with_token
|
306
|
-
:resend_confirmation (deprecated)
|
307
302
|
:resend_confirmation_with_token
|
308
303
|
:confirm_registration_with_token
|
309
|
-
:confirm_account (deprecated)
|
310
|
-
:check_password_token (deprecated)
|
311
304
|
```
|
312
305
|
|
313
306
|
### Configuring Model
|
@@ -327,7 +320,7 @@ class User < ApplicationRecord
|
|
327
320
|
:confirmable
|
328
321
|
|
329
322
|
# including after calling the `devise` method is important.
|
330
|
-
include GraphqlDevise::
|
323
|
+
include GraphqlDevise::Authenticatable
|
331
324
|
end
|
332
325
|
```
|
333
326
|
|
@@ -369,31 +362,6 @@ user.update_with_email(
|
|
369
362
|
)
|
370
363
|
```
|
371
364
|
|
372
|
-
#### Deprecated flow - Do Not Use
|
373
|
-
`update_with_email` requires two additional attributes when email will change or an error
|
374
|
-
will be raised:
|
375
|
-
|
376
|
-
- `schema_url`: The full url where your GQL schema is mounted. You can get this value from the
|
377
|
-
controller available in the context of your mutations and queries like this:
|
378
|
-
```ruby
|
379
|
-
context[:controller].full_url_without_params
|
380
|
-
```
|
381
|
-
- `confirmation_success_url`: This the full url where you want users to be redirected after
|
382
|
-
the email has changed successfully (usually a front-end url). This value is mandatory
|
383
|
-
unless you have set `default_confirm_success_url` in your devise_token_auth initializer.
|
384
|
-
|
385
|
-
So, it's up to you where you require confirmation of changing emails.
|
386
|
-
[Here's an example](https://github.com/graphql-devise/graphql_devise/blob/c4dcb17e98f8d84cc5ac002c66ed98a797d3bc82/spec/dummy/app/graphql/mutations/update_user.rb#L13)
|
387
|
-
on how you might do this. And also a demonstration on the method usage:
|
388
|
-
```ruby
|
389
|
-
user.update_with_email(
|
390
|
-
name: 'New Name',
|
391
|
-
email: 'new@domain.com',
|
392
|
-
schema_url: 'http://localhost:3000/graphql',
|
393
|
-
confirmation_success_url: 'https://google.com'
|
394
|
-
)
|
395
|
-
```
|
396
|
-
|
397
365
|
### Customizing Email Templates
|
398
366
|
The approach of this gem is a bit different from DeviseTokenAuth. We have placed our templates in `app/views/graphql_devise/mailer`,
|
399
367
|
so if you want to change them, place yours on the same dir structure on your Rails project. You can customize these two templates:
|
@@ -420,7 +388,7 @@ GQL schema execution like this:
|
|
420
388
|
# app/controllers/my_controller.rb
|
421
389
|
|
422
390
|
class MyController < ApplicationController
|
423
|
-
include GraphqlDevise::
|
391
|
+
include GraphqlDevise::SetUserByToken
|
424
392
|
|
425
393
|
def my_action
|
426
394
|
result = DummySchema.execute(params[:query], context: gql_devise_context(User))
|
@@ -433,7 +401,7 @@ end
|
|
433
401
|
# app/controllers/my_controller.rb
|
434
402
|
|
435
403
|
class MyController < ApplicationController
|
436
|
-
include GraphqlDevise::
|
404
|
+
include GraphqlDevise::SetUserByToken
|
437
405
|
|
438
406
|
def my_action
|
439
407
|
result = DummySchema.execute(params[:query], context: gql_devise_context(User, Admin))
|
@@ -479,87 +447,6 @@ module Types
|
|
479
447
|
end
|
480
448
|
```
|
481
449
|
|
482
|
-
#### Authenticate Before Reaching Your GQL Schema (Deprecated)
|
483
|
-
For this you will need to call `authenticate_<model>!` in a `before_action` controller hook.
|
484
|
-
In our example our model is `User`, so it would look like this:
|
485
|
-
```ruby
|
486
|
-
# app/controllers/my_controller.rb
|
487
|
-
|
488
|
-
class MyController < ApplicationController
|
489
|
-
include GraphqlDevise::Concerns::SetUserByToken
|
490
|
-
|
491
|
-
before_action :authenticate_user!
|
492
|
-
|
493
|
-
def my_action
|
494
|
-
result = DummySchema.execute(params[:query], context: { current_resource: current_user })
|
495
|
-
render json: result unless performed?
|
496
|
-
end
|
497
|
-
end
|
498
|
-
```
|
499
|
-
|
500
|
-
The install generator can include the concern in you application controller.
|
501
|
-
If authentication fails for a request, execution will halt and a REST error will be returned since the request never reaches your GQL schema.
|
502
|
-
|
503
|
-
#### Authenticate in an Existing Schema (Deprecated)
|
504
|
-
For this you will need to add the `GraphqlDevise::SchemaPlugin` to your schema as described
|
505
|
-
[here](#mounting-operations-into-your-own-schema).
|
506
|
-
|
507
|
-
```ruby
|
508
|
-
# app/controllers/my_controller.rb
|
509
|
-
|
510
|
-
class MyController < ApplicationController
|
511
|
-
include GraphqlDevise::Concerns::SetUserByToken
|
512
|
-
|
513
|
-
def my_action
|
514
|
-
result = DummySchema.execute(params[:query], context: graphql_context(:user))
|
515
|
-
render json: result unless performed?
|
516
|
-
end
|
517
|
-
end
|
518
|
-
```
|
519
|
-
The `graphql_context` method receives a symbol identifying the resource you are trying
|
520
|
-
to authenticate. So if you mounted the `User` resource, the symbol is `:user`. You can use
|
521
|
-
this snippet to find the symbol for more complex scenarios
|
522
|
-
`resource_klass.to_s.underscore.tr('/', '_').to_sym`. `graphql_context` can also take an
|
523
|
-
array of resources if you mounted more than one into your schema. The gem will try to
|
524
|
-
authenticate a resource for each element on the array until it finds one.
|
525
|
-
|
526
|
-
Internally in your own mutations and queries a key `current_resource` will be available in
|
527
|
-
the context if a resource was successfully authenticated or `nil` otherwise.
|
528
|
-
|
529
|
-
Keep in mind that sending multiple values to the `graphql_context` method means that depending
|
530
|
-
on who makes the request, the context value `current_resource` might contain instances of the
|
531
|
-
different models you might have mounted into the schema.
|
532
|
-
|
533
|
-
Please note that by using this mechanism your GQL schema will be in control of what queries are
|
534
|
-
restricted to authenticated users and you can only do this at the root level fields of your GQL
|
535
|
-
schema. Configure the plugin as explained [here](#mounting-operations-into-your-own-schema)
|
536
|
-
so this can work.
|
537
|
-
|
538
|
-
##### Authentication Options
|
539
|
-
Whether you setup authentications as a default in the plugin, or you do it at the field level,
|
540
|
-
these are the options you can use:
|
541
|
-
1. **Any truthy value:** If `current_resource` is not `.present?`, query will return an authentication error.
|
542
|
-
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.
|
543
|
-
|
544
|
-
In your main app's schema this is how you might specify if a field needs to be authenticated or not:
|
545
|
-
```ruby
|
546
|
-
module Types
|
547
|
-
class QueryType < Types::BaseObject
|
548
|
-
# user field used the default set in the Plugin's initializer
|
549
|
-
field :user, resolver: Resolvers::UserShow
|
550
|
-
# this field will never require authentication
|
551
|
-
field :public_field, String, null: false, authenticate: false
|
552
|
-
# this field requires authentication
|
553
|
-
field :private_field, String, null: false, authenticate: true
|
554
|
-
# this field requires authenticated users to also be admins
|
555
|
-
field :admin_field, String, null: false, authenticate: ->(user) { user.admin? }
|
556
|
-
end
|
557
|
-
end
|
558
|
-
```
|
559
|
-
|
560
|
-
#### Important
|
561
|
-
Remember to check `performed?` before rendering the result of the graphql operation. This is required because some operations perform a redirect and without this check you will get a `AbstractController::DoubleRenderError`.
|
562
|
-
|
563
450
|
### Making Requests
|
564
451
|
Here is a list of the available mutations and queries assuming your mounted model is `User`.
|
565
452
|
|
@@ -572,30 +459,10 @@ Operation | Description | Example
|
|
572
459
|
:--- | :--- | :------------------:
|
573
460
|
login | This mutation has a second field by default. `credentials` can be fetched directly on the mutation return type.<br>Credentials are still returned in the headers of the response. | userLogin(email: String!, password: String!): UserLoginPayload |
|
574
461
|
logout | requires authentication headers. Deletes current session if successful. | userLogout: UserLogoutPayload |
|
575
|
-
signUp **(Deprecated)** | The parameter `confirmSuccessUrl` is optional unless you are using the `confirmable` plugin from Devise in your `resource`'s model. If you have `confirmable` set up, you will have to provide it unless you have `config.default_confirm_success_url` set in `config/initializers/devise_token_auth.rb`. | userSignUp(email: String!, password: String!, passwordConfirmation: String!, confirmSuccessUrl: String): UserSignUpPayload |
|
576
462
|
register | The parameter `confirmUrl` is optional unless you are using the `confirmable` plugin from Devise in your `resource`'s model. If you have `confirmable` set up, you will have to provide it unless you have `config.default_confirm_success_url` set in `config/initializers/devise_token_auth.rb`. | userRegister(email: String!, password: String!, passwordConfirmation: String!, confirmUrl: String): UserRegisterPayload |
|
577
463
|
sendPasswordResetWithToken | Sends an email to the provided address with a link to reset the password of the resource. First step of the most recently implemented password reset flow. | userSendPasswordResetWithToken(email: String!, redirectUrl: String!): UserSendPasswordResetWithTokenPayload |
|
578
464
|
updatePasswordWithToken | Uses a `resetPasswordToken` to update the password of a resource. Second and last step of the most recently implemented password reset flow. | userSendPasswordResetWithToken(resetPasswordToken: String!, password: String!, passwordConfirmation: String!): UserUpdatePasswordWithTokenPayload |
|
579
|
-
resendConfirmation **(Deprecated)** | The `UserResendConfirmationPayload` will return a `message: String!` that can be used to notify a user what to do after the instructions were sent to them | userResendConfirmation(email: String!, redirectUrl: String!): UserResendConfirmationPayload |
|
580
465
|
resendConfirmationWithToken | The `UserResendConfirmationWithTokenPayload` will return a `message: String!` that can be used to notify a user what to do after the instructions were sent to them. Email will contain a link to the provided `confirmUrl` and a `confirmationToken` query param. | userResendConfirmationWithToken(email: String!, confirmUrl: String!): UserResendConfirmationWithTokenPayload |
|
581
|
-
sendResetPassword **(Deprecated)** | Sends an email to the provided address with a link to reset the password of the resource. **This mutation is part of the first and soon to be deprecated password reset flow.** | userSendResetPassword(email: String!, redirectUrl: String!): UserSendResetPasswordPayload |
|
582
|
-
updatePassword **(Deprecated)** | The parameter `currentPassword` is optional if you have `config.check_current_password_before_update` set to false (disabled by default) on your generated `config/initializers/devise_token_aut.rb` or if the `resource` model supports the `recoverable` Devise plugin and the `resource`'s `allow_password_change` attribute is set to true (this is done in the `userCheckPasswordToken` query when you click on the sent email's link). **This mutation is part of the first and soon to be deprecated password reset flow.** | userUpdatePassword(password: String!, passwordConfirmation: String!, currentPassword: String): UserUpdatePasswordPayload |
|
583
|
-
|
584
|
-
#### Queries
|
585
|
-
Operation | Description | Example
|
586
|
-
:--- | :--- | :------------------:
|
587
|
-
confirmAccount **(Deprecated)** | Performs a redirect using the `redirectUrl` param | userConfirmAccount(confirmationToken: String!, redirectUrl: String!): User
|
588
|
-
checkPasswordToken **(Deprecated)** | Performs a redirect using the `redirectUrl` param | userCheckPasswordToken(resetPasswordToken: String!, redirectUrl: String): User
|
589
|
-
|
590
|
-
The reason for having 2 queries is that these 2 are going to be accessed when clicking on
|
591
|
-
the confirmation and reset password email urls. There is no limitation for making mutation
|
592
|
-
requests using the `GET` method on the Rails side, but looks like there might be a limitation
|
593
|
-
on the [Apollo Client](https://www.apollographql.com/docs/apollo-server/v1/requests/#get-requests).
|
594
|
-
|
595
|
-
We will continue to build better docs for the gem after this first release, but in the mean time
|
596
|
-
you can use [our specs](spec/requests) to better understand how to use the gem.
|
597
|
-
Also, the [dummy app](spec/dummy) used in our specs will give you
|
598
|
-
a clear idea on how to configure the gem on your Rails application.
|
599
466
|
|
600
467
|
### Reset Password Flow
|
601
468
|
This gem supports two password recovery flows. The most recently implemented is preferred and
|
@@ -638,6 +505,48 @@ In this section the most important configurations will be highlighted.
|
|
638
505
|
|
639
506
|
**Note:** Remember this gem adds a layer on top of Devise, so some configurations might not apply.
|
640
507
|
|
508
|
+
### GraphQL 2.0 Support (>= v1.0.0)
|
509
|
+
This gem now supports [GraphQL Ruby](https://github.com/rmosolgo/graphql-ruby) v2.
|
510
|
+
There's one manual step you need to take in order for this to work.
|
511
|
+
|
512
|
+
You need a custom `field_class` in your `MutationType` and `QueryType`. If you don't have one setup already, you can simply add the one
|
513
|
+
this gem provides, like this:
|
514
|
+
|
515
|
+
```ruby
|
516
|
+
module Types
|
517
|
+
class MutationType < BaseObject
|
518
|
+
field_class GraphqlDevise::Types::BaseField
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
module Types
|
523
|
+
class QueryType < Types::BaseObject
|
524
|
+
field_class GraphqlDevise::Types::BaseField
|
525
|
+
end
|
526
|
+
end
|
527
|
+
```
|
528
|
+
|
529
|
+
If you already have a `field_class` defined in any of your types, the only thing you need to do is add another `kwarg`
|
530
|
+
to that class initializer (`authenticate`) and make that value available through an attribute reader.
|
531
|
+
|
532
|
+
The next example is this gem's implementation of a custom class, but you can implement your own however you see fit
|
533
|
+
as long as you expose an `authenticate` public method with the value that was passed to the initializer.
|
534
|
+
|
535
|
+
```ruby
|
536
|
+
module GraphqlDevise
|
537
|
+
module Types
|
538
|
+
class BaseField < GraphQL::Schema::Field
|
539
|
+
def initialize(*args, authenticate: nil, **kwargs, &block)
|
540
|
+
@authenticate = authenticate
|
541
|
+
super(*args, **kwargs, &block)
|
542
|
+
end
|
543
|
+
|
544
|
+
attr_reader :authenticate
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
```
|
549
|
+
|
641
550
|
### GraphQL Interpreter
|
642
551
|
GraphQL-Ruby `>= 1.9.0` includes a new runtime module which you may use for your schema.
|
643
552
|
Eventually, it will become the default. You can read more about it
|
@@ -653,6 +562,9 @@ information you can check [this answer here](https://github.com/lynndylanhurley/
|
|
653
562
|
This gem supports the same and should be easier to handle email templates due to the fact we don't override
|
654
563
|
standard Devise templates.
|
655
564
|
|
565
|
+
## Changelog
|
566
|
+
Full list of changes in [CHANGELOG.md](CHANGELOG.md)
|
567
|
+
|
656
568
|
## Future Work
|
657
569
|
We will continue to improve the gem and add better docs.
|
658
570
|
|
@@ -661,6 +573,23 @@ We will continue to improve the gem and add better docs.
|
|
661
573
|
1. Add support for unlockable and other Devise modules.
|
662
574
|
1. Add feature specs for confirm account and reset password flows.
|
663
575
|
|
576
|
+
We will continue to build better docs for the gem after this first release, but in the mean time
|
577
|
+
you can use [our specs](spec/requests) to better understand how to use the gem.
|
578
|
+
Also, the [dummy app](spec/dummy) used in our specs will give you
|
579
|
+
a clear idea on how to configure the gem on your Rails application.
|
580
|
+
|
581
|
+
## Buy Us a Coffee
|
582
|
+
If you'd like to support our work, you are welcome to do so!
|
583
|
+
|
584
|
+
##### BTC
|
585
|
+
```
|
586
|
+
bc1qntlmyl24wuf6y5jyn2vg8kduss57dwtyrcflyq
|
587
|
+
```
|
588
|
+
##### ADA
|
589
|
+
```
|
590
|
+
addr1q8e8cjzutzptcrfgjgsjl3k4t4xy5ucrmkf2dmq9qn966q8saucty53avujfc9yu9vfk7266auhdx9fz4fsryzeagqds893nfw
|
591
|
+
```
|
592
|
+
|
664
593
|
## Contributing
|
665
594
|
|
666
595
|
Bug reports and pull requests are welcome on GitHub at https://github.com/graphql-devise/graphql_devise.
|
@@ -4,17 +4,17 @@ require_dependency 'graphql_devise/application_controller'
|
|
4
4
|
|
5
5
|
module GraphqlDevise
|
6
6
|
class GraphqlController < ApplicationController
|
7
|
-
include
|
7
|
+
include SetUserByToken
|
8
8
|
|
9
9
|
def auth
|
10
10
|
result = if params[:_json]
|
11
|
-
|
11
|
+
Schema.multiplex(
|
12
12
|
params[:_json].map do |param|
|
13
13
|
{ query: param[:query] }.merge(execute_params(param))
|
14
14
|
end
|
15
15
|
)
|
16
16
|
else
|
17
|
-
|
17
|
+
Schema.execute(params[:query], **execute_params(params))
|
18
18
|
end
|
19
19
|
|
20
20
|
render json: result unless performed?
|
@@ -3,9 +3,5 @@
|
|
3
3
|
<p><%= t('.confirm_link_msg') %></p>
|
4
4
|
|
5
5
|
<p>
|
6
|
-
|
7
|
-
<%= link_to t('.confirm_account_link'), "#{message['schema_url']}?#{confirmation_query(resource_name: @resource.class.to_s, redirect_url: message['redirect-url'], token: @token).to_query}" %>
|
8
|
-
<% else %>
|
9
|
-
<%= link_to t('.confirm_account_link'), "#{CGI.escape(message['redirect-url'].to_s)}?#{{ confirmationToken: @token }.to_query}" %>
|
10
|
-
<% end %>
|
6
|
+
<%= link_to t('.confirm_account_link'), "#{message['redirect-url'].to_s}?#{{ confirmationToken: @token }.to_query}" %>
|
11
7
|
</p>
|
data/config/routes.rb
CHANGED
data/graphql_devise.gemspec
CHANGED
@@ -25,11 +25,12 @@ Gem::Specification.new do |spec|
|
|
25
25
|
`git ls-files -z`.split("\x0").select { |f| f.match(%r{^spec/}) }
|
26
26
|
end
|
27
27
|
|
28
|
-
spec.required_ruby_version = '>= 2.
|
28
|
+
spec.required_ruby_version = '>= 2.4.4'
|
29
29
|
|
30
30
|
spec.add_dependency 'devise_token_auth', '>= 0.1.43', '< 2.0'
|
31
|
-
spec.add_dependency 'graphql', '>= 1.8', '< 1
|
31
|
+
spec.add_dependency 'graphql', '>= 1.8', '< 2.1'
|
32
32
|
spec.add_dependency 'rails', '>= 4.2', '< 6.2'
|
33
|
+
spec.add_dependency 'zeitwerk'
|
33
34
|
|
34
35
|
spec.add_development_dependency 'appraisal'
|
35
36
|
spec.add_development_dependency 'coveralls-ruby', '~> 0.2'
|
@@ -41,8 +42,9 @@ Gem::Specification.new do |spec|
|
|
41
42
|
spec.add_development_dependency 'pry-byebug'
|
42
43
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
43
44
|
spec.add_development_dependency 'rspec-rails', '~> 4.0'
|
44
|
-
spec.add_development_dependency 'rubocop', '0.
|
45
|
-
spec.add_development_dependency 'rubocop-performance'
|
46
|
-
spec.add_development_dependency 'rubocop-
|
45
|
+
spec.add_development_dependency 'rubocop', '< 0.82.0'
|
46
|
+
spec.add_development_dependency 'rubocop-performance', '< 1.6.0'
|
47
|
+
spec.add_development_dependency 'rubocop-rails', '< 2.6.0'
|
48
|
+
spec.add_development_dependency 'rubocop-rspec', '< 1.39.0'
|
47
49
|
spec.add_development_dependency 'sqlite3', '~> 1.3'
|
48
50
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlDevise
|
4
|
+
module AdditionalControllerMethods
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attr_accessor :client_id, :token, :resource
|
9
|
+
end
|
10
|
+
|
11
|
+
def gql_devise_context(*models)
|
12
|
+
{
|
13
|
+
current_resource: authenticate_model(*models),
|
14
|
+
controller: self
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate_model(*models)
|
19
|
+
models.each do |model|
|
20
|
+
set_resource_by_token(model)
|
21
|
+
return @resource if @resource.present?
|
22
|
+
end
|
23
|
+
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_class(resource = nil)
|
28
|
+
# Return the resource class instead of looking for a Devise mapping if resource is already a resource class
|
29
|
+
return resource if resource.respond_to?(:find_by)
|
30
|
+
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_resource_by_token(resource)
|
35
|
+
set_user_by_token(resource)
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_redirect_headers(access_token, client, redirect_header_options = {})
|
39
|
+
{
|
40
|
+
DeviseTokenAuth.headers_names[:"access-token"] => access_token,
|
41
|
+
DeviseTokenAuth.headers_names[:client] => client,
|
42
|
+
:config => params[:config],
|
43
|
+
:client_id => client,
|
44
|
+
:token => access_token
|
45
|
+
}.merge(redirect_header_options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlDevise
|
4
|
+
module AdditionalModelMethods
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
def reconfirmable
|
9
|
+
devise_modules.include?(:confirmable) && column_names.include?('unconfirmed_email')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_with_email(attributes = {})
|
14
|
+
GraphqlDevise::Model::WithEmailUpdater.new(self, attributes).call
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,122 +1,99 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GraphqlDevise
|
4
|
-
module
|
5
|
-
|
6
|
-
extend ActiveSupport::Concern
|
4
|
+
module ControllerMethods
|
5
|
+
extend ActiveSupport::Concern
|
7
6
|
|
8
|
-
|
7
|
+
private
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def raise_user_error(message)
|
17
|
-
raise GraphqlDevise::UserError, message
|
18
|
-
end
|
19
|
-
|
20
|
-
def raise_user_error_list(message, errors:)
|
21
|
-
raise GraphqlDevise::DetailedUserError.new(message, errors: errors)
|
22
|
-
end
|
23
|
-
|
24
|
-
def remove_resource
|
25
|
-
controller.resource = nil
|
26
|
-
controller.client_id = nil
|
27
|
-
controller.token = nil
|
9
|
+
def check_redirect_url_whitelist!(redirect_url)
|
10
|
+
if blacklisted_redirect_url?(redirect_url)
|
11
|
+
raise_user_error(I18n.t('graphql_devise.redirect_url_not_allowed', redirect_url: redirect_url))
|
28
12
|
end
|
13
|
+
end
|
29
14
|
|
30
|
-
|
31
|
-
|
32
|
-
|
15
|
+
def raise_user_error(message)
|
16
|
+
raise UserError, message
|
17
|
+
end
|
33
18
|
|
34
|
-
|
35
|
-
|
36
|
-
|
19
|
+
def raise_user_error_list(message, errors:)
|
20
|
+
raise DetailedUserError.new(message, errors: errors)
|
21
|
+
end
|
37
22
|
|
38
|
-
|
39
|
-
|
40
|
-
|
23
|
+
def remove_resource
|
24
|
+
controller.resource = nil
|
25
|
+
controller.client_id = nil
|
26
|
+
controller.token = nil
|
27
|
+
end
|
41
28
|
|
42
|
-
|
43
|
-
|
44
|
-
|
29
|
+
def response
|
30
|
+
controller.response
|
31
|
+
end
|
45
32
|
|
46
|
-
|
47
|
-
|
48
|
-
|
33
|
+
def controller
|
34
|
+
context[:controller]
|
35
|
+
end
|
49
36
|
|
50
|
-
|
51
|
-
|
52
|
-
|
37
|
+
def resource_name
|
38
|
+
::GraphqlDevise.to_mapping_name(resource_class)
|
39
|
+
end
|
53
40
|
|
54
|
-
|
55
|
-
|
56
|
-
|
41
|
+
def resource_class
|
42
|
+
self.class.instance_variable_get(:@resource_klass)
|
43
|
+
end
|
57
44
|
|
58
|
-
|
59
|
-
|
60
|
-
|
45
|
+
def recoverable_enabled?
|
46
|
+
resource_class.devise_modules.include?(:recoverable)
|
47
|
+
end
|
61
48
|
|
62
|
-
|
63
|
-
|
64
|
-
|
49
|
+
def confirmable_enabled?
|
50
|
+
resource_class.devise_modules.include?(:confirmable)
|
51
|
+
end
|
65
52
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
else
|
70
|
-
controller.token.client if controller.token.present?
|
71
|
-
end
|
72
|
-
end
|
53
|
+
def blacklisted_redirect_url?(redirect_url)
|
54
|
+
DeviseTokenAuth.redirect_whitelist && !DeviseTokenAuth::Url.whitelisted?(redirect_url)
|
55
|
+
end
|
73
56
|
|
74
|
-
|
75
|
-
|
76
|
-
|
57
|
+
def current_resource
|
58
|
+
@current_resource ||= controller.send(:set_resource_by_token, resource_class)
|
59
|
+
end
|
77
60
|
|
78
|
-
|
61
|
+
def client
|
62
|
+
if Gem::Version.new(DeviseTokenAuth::VERSION) <= Gem::Version.new('1.1.0')
|
63
|
+
controller.client_id
|
64
|
+
else
|
65
|
+
controller.token.client if controller.token.present?
|
79
66
|
end
|
67
|
+
end
|
80
68
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
else
|
85
|
-
{ client_id: token.client, token: token.token }
|
86
|
-
end
|
87
|
-
end
|
69
|
+
def set_auth_headers(resource)
|
70
|
+
auth_headers = resource.create_new_auth_token
|
71
|
+
response.headers.merge!(auth_headers)
|
88
72
|
|
89
|
-
|
90
|
-
|
91
|
-
:build_redirect_headers,
|
92
|
-
token_info.fetch(:token),
|
93
|
-
token_info.fetch(:client_id),
|
94
|
-
redirect_header_options
|
95
|
-
)
|
96
|
-
end
|
73
|
+
auth_headers
|
74
|
+
end
|
97
75
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
76
|
+
def find_resource(field, value)
|
77
|
+
if resource_class.connection.adapter_name.downcase.include?('mysql')
|
78
|
+
# fix for mysql default case insensitivity
|
79
|
+
resource_class.where("BINARY #{field} = ? AND provider= ?", value, provider).first
|
80
|
+
elsif Gem::Version.new(DeviseTokenAuth::VERSION) < Gem::Version.new('1.1.0')
|
81
|
+
resource_class.find_by(field => value, :provider => provider)
|
82
|
+
else
|
83
|
+
resource_class.dta_find_by(field => value, :provider => provider)
|
107
84
|
end
|
85
|
+
end
|
108
86
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
87
|
+
def get_case_insensitive_field(field, value)
|
88
|
+
if resource_class.case_insensitive_keys.include?(field)
|
89
|
+
value.downcase
|
90
|
+
else
|
91
|
+
value
|
115
92
|
end
|
93
|
+
end
|
116
94
|
|
117
|
-
|
118
|
-
|
119
|
-
end
|
95
|
+
def provider
|
96
|
+
:email
|
120
97
|
end
|
121
98
|
end
|
122
99
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlDevise
|
4
|
+
module FieldAuthentication
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def initialize(*args, authenticate: nil, **kwargs, &block)
|
8
|
+
@authenticate = authenticate
|
9
|
+
super(*args, **kwargs, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :authenticate
|
13
|
+
end
|
14
|
+
end
|