diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index a7f0d24f..332f6ba4 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -40,6 +40,10 @@ class QueryType < Types::BaseObject argument :id, Types::GlobalIdType[::Namespace], required: true, description: 'GlobalID of the target namespace' end + field :user, Types::UserType, null: true, description: 'Find a user' do + argument :id, Types::GlobalIdType[::User], required: true, description: 'GlobalID of the target user' + end + field :users, Types::UserType.connection_type, null: false, description: 'Find users' field :global_runtimes, Types::RuntimeType.connection_type, null: false, description: 'Find runtimes' @@ -83,7 +87,13 @@ def namespace(id:) SagittariusSchema.object_from_id(id) end + def user(id:) + SagittariusSchema.object_from_id(id) + end + def users + return User.none unless Ability.allowed?(context[:current_authentication], :list_users, :global) + User.all end diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb index 84e90fd8..770fd1c1 100644 --- a/app/policies/global_policy.rb +++ b/app/policies/global_policy.rb @@ -20,5 +20,6 @@ class GlobalPolicy < BasePolicy enable :update_runtime enable :delete_runtime enable :rotate_runtime_token + enable :list_users end end diff --git a/docs/graphql/object/query.md b/docs/graphql/object/query.md index f7046c80..9d8a171c 100644 --- a/docs/graphql/object/query.md +++ b/docs/graphql/object/query.md @@ -68,3 +68,13 @@ Returns [`Organization`](../object/organization.md). |------|------|-------------| | `id` | [`OrganizationID`](../scalar/organizationid.md) | GlobalID of the target organization | | `name` | [`String`](../scalar/string.md) | Name of the target organization | + +### user + +Find a user + +Returns [`User`](../object/user.md). + +| Name | Type | Description | +|------|------|-------------| +| `id` | [`UserID!`](../scalar/userid.md) | GlobalID of the target user | diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index 179b49ba..56bae912 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -12,6 +12,7 @@ organization organizations users + user global_runtimes namespace userAbilities diff --git a/spec/requests/graphql/query/user_query_spec.rb b/spec/requests/graphql/query/user_query_spec.rb new file mode 100644 index 00000000..87bd4c8a --- /dev/null +++ b/spec/requests/graphql/query/user_query_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'user Query' do + include GraphqlHelpers + + subject(:query!) { post_graphql query, current_user: current_user } + + let(:target_user) { create(:user) } + let(:query) do + <<~QUERY + query { + user(id: "#{target_user.to_global_id}") { + id + username + } + } + QUERY + end + + context 'when anonymous' do + let(:current_user) { nil } + + it 'returns nil due to read_user authorization on UserType' do + query! + + expect(graphql_data_at(:user)).to be_nil + end + end + + context 'when logged in as regular user' do + let(:current_user) { create(:user) } + + it 'returns the user' do + query! + + expect(graphql_data_at(:user, :id)).to eq(target_user.to_global_id.to_s) + expect(graphql_data_at(:user, :username)).to eq(target_user.username) + end + end + + context 'when logged in as admin user' do + let(:current_user) { create(:user, :admin) } + + it 'returns the user' do + query! + + expect(graphql_data_at(:user, :id)).to eq(target_user.to_global_id.to_s) + expect(graphql_data_at(:user, :username)).to eq(target_user.username) + end + end + + context 'when querying self' do + let(:current_user) { create(:user) } + let(:target_user) { current_user } + + it 'returns the user' do + query! + + expect(graphql_data_at(:user, :id)).to eq(current_user.to_global_id.to_s) + expect(graphql_data_at(:user, :username)).to eq(current_user.username) + end + end +end diff --git a/spec/requests/graphql/query/users_query_spec.rb b/spec/requests/graphql/query/users_query_spec.rb new file mode 100644 index 00000000..0db57b59 --- /dev/null +++ b/spec/requests/graphql/query/users_query_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'users Query' do + include GraphqlHelpers + + let(:query) do + <<~QUERY + query { + users { + nodes { + id + username + } + } + } + QUERY + end + + before do + create(:user) + create(:user) + create(:user) + + post_graphql query, current_user: current_user + end + + context 'when anonymous' do + let(:current_user) { nil } + + it 'returns an error' do + expect(graphql_data_at(:users, :nodes)).to be_empty + end + end + + context 'when logged in as regular user' do + let(:current_user) { create(:user) } + + it 'returns an error' do + expect(graphql_data_at(:users, :nodes)).to be_empty + end + end + + context 'when logged in as admin user' do + let(:current_user) { create(:user, :admin) } + + it 'returns all users' do + expect(graphql_data_at(:users, :nodes)).to have_attributes(length: 4) + end + end +end