Skip to content

Commit

Permalink
Rename controller concern, add context method, add more test scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
mcelicalderon committed Jun 10, 2020
1 parent 6898d21 commit 7cb6072
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 59 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ In our example our model is `User`, so it would look like this:
# app/controllers/my_controller.rb

class MyController < ApplicationController
include GraphqlDevise::Concerns::SetUserByToken
include GraphqlDevise::Concerns::SetResourceByToken

before_action :authenticate_user!

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
module GraphqlDevise
module Concerns
SetUserByToken = DeviseTokenAuth::Concerns::SetUserByToken
SetResourceByToken = DeviseTokenAuth::Concerns::SetUserByToken

SetUserByToken.module_eval do
DeviseTokenAuth::Concerns::SetUserByToken.module_eval do
attr_accessor :client_id, :token, :resource

alias_method :set_resource_by_token, :set_user_by_token

def graphql_context
{
current_resource: @resource,
controller: self
}
end

def build_redirect_headers(access_token, client, redirect_header_options = {})
{
DeviseTokenAuth.headers_names[:"access-token"] => access_token,
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/graphql_devise/graphql_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module GraphqlDevise
class GraphqlController < ApplicationController
include GraphqlDevise::Concerns::SetUserByToken
include GraphqlDevise::Concerns::SetResourceByToken

def auth
result = if params[:_json]
Expand Down
4 changes: 2 additions & 2 deletions lib/generators/graphql_devise/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def execute_dta_installer
end
gsub_file(
'app/controllers/application_controller.rb',
'GraphqlDevise::Concerns::SetUserByToken',
'GraphqlDevise::Concerns::SetResourceByToken',
'DeviseTokenAuth::Concerns::SetUserByToken'
)

Expand Down Expand Up @@ -53,7 +53,7 @@ def replace_controller_concern
gsub_file(
'app/controllers/application_controller.rb',
/^\s+include DeviseTokenAuth::Concerns::SetUserByToken/,
' include GraphqlDevise::Concerns::SetUserByToken'
' include GraphqlDevise::Concerns::SetResourceByToken'
)
end

Expand Down
11 changes: 5 additions & 6 deletions lib/graphql_devise/schema_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ def trace(event, trace_data)
field = traced_field(trace_data)
provided_value = authenticate_option(field, trace_data)

if (!provided_value.nil? && provided_value) || @authenticate_default
raise_on_missing_resource(
context(trace_data),
field
)
if !provided_value.nil?
raise_on_missing_resource(context(trace_data), field) if provided_value
elsif @authenticate_default
raise_on_missing_resource(context(trace_data), field)
end

yield
Expand Down Expand Up @@ -78,7 +77,7 @@ def load_fields
@resource_loaders.each do |resource_loader|
raise Error, 'Invalid resource loader instance' unless resource_loader.instance_of?(GraphqlDevise::ResourceLoader)

resource_loader.call(@query, @mutation, false)
resource_loader.call(@query, @mutation)
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions spec/dummy/app/controllers/api/v1/graphql_controller.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module Api
module V1
class GraphqlController < ApplicationController
include GraphqlDevise::Concerns::SetUserByToken
include GraphqlDevise::Concerns::SetResourceByToken

before_action -> { set_user_by_token(:user) }
before_action -> { set_resource_by_token(:user) }

def graphql
render json: DummySchema.execute(params[:query], context: { current_resource: @resource, controller: self })
render json: DummySchema.execute(params[:query], context: graphql_context)
end

def interpreter
render json: InterpreterSchema.execute(params[:query], context: { current_resource: @resource, controller: self })
render json: InterpreterSchema.execute(params[:query], context: graphql_context)
end

private
Expand Down
9 changes: 8 additions & 1 deletion spec/dummy/app/graphql/dummy_schema.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
class DummySchema < GraphQL::Schema
use GraphqlDevise::SchemaPlugin.new(query: Types::QueryType)
use GraphqlDevise::SchemaPlugin.new(
query: Types::QueryType,
mutation: Types::MutationType,
resource_loaders: [
GraphqlDevise::ResourceLoader.new('User', only: [:login, :confirm_account]),
GraphqlDevise::ResourceLoader.new('Guest', only: [:logout])
]
)

mutation(Types::MutationType)
query(Types::QueryType)
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/graphql/interpreter_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class InterpreterSchema < GraphQL::Schema
use GraphQL::Execution::Interpreter if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.9.0')
use GraphQL::Analysis::AST if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.10.0')

use GraphqlDevise::SchemaPlugin.new(query: Types::QueryType)
use GraphqlDevise::SchemaPlugin.new(query: Types::QueryType, authenticate_default: false)

mutation(Types::MutationType)
query(Types::QueryType)
Expand Down
10 changes: 10 additions & 0 deletions spec/dummy/app/graphql/types/query_type.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
module Types
class QueryType < Types::BaseObject
field :user, resolver: Resolvers::UserShow
field :public_field, String, null: false, authenticate: false
field :private_field, String, null: false, authenticate: true

def public_field
'Field does not require authentication'
end

def private_field
'Field will always require authentication'
end
end
end
4 changes: 2 additions & 2 deletions spec/generators/graphql_devise/install_generator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

assert_file 'app/models/user.rb', /^\s{2}devise :.+include GraphqlDevise::Concerns::Model/m

assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetUserByToken/
assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetResourceByToken/
end
end

Expand All @@ -51,7 +51,7 @@

assert_file 'app/models/admin.rb', /^\s{2}devise :.+include GraphqlDevise::Concerns::Model/m

assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetUserByToken/
assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetResourceByToken/
end
end

Expand Down
159 changes: 120 additions & 39 deletions spec/requests/user_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -1,64 +1,145 @@
require 'rails_helper'

RSpec.describe 'Integrations with the user controller' do
RSpec.describe "Integrations with the user's controller" do
include_context 'with graphql query request'

let(:user) { create(:user, :confirmed) }
let(:query) do
<<-GRAPHQL
query {
user(
id: #{user.id}
) {
id
email

describe 'publicField' do
let(:query) do
<<-GRAPHQL
query {
publicField
}
}
GRAPHQL
GRAPHQL
end

context 'when using a regular schema' do
before { post_request('/api/v1/graphql') }

it 'does not require authentication' do
expect(json_response[:data][:publicField]).to eq('Field does not require authentication')
end
end

context 'when using an interpreter schema' do
before { post_request('/api/v1/interpreter') }

it 'does not require authentication' do
expect(json_response[:data][:publicField]).to eq('Field does not require authentication')
end
end
end

context 'when using a regular schema' do
before { post_request('/api/v1/graphql') }
describe 'privateField' do
let(:query) do
<<-GRAPHQL
query {
privateField
}
GRAPHQL
end

context 'when using a regular schema' do
before { post_request('/api/v1/graphql') }

context 'when user is authenticated' do
let(:headers) { user.create_new_auth_token }

context 'when user is authenticated' do
let(:headers) { user.create_new_auth_token }
it 'allow to perform the query' do
expect(json_response[:data][:privateField]).to eq('Field will always require authentication')
end
end

it 'allow to perform the query' do
expect(json_response[:data][:user]).to match(
email: user.email,
id: user.id
)
context 'when user is not authenticated' do
it 'returns a must sign in error' do
expect(json_response[:errors]).to contain_exactly(
hash_including(message: 'privateField field requires authentication', extensions: { code: 'USER_ERROR' })
)
end
end
end

context 'when user is not authenticated' do
it 'returns a must sign in error' do
expect(json_response[:errors]).to contain_exactly(
hash_including(message: 'user field requires authentication', extensions: { code: 'USER_ERROR' })
)
context 'when using an interpreter schema' do
before { post_request('/api/v1/interpreter') }

context 'when user is authenticated' do
let(:headers) { user.create_new_auth_token }

it 'allow to perform the query' do
expect(json_response[:data][:privateField]).to eq('Field will always require authentication')
end
end

context 'when user is not authenticated' do
it 'returns a must sign in error' do
expect(json_response[:errors]).to contain_exactly(
hash_including(message: 'privateField field requires authentication', extensions: { code: 'USER_ERROR' })
)
end
end
end
end

context 'when using an interpreter schema' do
before { post_request('/api/v1/interpreter') }
describe 'user' do
let(:query) do
<<-GRAPHQL
query {
user(
id: #{user.id}
) {
id
email
}
}
GRAPHQL
end

context 'when using a regular schema' do
before { post_request('/api/v1/graphql') }

context 'when user is authenticated' do
let(:headers) { user.create_new_auth_token }

context 'when user is authenticated' do
let(:headers) { user.create_new_auth_token }
it 'allow to perform the query' do
expect(json_response[:data][:user]).to match(
email: user.email,
id: user.id
)
end
end

it 'allow to perform the query' do
expect(json_response[:data][:user]).to match(
email: user.email,
id: user.id
)
context 'when user is not authenticated' do
it 'returns a must sign in error' do
expect(json_response[:errors]).to contain_exactly(
hash_including(message: 'user field requires authentication', extensions: { code: 'USER_ERROR' })
)
end
end
end

context 'when user is not authenticated' do
it 'returns a must sign in error' do
expect(json_response[:errors]).to contain_exactly(
hash_including(message: 'user field requires authentication', extensions: { code: 'USER_ERROR' })
)
context 'when using an interpreter schema' do
before { post_request('/api/v1/interpreter') }

context 'when user is authenticated' do
let(:headers) { user.create_new_auth_token }

it 'allow to perform the query' do
expect(json_response[:data][:user]).to match(
email: user.email,
id: user.id
)
end
end

context 'when user is not authenticated' do
# Interpreter schema fields are public unless specified otherwise (plugin setting)
it 'allow to perform the query' do
expect(json_response[:data][:user]).to match(
email: user.email,
id: user.id
)
end
end
end
end
Expand Down

0 comments on commit 7cb6072

Please sign in to comment.