Commit eb8551ae authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '247930-remove-resolve-procs-from-types-2' into 'master'

GraphQL: Remove use of resolve procs from type definitions (Part 2)

See merge request gitlab-org/gitlab!44747
parents 67053805 ccb37cbc
...@@ -33,44 +33,61 @@ module Types ...@@ -33,44 +33,61 @@ module Types
description: "Indicates whether the vulnerability is fixed on the default branch or not" description: "Indicates whether the vulnerability is fixed on the default branch or not"
field :user_notes_count, GraphQL::INT_TYPE, null: false, field :user_notes_count, GraphQL::INT_TYPE, null: false,
description: 'Number of user notes attached to the vulnerability', description: 'Number of user notes attached to the vulnerability'
resolve: -> (obj, _args, ctx) {
::Gitlab::Graphql::Aggregations::Vulnerabilities::LazyUserNotesCountAggregate.new(ctx, obj)
}
field :vulnerability_path, GraphQL::STRING_TYPE, null: true, field :vulnerability_path, GraphQL::STRING_TYPE, null: true,
description: "URL to the vulnerability's details page", description: "URL to the vulnerability's details page"
resolve: -> (obj, _args, _ctx) { ::Gitlab::Routing.url_helpers.project_security_vulnerability_path(obj.project, obj) }
field :issue_links, ::Types::Vulnerability::IssueLinkType.connection_type, null: false, field :issue_links, ::Types::Vulnerability::IssueLinkType.connection_type, null: false,
description: "List of issue links related to the vulnerability", description: "List of issue links related to the vulnerability",
resolver: Resolvers::Vulnerabilities::IssueLinksResolver resolver: Resolvers::Vulnerabilities::IssueLinksResolver
field :location, VulnerabilityLocationType, null: true, field :location, VulnerabilityLocationType, null: true,
description: 'Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability', description: 'Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability'
resolve: -> (obj, _args, _ctx) { obj.finding&.location&.merge(report_type: obj.report_type) }
field :scanner, VulnerabilityScannerType, null: true, field :scanner, VulnerabilityScannerType, null: true,
description: 'Scanner metadata for the vulnerability.', description: 'Scanner metadata for the vulnerability.'
resolve: -> (obj, _args, _ctx) do
Representation::VulnerabilityScannerEntry.new(obj.finding&.scanner, obj.report_type)
end
field :primary_identifier, VulnerabilityIdentifierType, null: true, field :primary_identifier, VulnerabilityIdentifierType, null: true,
description: 'Primary identifier of the vulnerability.', description: 'Primary identifier of the vulnerability.'
resolve: -> (obj, _args, _ctx) { obj.finding&.primary_identifier }
field :identifiers, [VulnerabilityIdentifierType], null: false, field :identifiers, [VulnerabilityIdentifierType], null: false,
description: 'Identifiers of the vulnerability.', description: 'Identifiers of the vulnerability.'
resolve: -> (obj, _args, _ctx) { obj.finding&.identifiers }
field :project, ::Types::ProjectType, null: true, field :project, ::Types::ProjectType, null: true,
description: 'The project on which the vulnerability was found', description: 'The project on which the vulnerability was found',
authorize: :read_project, authorize: :read_project
resolve: -> (obj, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, obj.project_id).find }
field :detected_at, Types::TimeType, null: false, field :detected_at, Types::TimeType, null: false,
description: 'Timestamp of when the vulnerability was first detected', description: 'Timestamp of when the vulnerability was first detected',
method: :created_at method: :created_at
def user_notes_count
::Gitlab::Graphql::Aggregations::Vulnerabilities::LazyUserNotesCountAggregate.new(context, object)
end
def vulnerability_path
::Gitlab::Routing.url_helpers.project_security_vulnerability_path(object.project, object)
end
def location
object.finding&.location&.merge(report_type: object.report_type)
end
def scanner
Representation::VulnerabilityScannerEntry.new(object.finding&.scanner, object.report_type)
end
def primary_identifier
object.finding&.primary_identifier
end
def identifiers
object.finding&.identifiers
end
def project
Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
end
end end
end end
...@@ -19,24 +19,29 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -19,24 +19,29 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
options.reverse_merge!(null: true) options.reverse_merge!(null: true)
field :test_field, field_type, field :test_field, field_type,
authorize: field_authorizations, authorize: field_authorizations,
resolve: -> (_, _, _) { resolved_value },
**options **options
define_method :test_field do
resolved_value
end
end end
end end
let(:current_user) { double(:current_user) }
subject(:service) { described_class.new(field) } subject(:service) { described_class.new(field) }
describe '#authorized_resolve' do describe '#authorized_resolve' do
let(:presented_object) { double('presented object') } let_it_be(:current_user) { build(:user) }
let(:presented_type) { double('parent type', object: presented_object) } let_it_be(:presented_object) { 'presented object' }
let(:query_type) { GraphQL::ObjectType.new } let_it_be(:query_type) { GraphQL::ObjectType.new }
let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)} let_it_be(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
let(:query_context) { OpenStruct.new(schema: schema) } let_it_be(:query) { GraphQL::Query.new(schema, document: nil, context: {}, variables: {}) }
let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema, context: query_context), values: { current_user: current_user }, object: nil) } let_it_be(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }, object: nil) }
let(:type_class) { type_with_field(custom_type, :read_field, presented_object) }
let(:type_instance) { type_class.authorized_new(presented_object, context) }
let(:field) { type_class.fields['testField'].to_graphql }
subject(:resolved) { service.authorized_resolve.call(presented_type, {}, context) } subject(:resolved) { service.authorized_resolve.call(type_instance, {}, context) }
context 'scalar types' do context 'scalar types' do
shared_examples 'checking permissions on the presented object' do shared_examples 'checking permissions on the presented object' do
...@@ -48,7 +53,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -48,7 +53,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
expect(resolved).to eq('Resolved value') expect(resolved).to eq('Resolved value')
end end
it "returns nil if the value wasn't authorized" do it 'returns nil if the value was not authorized' do
allow(Ability).to receive(:allowed?).and_return false allow(Ability).to receive(:allowed?).and_return false
expect(resolved).to be_nil expect(resolved).to be_nil
...@@ -56,28 +61,28 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -56,28 +61,28 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end end
context 'when the field is a built-in scalar type' do context 'when the field is a built-in scalar type' do
let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields['testField'].to_graphql } let(:type_class) { type_with_field(GraphQL::STRING_TYPE, :read_field) }
let(:expected_permissions) { [:read_field] } let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object' it_behaves_like 'checking permissions on the presented object'
end end
context 'when the field is a list of scalar types' do context 'when the field is a list of scalar types' do
let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields['testField'].to_graphql } let(:type_class) { type_with_field([GraphQL::STRING_TYPE], :read_field) }
let(:expected_permissions) { [:read_field] } let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object' it_behaves_like 'checking permissions on the presented object'
end end
context 'when the field is sub-classed scalar type' do context 'when the field is sub-classed scalar type' do
let(:field) { type_with_field(Types::TimeType, :read_field).fields['testField'].to_graphql } let(:type_class) { type_with_field(Types::TimeType, :read_field) }
let(:expected_permissions) { [:read_field] } let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object' it_behaves_like 'checking permissions on the presented object'
end end
context 'when the field is a list of sub-classed scalar types' do context 'when the field is a list of sub-classed scalar types' do
let(:field) { type_with_field([Types::TimeType], :read_field).fields['testField'].to_graphql } let(:type_class) { type_with_field([Types::TimeType], :read_field) }
let(:expected_permissions) { [:read_field] } let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object' it_behaves_like 'checking permissions on the presented object'
...@@ -86,7 +91,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -86,7 +91,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
context 'when the field is a connection' do context 'when the field is a connection' do
context 'when it resolves to nil' do context 'when it resolves to nil' do
let(:field) { type_with_field(Types::QueryType.connection_type, :read_field, nil).fields['testField'].to_graphql } let(:type_class) { type_with_field(Types::QueryType.connection_type, :read_field, nil) }
it 'does not fail when authorizing' do it 'does not fail when authorizing' do
expect(resolved).to be_nil expect(resolved).to be_nil
...@@ -97,7 +102,11 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -97,7 +102,11 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
context 'when the field is a specific type' do context 'when the field is a specific type' do
let(:custom_type) { type(:read_type) } let(:custom_type) { type(:read_type) }
let(:object_in_field) { double('presented in field') } let(:object_in_field) { double('presented in field') }
let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields['testField'].to_graphql }
let(:type_class) { type_with_field(custom_type, :read_field, object_in_field) }
let(:type_instance) { type_class.authorized_new(object_in_field, context) }
subject(:resolved) { service.authorized_resolve.call(type_instance, {}, context) }
it 'checks both field & type permissions' do it 'checks both field & type permissions' do
spy_ability_check_for(:read_field, object_in_field, passed: true) spy_ability_check_for(:read_field, object_in_field, passed: true)
...@@ -114,7 +123,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -114,7 +123,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end end
context 'when the field is not nullable' do context 'when the field is not nullable' do
let(:field) { type_with_field(custom_type, [], object_in_field, null: false).fields['testField'].to_graphql } let(:type_class) { type_with_field(custom_type, :read_field, object_in_field, null: false) }
it 'returns nil when viewing is not allowed' do it 'returns nil when viewing is not allowed' do
spy_ability_check_for(:read_type, object_in_field, passed: false) spy_ability_check_for(:read_type, object_in_field, passed: false)
...@@ -127,7 +136,9 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do ...@@ -127,7 +136,9 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
let(:object_1) { double('presented in field 1') } let(:object_1) { double('presented in field 1') }
let(:object_2) { double('presented in field 2') } let(:object_2) { double('presented in field 2') }
let(:presented_types) { [double(object: object_1), double(object: object_2)] } let(:presented_types) { [double(object: object_1), double(object: object_2)] }
let(:field) { type_with_field([custom_type], :read_field, presented_types).fields['testField'].to_graphql }
let(:type_class) { type_with_field([custom_type], :read_field, presented_types) }
let(:type_instance) { type_class.authorized_new(presented_types, context) }
it 'checks all permissions' do it 'checks all permissions' do
allow(Ability).to receive(:allowed?) { true } allow(Ability).to receive(:allowed?) { true }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment