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
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlDevise
|
4
|
+
module DefaultOperations
|
5
|
+
QUERIES = {}.freeze
|
6
|
+
MUTATIONS = {
|
7
|
+
login: { klass: Mutations::Login, authenticatable: true },
|
8
|
+
logout: { klass: Mutations::Logout, authenticatable: true },
|
9
|
+
register: { klass: Mutations::Register, authenticatable: true },
|
10
|
+
update_password_with_token: { klass: Mutations::UpdatePasswordWithToken, authenticatable: true },
|
11
|
+
send_password_reset_with_token: { klass: Mutations::SendPasswordResetWithToken, authenticatable: false },
|
12
|
+
resend_confirmation_with_token: { klass: Mutations::ResendConfirmationWithToken, authenticatable: false },
|
13
|
+
confirm_registration_with_token: { klass: Mutations::ConfirmRegistrationWithToken, authenticatable: true }
|
14
|
+
}.freeze
|
15
|
+
end
|
16
|
+
end
|
@@ -9,15 +9,13 @@ module GraphqlDevise
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call
|
12
|
-
|
13
|
-
|
14
|
-
resource_attributes = @attributes.except(:schema_url, :confirmation_success_url, :confirmation_url)
|
12
|
+
resource_attributes = @attributes.except(:confirmation_url)
|
15
13
|
return @resource.update(resource_attributes) unless requires_reconfirmation?(resource_attributes)
|
16
14
|
|
17
15
|
@resource.assign_attributes(resource_attributes)
|
18
16
|
|
19
17
|
if @resource.email == email_in_database
|
20
|
-
|
18
|
+
@resource.save
|
21
19
|
elsif required_reconfirm_attributes?
|
22
20
|
return false unless @resource.valid?
|
23
21
|
|
@@ -28,7 +26,7 @@ module GraphqlDevise
|
|
28
26
|
saved
|
29
27
|
else
|
30
28
|
raise(
|
31
|
-
GraphqlDevise::Error,
|
29
|
+
::GraphqlDevise::Error,
|
32
30
|
'Method `update_with_email` requires attribute `confirmation_url` for email reconfirmation to work'
|
33
31
|
)
|
34
32
|
end
|
@@ -36,24 +34,8 @@ module GraphqlDevise
|
|
36
34
|
|
37
35
|
private
|
38
36
|
|
39
|
-
def check_deprecated_attributes
|
40
|
-
if [@attributes[:schema_url], @attributes[:confirmation_success_url]].any?(&:present?)
|
41
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
|
42
|
-
Providing `schema_url` and `confirmation_success_url` to `update_with_email` is deprecated and will be
|
43
|
-
removed in a future version of this gem.
|
44
|
-
|
45
|
-
Now you must only provide `confirmation_url` and the email will contain the new format of the confirmation
|
46
|
-
url that needs to be used with the new `confirmRegistrationWithToken` on the client application.
|
47
|
-
DEPRECATION
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
37
|
def required_reconfirm_attributes?
|
52
|
-
|
53
|
-
[@attributes[:confirmation_success_url], DeviseTokenAuth.default_confirm_success_url].any?(&:present?)
|
54
|
-
else
|
55
|
-
[@attributes[:confirmation_url], DeviseTokenAuth.default_confirm_success_url].any?(&:present?)
|
56
|
-
end
|
38
|
+
[@attributes[:confirmation_url], DeviseTokenAuth.default_confirm_success_url].any?(&:present?)
|
57
39
|
end
|
58
40
|
|
59
41
|
def requires_reconfirmation?(resource_attributes)
|
@@ -78,14 +60,7 @@ module GraphqlDevise
|
|
78
60
|
end
|
79
61
|
|
80
62
|
def confirmation_method_params
|
81
|
-
|
82
|
-
{
|
83
|
-
redirect_url: @attributes[:confirmation_success_url] || DeviseTokenAuth.default_confirm_success_url,
|
84
|
-
schema_url: @attributes[:schema_url]
|
85
|
-
}
|
86
|
-
else
|
87
|
-
{ redirect_url: @attributes[:confirmation_url] || DeviseTokenAuth.default_confirm_success_url }
|
88
|
-
end
|
63
|
+
{ redirect_url: @attributes[:confirmation_url] || DeviseTokenAuth.default_confirm_success_url }
|
89
64
|
end
|
90
65
|
|
91
66
|
def send_confirmation_instructions(saved)
|
@@ -1,12 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'operation_preparers/gql_name_setter'
|
4
|
-
require_relative 'operation_preparers/mutation_field_setter'
|
5
|
-
require_relative 'operation_preparers/resolver_type_setter'
|
6
|
-
require_relative 'operation_preparers/resource_klass_setter'
|
7
|
-
require_relative 'operation_preparers/default_operation_preparer'
|
8
|
-
require_relative 'operation_preparers/custom_operation_preparer'
|
9
|
-
|
10
3
|
module GraphqlDevise
|
11
4
|
module MountMethod
|
12
5
|
class OperationPreparer
|
@@ -11,7 +11,7 @@ module GraphqlDevise
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def call
|
14
|
-
mapping_name = GraphqlDevise.to_mapping_name(@model)
|
14
|
+
mapping_name = ::GraphqlDevise.to_mapping_name(@model)
|
15
15
|
|
16
16
|
@custom_operations.slice(*@selected_keys).each_with_object({}) do |(action, operation), result|
|
17
17
|
mapped_action = "#{mapping_name}_#{action}"
|
@@ -12,7 +12,7 @@ module GraphqlDevise
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def call
|
15
|
-
mapping_name = GraphqlDevise.to_mapping_name(@model)
|
15
|
+
mapping_name = ::GraphqlDevise.to_mapping_name(@model)
|
16
16
|
|
17
17
|
@selected_operations.except(*@custom_keys).each_with_object({}) do |(action, operation_info), result|
|
18
18
|
mapped_action = "#{mapping_name}_#{action}"
|
@@ -25,18 +25,6 @@ module GraphqlDevise
|
|
25
25
|
else
|
26
26
|
@default
|
27
27
|
end
|
28
|
-
|
29
|
-
operations.each do |operation, values|
|
30
|
-
next if values[:deprecation_reason].blank?
|
31
|
-
|
32
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
|
33
|
-
`#{operation}` is deprecated and will be removed in a future version of this gem.
|
34
|
-
#{values[:deprecation_reason]}
|
35
|
-
|
36
|
-
You can supress this message by skipping `#{operation}` on your ResourceLoader or the
|
37
|
-
mount_graphql_devise_for method on your routes file.
|
38
|
-
DEPRECATION
|
39
|
-
end
|
40
28
|
end
|
41
29
|
end
|
42
30
|
end
|
@@ -13,11 +13,11 @@ module GraphqlDevise
|
|
13
13
|
return @default_value if value.blank?
|
14
14
|
|
15
15
|
unless value.instance_of?(Array)
|
16
|
-
raise
|
16
|
+
raise InvalidMountOptionsError, "`#{key}` option has an invalid value. Array expected."
|
17
17
|
end
|
18
18
|
|
19
19
|
unless value.all? { |element| element.instance_of?(@element_type) }
|
20
|
-
raise
|
20
|
+
raise InvalidMountOptionsError, "`#{key}` option has invalid elements. #{@element_type} expected."
|
21
21
|
end
|
22
22
|
|
23
23
|
value
|
@@ -12,11 +12,11 @@ module GraphqlDevise
|
|
12
12
|
return if value.nil?
|
13
13
|
|
14
14
|
unless value.instance_of?(Class)
|
15
|
-
raise
|
15
|
+
raise InvalidMountOptionsError, "`#{key}` option has an invalid value. Class expected."
|
16
16
|
end
|
17
17
|
|
18
18
|
unless @klass_array.any? { |klass| value.ancestors.include?(klass) }
|
19
|
-
raise
|
19
|
+
raise InvalidMountOptionsError,
|
20
20
|
"`#{key}` option has an invalid value. #{@klass_array.join(', ')} or descendants expected. Got #{value}."
|
21
21
|
end
|
22
22
|
|
@@ -13,7 +13,7 @@ module GraphqlDevise
|
|
13
13
|
return @default_value if value.blank?
|
14
14
|
|
15
15
|
unless value.instance_of?(Hash)
|
16
|
-
raise
|
16
|
+
raise InvalidMountOptionsError, "`#{key}` option has an invalid value. Hash expected. Got #{value.class}."
|
17
17
|
end
|
18
18
|
|
19
19
|
value.each { |internal_key, klass| ClassChecker.new(@element_type_array).call!(klass, "#{key} -> #{internal_key}") }
|
@@ -12,7 +12,7 @@ module GraphqlDevise
|
|
12
12
|
return @default_string if value.blank?
|
13
13
|
|
14
14
|
unless value.instance_of?(String)
|
15
|
-
raise
|
15
|
+
raise InvalidMountOptionsError, "`#{key}` option has an invalid value. String expected."
|
16
16
|
end
|
17
17
|
|
18
18
|
value
|
@@ -11,7 +11,7 @@ module GraphqlDevise
|
|
11
11
|
def validate!
|
12
12
|
if [@options.skip, @options.only].all?(&:present?)
|
13
13
|
raise(
|
14
|
-
|
14
|
+
InvalidMountOptionsError,
|
15
15
|
"Can't specify both `skip` and `only` options when mounting the route."
|
16
16
|
)
|
17
17
|
end
|
@@ -15,7 +15,7 @@ module GraphqlDevise
|
|
15
15
|
|
16
16
|
if unsupported_operations.present?
|
17
17
|
raise(
|
18
|
-
|
18
|
+
InvalidMountOptionsError,
|
19
19
|
"#{@key} option contains unsupported operations: \"#{unsupported_operations.join(', ')}\". Check for typos."
|
20
20
|
)
|
21
21
|
end
|
@@ -1,10 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'option_sanitizers/array_checker'
|
4
|
-
require_relative 'option_sanitizers/hash_checker'
|
5
|
-
require_relative 'option_sanitizers/string_checker'
|
6
|
-
require_relative 'option_sanitizers/class_checker'
|
7
|
-
|
8
3
|
module GraphqlDevise
|
9
4
|
module MountMethod
|
10
5
|
SUPPORTED_OPTIONS = {
|
@@ -6,7 +6,7 @@ module GraphqlDevise
|
|
6
6
|
argument :confirmation_token, String, required: true
|
7
7
|
|
8
8
|
field :credentials,
|
9
|
-
|
9
|
+
Types::CredentialType,
|
10
10
|
null: true,
|
11
11
|
description: 'Authentication credentials. Null unless user is signed in after confirmation.'
|
12
12
|
|
@@ -6,7 +6,7 @@ module GraphqlDevise
|
|
6
6
|
argument :email, String, required: true
|
7
7
|
argument :password, String, required: true
|
8
8
|
|
9
|
-
field :credentials,
|
9
|
+
field :credentials, Types::CredentialType, null: false
|
10
10
|
|
11
11
|
def resolve(email:, password:)
|
12
12
|
resource = find_resource(
|
@@ -9,7 +9,7 @@ module GraphqlDevise
|
|
9
9
|
argument :confirm_url, String, required: false
|
10
10
|
|
11
11
|
field :credentials,
|
12
|
-
|
12
|
+
Types::CredentialType,
|
13
13
|
null: true,
|
14
14
|
description: 'Authentication credentials. Null if after signUp resource is not active for authentication (e.g. Email confirmation required).'
|
15
15
|
|
@@ -8,7 +8,7 @@ module GraphqlDevise
|
|
8
8
|
argument :reset_password_token, String, required: true
|
9
9
|
|
10
10
|
field :credentials,
|
11
|
-
|
11
|
+
Types::CredentialType,
|
12
12
|
null: true,
|
13
13
|
description: 'Authentication credentials. Resource must be signed_in for credentials to be returned.'
|
14
14
|
|
@@ -6,95 +6,127 @@ module GraphqlDevise
|
|
6
6
|
@resource = resource
|
7
7
|
@options = options
|
8
8
|
@routing = routing
|
9
|
-
@default_operations =
|
9
|
+
@default_operations = DefaultOperations::MUTATIONS.merge(DefaultOperations::QUERIES)
|
10
10
|
end
|
11
11
|
|
12
12
|
def call(query, mutation)
|
13
13
|
# clean_options responds to all keys defined in GraphqlDevise::MountMethod::SUPPORTED_OPTIONS
|
14
|
-
clean_options =
|
14
|
+
clean_options = MountMethod::OptionSanitizer.new(@options).call!
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
EXAMPLE
|
22
|
-
|
23
|
-
GraphqlDevise::ResourceLoader.new(User) # instead of GraphqlDevise::ResourceLoader.new('User')
|
24
|
-
|
25
|
-
mount_graphql_devise_for User # instead of mount_graphql_devise_for 'User'
|
26
|
-
DEPRECATION
|
27
|
-
@resource.constantize
|
28
|
-
else
|
29
|
-
@resource
|
16
|
+
unless @resource.is_a?(Class)
|
17
|
+
raise(
|
18
|
+
InvalidMountOptionsError,
|
19
|
+
'A class must be provided when mounting a model. String values are no longer supported.'
|
20
|
+
)
|
30
21
|
end
|
31
22
|
|
32
23
|
# Necesary when mounting a resource via route file as Devise forces the reloading of routes
|
33
|
-
return clean_options if GraphqlDevise.resource_mounted?(
|
24
|
+
return clean_options if ::GraphqlDevise.resource_mounted?(@resource) && @routing
|
34
25
|
|
35
26
|
validate_options!(clean_options)
|
36
27
|
|
37
28
|
authenticatable_type = clean_options.authenticatable_type.presence ||
|
38
29
|
"Types::#{@resource}Type".safe_constantize ||
|
39
|
-
|
30
|
+
Types::AuthenticatableType
|
40
31
|
|
41
|
-
prepared_mutations = prepare_mutations(
|
32
|
+
prepared_mutations = prepare_mutations(@resource, clean_options, authenticatable_type)
|
42
33
|
|
43
34
|
if prepared_mutations.any? && mutation.blank?
|
44
|
-
raise GraphqlDevise::Error, 'You need to provide a mutation type unless all mutations are skipped'
|
35
|
+
raise ::GraphqlDevise::Error, 'You need to provide a mutation type unless all mutations are skipped'
|
45
36
|
end
|
46
37
|
|
47
|
-
|
48
|
-
|
38
|
+
begin
|
39
|
+
prepared_mutations.each do |action, prepared_mutation|
|
40
|
+
mutation.field(action, mutation: prepared_mutation, authenticate: false)
|
41
|
+
end
|
42
|
+
rescue ArgumentError
|
43
|
+
raise unless Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('2.0')
|
44
|
+
|
45
|
+
raise_undefined_field_class_error('MutationType')
|
49
46
|
end
|
50
47
|
|
51
|
-
prepared_resolvers = prepare_resolvers(
|
48
|
+
prepared_resolvers = prepare_resolvers(@resource, clean_options, authenticatable_type)
|
52
49
|
|
53
50
|
if prepared_resolvers.any? && query.blank?
|
54
|
-
raise GraphqlDevise::Error, 'You need to provide a query type unless all queries are skipped'
|
51
|
+
raise ::GraphqlDevise::Error, 'You need to provide a query type unless all queries are skipped'
|
55
52
|
end
|
56
53
|
|
57
|
-
|
58
|
-
|
54
|
+
begin
|
55
|
+
prepared_resolvers.each do |action, resolver|
|
56
|
+
query.field(action, resolver: resolver, authenticate: false)
|
57
|
+
end
|
58
|
+
rescue ArgumentError
|
59
|
+
raise unless Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('2.0')
|
60
|
+
|
61
|
+
raise_undefined_field_class_error('QueryType')
|
59
62
|
end
|
60
63
|
|
61
|
-
GraphqlDevise.add_mapping(GraphqlDevise.to_mapping_name(@resource).to_sym, @resource)
|
62
|
-
GraphqlDevise.mount_resource(
|
64
|
+
::GraphqlDevise.add_mapping(::GraphqlDevise.to_mapping_name(@resource).to_sym, @resource)
|
65
|
+
::GraphqlDevise.mount_resource(@resource) if @routing
|
63
66
|
|
64
67
|
clean_options
|
65
68
|
end
|
66
69
|
|
67
70
|
private
|
68
71
|
|
72
|
+
def raise_undefined_field_class_error(type_class)
|
73
|
+
raise(
|
74
|
+
GraphqlDevise::Error,
|
75
|
+
<<~MESSAGE
|
76
|
+
To use this gem with graphql >= 2.0 you need to use a custom `field_class`
|
77
|
+
on your #{type_class}. You can use the `field_class` defined in this gem like this:
|
78
|
+
|
79
|
+
module Types
|
80
|
+
class #{type_class} < GraphQL::Schema::Object
|
81
|
+
field_class GraphqlDevise::Types::BaseField
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
If you already have a `field_class` set on your #{type_class}, you can include our concern
|
86
|
+
to make this work
|
87
|
+
|
88
|
+
module Types
|
89
|
+
class BaseField < GraphQL::Schema::Field
|
90
|
+
include GraphqlDevise::FieldAuthentication
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
The concern will define an initializer, if your custom field logic is not standard, you can look
|
95
|
+
at the `GraphqlDevise::FieldAuthentication` implementation to add what is required to your own
|
96
|
+
field class
|
97
|
+
MESSAGE
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
69
101
|
def prepare_resolvers(model, clean_options, authenticatable_type)
|
70
|
-
|
102
|
+
MountMethod::OperationPreparer.new(
|
71
103
|
model: model,
|
72
104
|
custom: clean_options.operations,
|
73
105
|
additional_operations: clean_options.additional_queries,
|
74
|
-
preparer:
|
75
|
-
selected_operations:
|
76
|
-
default:
|
106
|
+
preparer: MountMethod::OperationPreparers::ResolverTypeSetter.new(authenticatable_type),
|
107
|
+
selected_operations: MountMethod::OperationSanitizer.call(
|
108
|
+
default: DefaultOperations::QUERIES, only: clean_options.only, skipped: clean_options.skip
|
77
109
|
)
|
78
110
|
).call
|
79
111
|
end
|
80
112
|
|
81
113
|
def prepare_mutations(model, clean_options, authenticatable_type)
|
82
|
-
|
114
|
+
MountMethod::OperationPreparer.new(
|
83
115
|
model: model,
|
84
116
|
custom: clean_options.operations,
|
85
117
|
additional_operations: clean_options.additional_mutations,
|
86
|
-
preparer:
|
87
|
-
selected_operations:
|
88
|
-
default:
|
118
|
+
preparer: MountMethod::OperationPreparers::MutationFieldSetter.new(authenticatable_type),
|
119
|
+
selected_operations: MountMethod::OperationSanitizer.call(
|
120
|
+
default: DefaultOperations::MUTATIONS, only: clean_options.only, skipped: clean_options.skip
|
89
121
|
)
|
90
122
|
).call
|
91
123
|
end
|
92
124
|
|
93
125
|
def validate_options!(clean_options)
|
94
|
-
|
126
|
+
MountMethod::OptionsValidator.new(
|
95
127
|
[
|
96
|
-
|
97
|
-
|
128
|
+
MountMethod::OptionValidators::SkipOnlyValidator.new(options: clean_options),
|
129
|
+
MountMethod::OptionValidators::ProvidedOperationsValidator.new(
|
98
130
|
options: clean_options, supported_operations: @default_operations
|
99
131
|
)
|
100
132
|
]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module GraphqlDevise
|
2
|
+
module RouteMounter
|
3
|
+
def mount_graphql_devise_for(resource, options = {})
|
4
|
+
clean_options = ResourceLoader.new(resource, options, true).call(
|
5
|
+
Types::QueryType,
|
6
|
+
Types::MutationType
|
7
|
+
)
|
8
|
+
|
9
|
+
post clean_options.at, to: 'graphql_devise/graphql#auth'
|
10
|
+
get clean_options.at, to: 'graphql_devise/graphql#auth'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -4,7 +4,7 @@ module GraphqlDevise
|
|
4
4
|
class SchemaPlugin
|
5
5
|
# NOTE: Based on GQL-Ruby docs https://graphql-ruby.org/schema/introspection.html
|
6
6
|
INTROSPECTION_FIELDS = ['__schema', '__type', '__typename']
|
7
|
-
DEFAULT_NOT_AUTHENTICATED = ->(field) { raise
|
7
|
+
DEFAULT_NOT_AUTHENTICATED = ->(field) { raise AuthenticationError, "#{field} field requires authentication" }
|
8
8
|
|
9
9
|
def initialize(query: nil, mutation: nil, authenticate_default: true, public_introspection: !Rails.env.production?, resource_loaders: [], unauthenticated_proc: DEFAULT_NOT_AUTHENTICATED)
|
10
10
|
@query = query
|
@@ -30,22 +30,7 @@ module GraphqlDevise
|
|
30
30
|
auth_required = authenticate_option(field, trace_data)
|
31
31
|
context = context_from_data(trace_data)
|
32
32
|
|
33
|
-
if context.key?(:resource_name)
|
34
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
|
35
|
-
Providing `resource_name` as part of the GQL context, or doing so by using the `graphql_context(resource_name)`
|
36
|
-
method on your controller is deprecated and will be removed in a future version of this gem.
|
37
|
-
Please use `gql_devise_context` in you controller instead.
|
38
|
-
|
39
|
-
EXAMPLE
|
40
|
-
include GraphqlDevise::SetUserByToken
|
41
|
-
|
42
|
-
DummySchema.execute(params[:query], context: gql_devise_context(User))
|
43
|
-
DummySchema.execute(params[:query], context: gql_devise_context(User, Admin))
|
44
|
-
DEPRECATION
|
45
|
-
end
|
46
|
-
|
47
33
|
if auth_required && !(public_introspection && introspection_field?(field))
|
48
|
-
context = set_current_resource(context)
|
49
34
|
raise_on_missing_resource(context, field, auth_required)
|
50
35
|
end
|
51
36
|
|
@@ -56,25 +41,6 @@ module GraphqlDevise
|
|
56
41
|
|
57
42
|
attr_reader :public_introspection
|
58
43
|
|
59
|
-
def set_current_resource(context)
|
60
|
-
controller = context[:controller]
|
61
|
-
resource_names = Array(context[:resource_name])
|
62
|
-
|
63
|
-
context[:current_resource] ||= resource_names.find do |resource_name|
|
64
|
-
unless Devise.mappings.key?(resource_name)
|
65
|
-
raise(
|
66
|
-
GraphqlDevise::Error,
|
67
|
-
"Invalid resource_name `#{resource_name}` provided to `graphql_context`. Possible values are: #{Devise.mappings.keys}."
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
found = controller.set_resource_by_token(resource_name)
|
72
|
-
break found if found
|
73
|
-
end
|
74
|
-
|
75
|
-
context
|
76
|
-
end
|
77
|
-
|
78
44
|
def raise_on_missing_resource(context, field, auth_required)
|
79
45
|
@unauthenticated_proc.call(field.name) if context[:current_resource].blank?
|
80
46
|
|
@@ -113,7 +79,11 @@ module GraphqlDevise
|
|
113
79
|
auth_required = if trace_data[:context]
|
114
80
|
field.metadata[:authenticate]
|
115
81
|
else
|
116
|
-
if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('
|
82
|
+
if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('2.0')
|
83
|
+
# authenticate will only be defined if "field_class GraphqlDevise::Types::BaseField" is added to the type
|
84
|
+
# returning nil here will use the default value used when mounting the plugin
|
85
|
+
field.try(:authenticate)
|
86
|
+
elsif Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.13.1')
|
117
87
|
field.graphql_definition(silence_deprecation_warning: true).metadata[:authenticate]
|
118
88
|
else
|
119
89
|
field.graphql_definition.metadata[:authenticate]
|
@@ -125,7 +95,7 @@ module GraphqlDevise
|
|
125
95
|
|
126
96
|
def load_fields
|
127
97
|
@resource_loaders.each do |resource_loader|
|
128
|
-
raise Error, 'Invalid resource loader instance' unless resource_loader.instance_of?(
|
98
|
+
raise ::GraphqlDevise::Error, 'Invalid resource loader instance' unless resource_loader.instance_of?(ResourceLoader)
|
129
99
|
|
130
100
|
resource_loader.call(@query, @mutation)
|
131
101
|
end
|
@@ -136,6 +106,3 @@ module GraphqlDevise
|
|
136
106
|
end
|
137
107
|
end
|
138
108
|
end
|
139
|
-
|
140
|
-
GraphQL::Field.accepts_definitions(authenticate: GraphQL::Define.assign_metadata_key(:authenticate))
|
141
|
-
GraphQL::Schema::Field.accepts_definition(:authenticate)
|