diff --git a/app/finders/organizations_finder.rb b/app/finders/organizations_finder.rb index fe80a07e..51b3afd2 100644 --- a/app/finders/organizations_finder.rb +++ b/app/finders/organizations_finder.rb @@ -5,6 +5,7 @@ def execute organizations = base_scope organizations = by_id(organizations) organizations = by_name(organizations) + organizations = by_namespace_member_user(organizations) super(organizations) end @@ -26,4 +27,15 @@ def by_name(organizations) organizations.where(name: params[:name]) end + + def by_namespace_member_user(organizations) + return organizations unless params.key?(:namespace_member_user) + return Organization.none if params[:namespace_member_user].nil? + + namespaces = NamespaceMember.where(user_id: params[:namespace_member_user][:id]).select(:namespace_id) + + organizations.where( + id: Namespace.where(id: namespaces, parent_type: 'Organization').select(:parent_id) + ) + end end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index da573fec..8a7ee22b 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -34,6 +34,8 @@ class QueryType < Types::BaseObject require_one_of %i[id name] end + field :organizations, Types::OrganizationType.connection_type, null: false, description: 'Find organizations' + field :namespace, Types::NamespaceType, null: true, description: 'Find a namespace' do argument :id, Types::GlobalIdType[::Namespace], required: true, description: 'GlobalID of the target namespace' end @@ -64,6 +66,10 @@ def organization(**args) OrganizationsFinder.new(**args, single: true).execute end + def organizations + OrganizationsFinder.new(namespace_member_user: current_user).execute + end + def namespace(id:) SagittariusSchema.object_from_id(id) end diff --git a/docs/graphql/object/organizationconnection.md b/docs/graphql/object/organizationconnection.md new file mode 100644 index 00000000..62ffe584 --- /dev/null +++ b/docs/graphql/object/organizationconnection.md @@ -0,0 +1,15 @@ +--- +title: OrganizationConnection +--- + +The connection type for Organization. + +## Fields without arguments + +| Name | Type | Description | +|------|------|-------------| +| `count` | [`Int!`](../scalar/int.md) | Total count of collection. | +| `edges` | [`[OrganizationEdge]`](../object/organizationedge.md) | A list of edges. | +| `nodes` | [`[Organization]`](../object/organization.md) | A list of nodes. | +| `pageInfo` | [`PageInfo!`](../object/pageinfo.md) | Information to aid in pagination. | + diff --git a/docs/graphql/object/organizationedge.md b/docs/graphql/object/organizationedge.md new file mode 100644 index 00000000..d521b10e --- /dev/null +++ b/docs/graphql/object/organizationedge.md @@ -0,0 +1,13 @@ +--- +title: OrganizationEdge +--- + +An edge in a connection. + +## Fields without arguments + +| Name | Type | Description | +|------|------|-------------| +| `cursor` | [`String!`](../scalar/string.md) | A cursor for use in pagination. | +| `node` | [`Organization`](../object/organization.md) | The item at the end of the edge. | + diff --git a/docs/graphql/object/query.md b/docs/graphql/object/query.md index 9dc8912d..fea125e0 100644 --- a/docs/graphql/object/query.md +++ b/docs/graphql/object/query.md @@ -12,6 +12,7 @@ Root Query type | `currentAuthentication` | [`Authentication`](../union/authentication.md) | Get the currently logged in authentication | | `currentUser` | [`User`](../object/user.md) | Get the currently logged in user | | `globalRuntimes` | [`RuntimeConnection!`](../object/runtimeconnection.md) | Find runtimes | +| `organizations` | [`OrganizationConnection!`](../object/organizationconnection.md) | Find organizations | | `users` | [`UserConnection!`](../object/userconnection.md) | Find users | ## Fields with arguments diff --git a/spec/finders/organizations_finder_spec.rb b/spec/finders/organizations_finder_spec.rb index abc347ab..5d963730 100644 --- a/spec/finders/organizations_finder_spec.rb +++ b/spec/finders/organizations_finder_spec.rb @@ -26,6 +26,23 @@ it { is_expected.to contain_exactly(second_organization) } end + context 'when filtering by namespace member' do + let(:user) { create(:user) } + let(:params) { { namespace_member_user: user } } + + before do + create(:namespace_member, user: user, namespace: first_organization.ensure_namespace) + end + + it { is_expected.to contain_exactly(first_organization) } + + context 'when filtered with null user' do + let(:params) { { namespace_member_user: nil } } + + it { is_expected.to be_empty } + end + end + context 'when setting limit' do let(:params) { { limit: 1 } } diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index 92d74fa3..2eea6db4 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -10,6 +10,7 @@ currentUser echo organization + organizations users global_runtimes namespace diff --git a/spec/requests/graphql/query/organizations_query_spec.rb b/spec/requests/graphql/query/organizations_query_spec.rb new file mode 100644 index 00000000..979fc663 --- /dev/null +++ b/spec/requests/graphql/query/organizations_query_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'organization Query' do + include GraphqlHelpers + + subject(:query!) { post_graphql query, current_user: current_user } + + let(:query) do + <<~QUERY + query { + organizations { + nodes { + id + name + } + } + } + QUERY + end + let(:current_user) { nil } + let!(:first_organization) { create(:organization) } + let!(:second_organization) { create(:organization) } + + before do + create(:organization) # organization where the user isn't a member + end + + context 'when anonymous' do + it 'does not return organizations' do + query! + + expect(graphql_data_at(:organizations, :nodes)).to be_empty + end + end + + context 'when logged in' do + let(:current_user) { create(:user) } + + before do + create(:namespace_member, namespace: first_organization.ensure_namespace, user: current_user) + create(:namespace_member, namespace: second_organization.ensure_namespace, user: current_user) + end + + it 'returns organizations where user is member' do + query! + + expect(graphql_data_at(:organizations, :nodes)).to contain_exactly( + a_graphql_entity_for(first_organization), + a_graphql_entity_for(second_organization) + ) + end + end +end