Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/graphql_devise/schema_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def trace(event, trace_data)

if auth_required && !(public_introspection && introspection_field?(field))
context = set_current_resource(context)
raise_on_missing_resource(context, field)
raise_on_missing_resource(context, field, auth_required)
end

yield
Expand Down Expand Up @@ -75,8 +75,12 @@ def set_current_resource(context)
context
end

def raise_on_missing_resource(context, field)
def raise_on_missing_resource(context, field, auth_required)
@unauthenticated_proc.call(field.name) if context[:current_resource].blank?

if auth_required.respond_to?(:call) && !auth_required.call(context[:current_resource])
@unauthenticated_proc.call(field.name)
end
end

def context_from_data(trace_data)
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/app/graphql/types/query_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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
field :vip_field, String, null: false, authenticate: ->(user) { user.is_a?(User) && user.vip? }

def public_field
'Field does not require authentication'
Expand All @@ -13,5 +14,9 @@ def public_field
def private_field
'Field will always require authentication'
end

def vip_field
'Field available only for VIP Users'
end
end
end
5 changes: 5 additions & 0 deletions spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddVipToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :vip, :boolean, null: false, default: false
end
end
7 changes: 4 additions & 3 deletions spec/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `rails
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2020_06_23_003142) do
ActiveRecord::Schema.define(version: 2021_05_16_211417) do

create_table "admins", force: :cascade do |t|
t.string "provider", default: "email", null: false
Expand Down Expand Up @@ -105,6 +105,7 @@
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "auth_available", default: true, null: false
t.boolean "vip", default: false, null: false
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
Expand Down
101 changes: 71 additions & 30 deletions spec/requests/user_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
RSpec.describe "Integrations with the user's controller" do
include_context 'with graphql query request'

shared_examples 'returns a must authenticate error' do |field|
it 'returns a must sign in error' do
expect(json_response[:errors]).to contain_exactly(
hash_including(message: "#{field} field requires authentication", extensions: { code: 'AUTHENTICATION_ERROR' })
)
end
end

let(:user) { create(:user, :confirmed) }

describe 'publicField' do
Expand Down Expand Up @@ -54,11 +62,7 @@
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: 'AUTHENTICATION_ERROR' })
)
end
it_behaves_like 'returns a must authenticate error', 'privateField'
end
end

Expand All @@ -82,11 +86,7 @@
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: 'AUTHENTICATION_ERROR' })
)
end
it_behaves_like 'returns a must authenticate error', 'privateField'
end

context 'when using the failing route' do
Expand All @@ -111,11 +111,7 @@
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: 'AUTHENTICATION_ERROR' })
)
end
it_behaves_like 'returns a must authenticate error', 'privateField'
end
end
end
Expand All @@ -141,11 +137,7 @@
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: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
)
end
it_behaves_like 'returns a must authenticate error', 'dummyMutation'
end
end

Expand All @@ -161,11 +153,7 @@
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: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
)
end
it_behaves_like 'returns a must authenticate error', 'dummyMutation'
end
end
end
Expand Down Expand Up @@ -199,11 +187,7 @@
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: 'AUTHENTICATION_ERROR' })
)
end
it_behaves_like 'returns a must authenticate error', 'user'
end
end

Expand Down Expand Up @@ -271,4 +255,61 @@
)
end
end

describe 'vipField' do
let(:error_message) { 'Field available only for VIP Users' }
let(:query) do
<<-GRAPHQL
query { vipField }
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 schema user is VIP' do
let(:user) { create(:user, :confirmed, vip: true) }

it 'allows to perform the query' do
expect(json_response[:data][:vipField]).to eq(error_message)
end
end

context 'when schema user is not VIP' do
it_behaves_like 'returns a must authenticate error', 'vipField'
end
end

context 'when user is not authenticated' do
it_behaves_like 'returns a must authenticate error', 'vipField'
end
end

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

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

context 'when schema user is VIP' do
let(:user) { create(:user, :confirmed, vip: true) }

it 'allows to perform the query' do
expect(json_response[:data][:vipField]).to eq(error_message)
end
end

context 'when schema user is not VIP' do
it_behaves_like 'returns a must authenticate error', 'vipField'
end
end

context 'when user is not authenticated' do
it_behaves_like 'returns a must authenticate error', 'vipField'
end
end
end
end