diff options
author | Luke Bennett <lbennett@gitlab.com> | 2018-11-29 01:06:10 +0000 |
---|---|---|
committer | Luke Bennett <lbennett@gitlab.com> | 2019-02-18 03:18:13 +0000 |
commit | 97e306a7334d64703c3cd4030c6ea3cd33ec5348 (patch) | |
tree | 5322245e3eaadb3b39169a90321ba3778d26173e | |
parent | 813df901e81257e3175015c94022151824682e83 (diff) | |
download | gitlab-ce-ce-improve-admin-licence-page.tar.gz |
Add GraphQL Metadata query typece-improve-admin-licence-page
Adds metadata resolver and permissions type.
Adds id sort values to Sort type.
24 files changed, 406 insertions, 4 deletions
diff --git a/app/graphql/resolvers/metadata_resolver.rb b/app/graphql/resolvers/metadata_resolver.rb new file mode 100644 index 00000000000..2b1d0d3952a --- /dev/null +++ b/app/graphql/resolvers/metadata_resolver.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Resolvers + class MetadataResolver < BaseResolver + type Types::MetadataType, null: false + + def resolve + { version: Gitlab::VERSION, revision: Gitlab.revision } + end + end +end diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb new file mode 100644 index 00000000000..7d5164fb619 --- /dev/null +++ b/app/graphql/types/metadata_type.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + class MetadataType < ::Types::BaseObject + graphql_name 'Metadata' + + expose_permissions Types::PermissionTypes::Metadata + + field :version, GraphQL::STRING_TYPE, null: false + field :revision, GraphQL::STRING_TYPE, null: false + end +end + +require_dependency Rails.root.join('ee', 'app', 'graphql', 'types', 'ee', 'metadata_type') +Types::MetadataType.prepend(EE::Types::MetadataType) diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 2b4ef299296..513049dff1c 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -9,3 +9,6 @@ module Types mount_mutation Mutations::MergeRequests::SetWip end end + +require_dependency Rails.root.join('ee', 'app', 'graphql', 'types', 'ee', 'mutation_type') +Types::MutationType.prepend(EE::Types::MutationType) diff --git a/app/graphql/types/permission_types/metadata.rb b/app/graphql/types/permission_types/metadata.rb new file mode 100644 index 00000000000..1316231786e --- /dev/null +++ b/app/graphql/types/permission_types/metadata.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Types + module PermissionTypes + class Metadata < BasePermissionType + graphql_name 'MetadataPermissions' + abilities :log_in + end + end +end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 7c41716b82a..22390fc695c 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Types - class QueryType < BaseObject + class QueryType < ::Types::BaseObject graphql_name 'Query' field :project, Types::ProjectType, @@ -11,6 +11,14 @@ module Types authorize :read_project end + field :metadata, Types::MetadataType, + null: true, + resolver: Resolvers::MetadataResolver, + description: 'Metadata about GitLab' do |*args| + + authorize :log_in + end + field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new end end diff --git a/app/graphql/types/sort.rb b/app/graphql/types/sort.rb index 1f756fdab69..da6dfd22e5d 100644 --- a/app/graphql/types/sort.rb +++ b/app/graphql/types/sort.rb @@ -6,5 +6,7 @@ module Types value "updated_asc", "Updated at ascending order" value "created_desc", "Created at descending order" value "created_asc", "Created at ascending order" + value "id_asc", "ID ascending order" + value "id_desc", "ID descending order" end end diff --git a/spec/finders/licenses_finder_spec.rb b/spec/finders/licenses_finder_spec.rb new file mode 100644 index 00000000000..f32d165883e --- /dev/null +++ b/spec/finders/licenses_finder_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe LicensesFinder do + let(:license) { License.last } + + it 'returns a license by id' do + expect(described_class.new(id: license[:id]).execute.take).to eq(license) + end + + it 'returns a sorted collection of licenses' do + expect(described_class.new(sort: 'id_desc').execute).to contain_exactly(*License.all.order_by('id_desc')) + end + + it 'returns empty relation if the license doesnt exist' do + expect(described_class.new(id: license[:id] + 1).execute).to be_empty + end +end diff --git a/spec/graphql/mutations/licenses/delete_spec.rb b/spec/graphql/mutations/licenses/delete_spec.rb new file mode 100644 index 00000000000..d8ff38eaa86 --- /dev/null +++ b/spec/graphql/mutations/licenses/delete_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::Licenses::Delete do + describe '#resolve' do + set(:license) { create(:license) } + + it 'raises an error if the user cannot update the license' do + mutation = described_class.new(object: nil, context: { current_user: create(:user) }) + expect { mutation.resolve(id: license[:id]) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + + describe 'when the user can update the license' do + set(:user) { create(:admin) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } + + it 'returns the deleted license' do + response = mutation.resolve(id: license[:id]) + expect(response[:license]).to eq(license) + expect(License.where(id: license[:id])).not_to exist + expect(response[:errors]).to be_empty + end + + it 'returns an error when the license doesnt exist' do + expect { mutation.resolve(id: license[:id] + 1) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + end +end diff --git a/spec/graphql/resolvers/license_resolver_spec.rb b/spec/graphql/resolvers/license_resolver_spec.rb new file mode 100644 index 00000000000..5e48c49604e --- /dev/null +++ b/spec/graphql/resolvers/license_resolver_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::LicenseResolver do + include GraphqlHelpers + + let(:license) { License.last } + + describe '#resolve' do + it 'returns an existing license found by id' do + expect(resolve_license(license[:id])).to eq(license) + end + + it 'returns nil if the license doesnt exist' do + expect(resolve_license(license[:id] + 1)).to be_nil + end + end + + def resolve_license(id) + resolve(described_class, args: { id: id }) + end +end diff --git a/spec/graphql/resolvers/licenses_resolver_spec.rb b/spec/graphql/resolvers/licenses_resolver_spec.rb new file mode 100644 index 00000000000..f2465806086 --- /dev/null +++ b/spec/graphql/resolvers/licenses_resolver_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::LicensesResolver do + include GraphqlHelpers + + let(:license) { License.last } + + describe '#resolve' do + it 'returns a collection of licenses sorted by asc id by default' do + expect(resolve_licenses).to contain_exactly(*License.all.order_by('id_asc')) + end + + it 'returns a collection of licenses sorted by a provided order_by string' do + expect(resolve_licenses('id_desc')).to contain_exactly(*License.all.order_by('id_asc')) + end + + it 'returns an array if no licenses exist' do + License.delete_all + + expect(resolve_licenses).to eq([]) + end + end + + def resolve_licenses(sort = nil) + resolve(described_class, args: { sort: sort }) + end +end diff --git a/spec/graphql/resolvers/metadata_resolver_spec.rb b/spec/graphql/resolvers/metadata_resolver_spec.rb new file mode 100644 index 00000000000..6fc7bfc355b --- /dev/null +++ b/spec/graphql/resolvers/metadata_resolver_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::MetadataResolver do + include GraphqlHelpers + + describe '#resolve' do + it 'resolves the current version and revision' do + resolution = resolve(described_class) + + expect(resolution[:version]).to eq(Gitlab::VERSION) + expect(resolution[:revision]).to eq(Gitlab.revision) + end + end +end diff --git a/spec/graphql/types/license_type_spec.rb b/spec/graphql/types/license_type_spec.rb new file mode 100644 index 00000000000..2455131c394 --- /dev/null +++ b/spec/graphql/types/license_type_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['License'] do + it 'has license permission type' do + expect(described_class).to expose_permissions_using(Types::PermissionTypes::License) + end + + it 'has required fields' do + required_fields = [ + :id, + :plan, + :expired, + :created_at, + :starts_at, + :expires_at, + :current_active_users_count, + :restricted_user_count, + :historical_max, + :overage, + :licensee + ] + + is_expected.to have_graphql_field(*required_fields) + end + + it 'has a non-null LicenseeType field' do + expect(described_class.fields["licensee"]).to have_graphql_type(Types::LicenseeType.to_non_null_type) + end +end diff --git a/spec/graphql/types/licensee_type_spec.rb b/spec/graphql/types/licensee_type_spec.rb new file mode 100644 index 00000000000..2d43cf0e0b6 --- /dev/null +++ b/spec/graphql/types/licensee_type_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Licensee'] do + it 'has required fields' do + is_expected.to have_graphql_field(:name, :email, :company) + end +end diff --git a/spec/graphql/types/metadata_type.rb b/spec/graphql/types/metadata_type.rb new file mode 100644 index 00000000000..735a97bb229 --- /dev/null +++ b/spec/graphql/types/metadata_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Metadata'] do + it 'is called Metadata' do + expect(described_class.graphql_name).to eq('Metadata') + end + + it 'has license permission type' do + expect(described_class).to expose_permissions_using(Types::PermissionTypes::Metadata) + end + + it 'has required queries' do + is_expected.to have_graphql_field(:version) + is_expected.to have_graphql_field(:revision) + end +end diff --git a/spec/graphql/types/metadata_type_spec.rb b/spec/graphql/types/metadata_type_spec.rb new file mode 100644 index 00000000000..4e1579e2698 --- /dev/null +++ b/spec/graphql/types/metadata_type_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Metadata'] do + context 'license' do + subject { described_class.fields['license'] } + + it 'has required arguments, type and resolver' do + is_expected.to have_graphql_arguments(:id) + is_expected.to have_graphql_type(Types::LicenseType) + is_expected.to have_graphql_resolver(Resolvers::LicenseResolver) + end + + it 'authorizes with read_license' do + is_expected.to require_graphql_authorizations(:read_license) + end + end + + context 'licenses' do + subject { described_class.fields['licenses'] } + + it 'has required arguments, type and resolver' do + is_expected.to have_graphql_arguments(:sort, :after, :before, :first, :last) + is_expected.to have_graphql_connection_type(Types::LicenseType) + is_expected.to have_graphql_resolver(Resolvers::LicensesResolver) + end + end +end diff --git a/spec/graphql/types/permission_types/license_spec.rb b/spec/graphql/types/permission_types/license_spec.rb new file mode 100644 index 00000000000..9e0ee9e410e --- /dev/null +++ b/spec/graphql/types/permission_types/license_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Types::PermissionTypes::License do + it 'has required fields' do + expect(described_class).to have_graphql_fields([:read_license, :update_license]) + end +end diff --git a/spec/graphql/types/permission_types/metadata_spec.rb b/spec/graphql/types/permission_types/metadata_spec.rb new file mode 100644 index 00000000000..b136873e37d --- /dev/null +++ b/spec/graphql/types/permission_types/metadata_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Types::PermissionTypes::Metadata do + it 'has required fields' do + expect(described_class).to have_graphql_fields([:logIn]) + end +end diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index e1df6f9811d..fbe0ea10171 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -5,7 +5,9 @@ describe GitlabSchema.types['Query'] do expect(described_class.graphql_name).to eq('Query') end - it { is_expected.to have_graphql_fields(:project, :echo) } + it 'has required queries' do + is_expected.to have_graphql_fields(:project, :echo, :metadata) + end describe 'project field' do subject { described_class.fields['project'] } diff --git a/spec/requests/api/graphql/license_type_spec.rb b/spec/requests/api/graphql/license_type_spec.rb new file mode 100644 index 00000000000..399499ee124 --- /dev/null +++ b/spec/requests/api/graphql/license_type_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'License' do + include GraphqlHelpers + + set(:license) { create(:license, data: build(:gitlab_license, restrictions: { active_user_count: 10 }, licensee: { Email: 'test@gitlab.com', Name: 'Test User', Company: 'GitLab' }).export) } + set(:license_two) { create(:license, data: build(:gitlab_license, restrictions: { active_user_count: 10 }, licensee: { Email: 'test@gitlab.com', Name: 'Test User', Company: 'GitLab' }).export) } + set(:current_user) { create(:admin) } + + let(:query) do + graphql_query_for('metadata', {}, query_graphql_field('license', { id: license[:id] })) + end + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: current_user) + end + end + + context 'licenses collection' do + let(:query) do + fields = <<~FIELDS + edges { + node { + #{all_graphql_fields_for('license'.classify)} + } + } + FIELDS + graphql_query_for('metadata', {}, query_graphql_field('licenses', { after: '', first: 2, sort: :id_desc }, fields)) + end + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: current_user) + end + end + end +end diff --git a/spec/requests/api/graphql/metadata_type_spec.rb b/spec/requests/api/graphql/metadata_type_spec.rb new file mode 100644 index 00000000000..a340623918f --- /dev/null +++ b/spec/requests/api/graphql/metadata_type_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Metadata' do + include GraphqlHelpers + + set(:current_user) { create(:user) } + let(:query) do + fields = <<~FIELDS + version + revision + FIELDS + graphql_query_for('metadata', {}, fields) + end + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: current_user) + end + end + + it 'returns version and revision' do + post_graphql(query, current_user: current_user) + + expect(graphql_data['metadata']['version']).to eq(Gitlab::VERSION) + expect(graphql_data['metadata']['revision']).to eq(Gitlab.revision) + end +end diff --git a/spec/requests/api/graphql/mutations/licenses/delete_spec.rb b/spec/requests/api/graphql/mutations/licenses/delete_spec.rb new file mode 100644 index 00000000000..e3632a26ab8 --- /dev/null +++ b/spec/requests/api/graphql/mutations/licenses/delete_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Deleting an instance license' do + include GraphqlHelpers + + set(:user) { create(:admin) } + set(:license) { create(:license) } + let(:mutation) do + variables = { + id: license[:id] + } + graphql_mutation(:license_delete, variables) + end + + def mutation_response + graphql_mutation_response(:license_delete) + end + + it 'returns an error if the user is not allowed to update the license' do + post_graphql_mutation(mutation, current_user: create(:user)) + + expect(graphql_errors).not_to be_empty + end + + it 'deletes the license' do + post_graphql_mutation(mutation, current_user: user) + + expect(response).to have_gitlab_http_status(:success) + expect(License.where(id: license[:id])).not_to exist + end +end diff --git a/spec/services/licenses/destroy_service_spec.rb b/spec/services/licenses/destroy_service_spec.rb new file mode 100644 index 00000000000..f4aad2c618b --- /dev/null +++ b/spec/services/licenses/destroy_service_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Licenses::DestroyService do + set(:license) { create(:license) } + + def destroy(user) + described_class.new(license, user).execute + end + + it 'destroys a license' do + destroy(create(:admin)) + + expect(License.where(id: license[:id])).not_to exist + end + + it 'raises an error if the user cannot delete the license' do + expect { destroy(create(:user)) }.to raise_error Gitlab::Access::AccessDeniedError + end +end diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index e468ee4676d..40fb6aa66af 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -12,7 +12,7 @@ module GraphqlHelpers # Run a loader's named resolver def resolve(resolver_class, obj: nil, args: {}, ctx: {}) - resolver_class.new(object: obj, context: ctx).resolve(args) + resolver_class.new(object: obj, context: ctx).resolve(**args) end # Runs a block inside a BatchLoader::Executor wrapper @@ -111,7 +111,8 @@ module GraphqlHelpers def attributes_to_graphql(attributes) attributes.map do |name, value| - "#{GraphqlHelpers.fieldnamerize(name.to_s)}: \"#{value}\"" + attribute = "#{GraphqlHelpers.fieldnamerize(name.to_s)}: " + attribute << (value.is_a?(Integer) || value.is_a?(Symbol) ? value.to_s : "\"#{value}\"") end.join(", ") end diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb index 7be84838e00..ea106a43123 100644 --- a/spec/support/matchers/graphql_matchers.rb +++ b/spec/support/matchers/graphql_matchers.rb @@ -58,6 +58,12 @@ RSpec::Matchers.define :have_graphql_type do |expected| end end +RSpec::Matchers.define :have_graphql_connection_type do |expected| + match do |field| + expect(field.type).to eq(expected.connection_type) + end +end + RSpec::Matchers.define :have_graphql_resolver do |expected| match do |field| case expected |