graphql_devise 0.18.2 → 1.0.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 +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
|