From 7c887970b8bb4855c242e27710ee9c86324761a8 Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Tue, 12 Sep 2023 19:08:21 +0530 Subject: [PATCH 001/131] feat: add invite model, schema, types and operations --- .../0031_organisationmemberinvite.py | 28 +++++++ .../0032_organisationmemberinvite_apps.py | 18 +++++ backend/api/models.py | 14 ++++ .../graphene/mutations/organisation.py | 76 ++++++++++++++----- backend/backend/graphene/types.py | 9 ++- backend/backend/schema.py | 20 ++++- 6 files changed, 143 insertions(+), 22 deletions(-) create mode 100644 backend/api/migrations/0031_organisationmemberinvite.py create mode 100644 backend/api/migrations/0032_organisationmemberinvite_apps.py diff --git a/backend/api/migrations/0031_organisationmemberinvite.py b/backend/api/migrations/0031_organisationmemberinvite.py new file mode 100644 index 00000000..98b901bb --- /dev/null +++ b/backend/api/migrations/0031_organisationmemberinvite.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.3 on 2023-09-12 08:18 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0030_usertoken_expires_at'), + ] + + operations = [ + migrations.CreateModel( + name='OrganisationMemberInvite', + fields=[ + ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('invitee_email', models.EmailField(max_length=254)), + ('valid', models.BooleanField(default=True)), + ('created_at', models.DateTimeField(auto_now_add=True, null=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('expires_at', models.DateTimeField()), + ('invited_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.organisationmember')), + ('organisation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='invites', to='api.organisation')), + ], + ), + ] diff --git a/backend/api/migrations/0032_organisationmemberinvite_apps.py b/backend/api/migrations/0032_organisationmemberinvite_apps.py new file mode 100644 index 00000000..68f7a410 --- /dev/null +++ b/backend/api/migrations/0032_organisationmemberinvite_apps.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.3 on 2023-09-12 13:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0031_organisationmemberinvite'), + ] + + operations = [ + migrations.AddField( + model_name='organisationmemberinvite', + name='apps', + field=models.ManyToManyField(to='api.app'), + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index a6866c10..168d119c 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -152,6 +152,20 @@ def __str__(self): return self.name +class OrganisationMemberInvite(models.Model): + id = models.TextField(default=uuid4, primary_key=True, editable=False) + organisation = models.ForeignKey( + Organisation, related_name='invites', on_delete=models.CASCADE) + apps = models.ManyToManyField(App) + invited_by = models.ForeignKey( + OrganisationMember, on_delete=models.CASCADE) + invitee_email = models.EmailField() + valid = models.BooleanField(default=True) + created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True) + updated_at = models.DateTimeField(auto_now=True) + expires_at = models.DateTimeField() + + class Environment(models.Model): DEVELOPMENT = "dev" diff --git a/backend/backend/graphene/mutations/organisation.py b/backend/backend/graphene/mutations/organisation.py index d2c1465f..07260ea0 100644 --- a/backend/backend/graphene/mutations/organisation.py +++ b/backend/backend/graphene/mutations/organisation.py @@ -1,8 +1,10 @@ from backend.graphene.utils.permissions import user_is_admin import graphene from graphql import GraphQLError -from api.models import Organisation, CustomUser, OrganisationMember -from backend.graphene.types import OrganisationMemberType, OrganisationType +from api.models import App, Organisation, CustomUser, OrganisationMember, OrganisationMemberInvite +from backend.graphene.types import OrganisationMemberInviteType, OrganisationMemberType, OrganisationType +from datetime import datetime, timedelta + class CreateOrganisationMutation(graphene.Mutation): class Arguments: @@ -23,10 +25,47 @@ def mutate(cls, root, info, id, name, identity_key): owner = CustomUser.objects.get(userId=info.context.user.userId) org = Organisation.objects.create( id=id, name=name, identity_key=identity_key) - OrganisationMember.objects.create(user=owner, organisation=org, role=OrganisationMember.OWNER, identity_key=identity_key) + OrganisationMember.objects.create( + user=owner, organisation=org, role=OrganisationMember.OWNER, identity_key=identity_key) return CreateOrganisationMutation(organisation=org) - + + +class InviteOrganisationMemberMutation(graphene.Mutation): + class Arguments: + org_id = graphene.ID(required=True) + email = graphene.String(required=True) + apps = graphene.List(graphene.String) + + invite = graphene.Field(OrganisationMemberInviteType) + + @classmethod + def mutate(cls, root, info, org_id, email, apps): + if user_is_admin(info.context.user, org_id): + user_already_exists = OrganisationMember.objects.filter( + organisation_id=org_id, user__email=email).exists() + if user_already_exists: + raise GraphQLError( + "This user is already a member if your organisation") + + invited_by = OrganisationMember.objects.get( + user=info.context.user, organisation_id=org_id) + + expiry = datetime.now() + timedelta(days=3) + + app_scope = App.objects.filter(id__in=apps) + + invite = OrganisationMemberInvite.objects.create( + organisation_id=org_id, invited_by=invited_by, invitee_email=email, expires_at=expiry) + + invite.apps.set(app_scope) + + return InviteOrganisationMemberMutation(invite=invite) + else: + raise GraphQLError( + "You don't have permission to perform this action") + + class CreateOrganisationMemberMutation(graphene.Mutation): class Arguments: org_id = graphene.ID(required=True) @@ -40,14 +79,17 @@ class Arguments: @classmethod def mutate(cls, root, info, org_id, user_id, role, identity_key, wrapped_keyring): if user_is_admin(info.context.user, org_id): - org = Organisation.objects.get(id=org_id) + org = Organisation.objects.get(id=org_id) + + org_member = OrganisationMember.objects.create( + user_id=user_id, organisation=org, role=role, identity_key=identity_key, wrapped_keyring=wrapped_keyring) + + return CreateOrganisationMemberMutation(org_member=org_member) + else: + raise GraphQLError( + "You don't have permission to perform this action") - org_member = OrganisationMember.objects.create(user_id=user_id, organisation=org, role=role, identity_key=identity_key, wrapped_keyring=wrapped_keyring) - return CreateOrganisationMemberMutation(org_member=org_member) - else: - raise GraphQLError("You don't have permission to perform this action") - class UpdateOrganisationMemberRole(graphene.Mutation): class Arguments: org_id = graphene.ID(required=True) @@ -60,14 +102,14 @@ class Arguments: def mutate(cls, root, info, org_id, user_id, role): if user_is_admin(info.context.user, org_id): if role == OrganisationMember.OWNER: - raise GraphQLError('You cannot set this user as the organisation owner') - org_member = OrganisationMember.objects.get(organisation__id=org_id, user__id=user_id) + raise GraphQLError( + 'You cannot set this user as the organisation owner') + org_member = OrganisationMember.objects.get( + organisation__id=org_id, user__id=user_id) org_member.role = role org_member.save() return UpdateOrganisationMemberRole(org_member=org_member) - else: - raise GraphQLError("You don't have permission to perform this action") - - - \ No newline at end of file + else: + raise GraphQLError( + "You don't have permission to perform this action") diff --git a/backend/backend/graphene/types.py b/backend/backend/graphene/types.py index 7a6f3d12..10631f6e 100644 --- a/backend/backend/graphene/types.py +++ b/backend/backend/graphene/types.py @@ -2,7 +2,7 @@ from enum import Enum from graphene import ObjectType, relay from graphene_django import DjangoObjectType -from api.models import CustomUser, Environment, EnvironmentKey, EnvironmentToken, Organisation, App, OrganisationMember, Secret, SecretEvent, SecretFolder, SecretTag, ServiceToken, UserToken +from api.models import CustomUser, Environment, EnvironmentKey, EnvironmentToken, Organisation, App, OrganisationMember, OrganisationMemberInvite, Secret, SecretEvent, SecretFolder, SecretTag, ServiceToken, UserToken from logs.dynamodb_models import KMSLog @@ -30,6 +30,13 @@ def resolve_username(self, info): return org_member.user.username +class OrganisationMemberInviteType(DjangoObjectType): + class Meta: + model = OrganisationMemberInvite + fields = ('id', 'invited_by', 'invitee_email', 'valid', + 'created_at', 'updated_at', 'expires_at') + + class AppType(DjangoObjectType): class Meta: model = App diff --git a/backend/backend/schema.py b/backend/backend/schema.py index 8aa8a5e3..a23596a5 100644 --- a/backend/backend/schema.py +++ b/backend/backend/schema.py @@ -1,11 +1,11 @@ from .graphene.mutations.environment import CreateEnvironmentKeyMutation, CreateEnvironmentMutation, CreateEnvironmentTokenMutation, CreateSecretFolderMutation, CreateSecretMutation, CreateSecretTagMutation, CreateServiceTokenMutation, CreateUserTokenMutation, DeleteSecretMutation, DeleteServiceTokenMutation, DeleteUserTokenMutation, EditSecretMutation -from .graphene.utils.permissions import user_can_access_app, user_can_access_environment, user_is_org_member +from .graphene.utils.permissions import user_can_access_app, user_can_access_environment, user_is_admin, user_is_org_member from .graphene.mutations.app import CreateAppMutation, DeleteAppMutation, RotateAppKeysMutation -from .graphene.mutations.organisation import CreateOrganisationMutation -from .graphene.types import AppType, ChartDataPointType, EnvironmentKeyType, EnvironmentTokenType, EnvironmentType, KMSLogType, OrganisationMemberType, OrganisationType, SecretEventType, SecretTagType, SecretType, ServiceTokenType, TimeRange, UserTokenType +from .graphene.mutations.organisation import CreateOrganisationMutation, InviteOrganisationMemberMutation +from .graphene.types import AppType, ChartDataPointType, EnvironmentKeyType, EnvironmentTokenType, EnvironmentType, KMSLogType, OrganisationMemberInviteType, OrganisationMemberType, OrganisationType, SecretEventType, SecretTagType, SecretType, ServiceTokenType, TimeRange, UserTokenType import graphene from graphql import GraphQLError -from api.models import Environment, EnvironmentKey, EnvironmentToken, Organisation, App, OrganisationMember, Secret, SecretEvent, SecretTag, ServiceToken, UserToken +from api.models import Environment, EnvironmentKey, EnvironmentToken, Organisation, App, OrganisationMember, OrganisationMemberInvite, Secret, SecretEvent, SecretTag, ServiceToken, UserToken from logs.queries import get_app_log_count, get_app_log_count_range, get_app_logs from datetime import datetime, timedelta from django.conf import settings @@ -21,6 +21,8 @@ class Query(graphene.ObjectType): ), user_id=graphene.ID(), role=graphene.List(graphene.String)) organisation_admins_and_self = graphene.List( OrganisationMemberType, organisation_id=graphene.ID()) + organisation_invites = graphene.List( + OrganisationMemberInviteType, org_id=graphene.ID()) apps = graphene.List( AppType, organisation_id=graphene.ID(), app_id=graphene.ID()) logs = graphene.List(KMSLogType, app_id=graphene.ID(), @@ -72,6 +74,15 @@ def resolve_organisation_admins_and_self(root, info, organisation_id): return members + def resolve_organisation_invites(root, info, org_id): + if not user_is_org_member(info.context.user.userId, org_id): + raise GraphQLError("You don't have access to this organisation") + + invites = OrganisationMemberInvite.objects.filter( + organisation_id=org_id, valid=True) + + return invites + def resolve_apps(root, info, organisation_id, app_id): filter = { 'organisation_id': organisation_id, @@ -266,6 +277,7 @@ def resolve_app_activity_chart(root, info, app_id, period=TimeRange.DAY): class Mutation(graphene.ObjectType): create_organisation = CreateOrganisationMutation.Field() + invite_organisation_member = InviteOrganisationMemberMutation.Field() create_app = CreateAppMutation.Field() rotate_app_keys = RotateAppKeysMutation.Field() delete_app = DeleteAppMutation.Field() From 7cc25e170821564cc2f17a705b06392f13a94d66 Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Tue, 12 Sep 2023 19:09:15 +0530 Subject: [PATCH 002/131] chore: regenerate schema and types --- frontend/apollo/gql.ts | 18 ++++++++--- frontend/apollo/graphql.ts | 55 ++++++++++++++++++++++++++++++++-- frontend/apollo/schema.graphql | 16 ++++++++++ 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/frontend/apollo/gql.ts b/frontend/apollo/gql.ts index 8c02b6f7..377ae59b 100644 --- a/frontend/apollo/gql.ts +++ b/frontend/apollo/gql.ts @@ -26,8 +26,9 @@ const documents = { "mutation RevokeServiceToken($tokenId: ID!) {\n deleteServiceToken(tokenId: $tokenId) {\n ok\n }\n}": types.RevokeServiceTokenDocument, "mutation UpdateSecret($id: ID!, $secretData: SecretInput!) {\n editSecret(id: $id, secretData: $secretData) {\n secret {\n id\n updatedAt\n }\n }\n}": types.UpdateSecretDocument, "mutation InitAppEnvironments($devEnv: EnvironmentInput!, $stagingEnv: EnvironmentInput!, $prodEnv: EnvironmentInput!) {\n devEnvironment: createEnvironment(environmentData: $devEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n stagingEnvironment: createEnvironment(environmentData: $stagingEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n prodEnvironment: createEnvironment(environmentData: $prodEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n}": types.InitAppEnvironmentsDocument, + "mutation InviteMember($orgId: ID!, $email: String!, $apps: [String]) {\n inviteOrganisationMember(orgId: $orgId, email: $email, apps: $apps) {\n invite {\n id\n }\n }\n}": types.InviteMemberDocument, "mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) {\n rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) {\n app {\n id\n }\n }\n}": types.RotateAppKeyDocument, - "mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n ) {\n ok\n }\n}": types.CreateNewUserTokenDocument, + "mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!, $expiry: BigInt) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n expiry: $expiry\n ) {\n ok\n }\n}": types.CreateNewUserTokenDocument, "mutation RevokeUserToken($tokenId: ID!) {\n deleteUserToken(tokenId: $tokenId) {\n ok\n }\n}": types.RevokeUserTokenDocument, "query GetAppActivityChart($appId: ID!, $period: TimeRange) {\n appActivityChart(appId: $appId, period: $period) {\n index\n date\n data\n }\n}": types.GetAppActivityChartDocument, "query GetAppDetail($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n identityKey\n createdAt\n appToken\n appSeed\n appVersion\n }\n}": types.GetAppDetailDocument, @@ -35,6 +36,7 @@ const documents = { "query GetAppLogs($appId: ID!, $start: BigInt, $end: BigInt) {\n logs(appId: $appId, start: $start, end: $end) {\n id\n timestamp\n phaseNode\n eventType\n ipAddress\n country\n city\n phSize\n }\n logsCount(appId: $appId)\n}": types.GetAppLogsDocument, "query GetApps($organisationId: ID!, $appId: ID!) {\n apps(organisationId: $organisationId, appId: $appId) {\n id\n name\n identityKey\n createdAt\n }\n}": types.GetAppsDocument, "query GetOrganisations {\n organisations {\n id\n name\n identityKey\n createdAt\n plan\n }\n}": types.GetOrganisationsDocument, + "query GetInvites($orgId: ID!) {\n organisationInvites(orgId: $orgId) {\n id\n createdAt\n expiresAt\n invitedBy {\n email\n }\n inviteeEmail\n }\n}": types.GetInvitesDocument, "query GetOrganisationAdminsAndSelf($organisationId: ID!) {\n organisationAdminsAndSelf(organisationId: $organisationId) {\n id\n role\n identityKey\n }\n}": types.GetOrganisationAdminsAndSelfDocument, "query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n role\n identityKey\n }\n}": types.GetOrganisationMembersDocument, "query GetAppEnvironments($appId: ID!) {\n appEnvironments(appId: $appId, environmentId: null) {\n id\n name\n envType\n identityKey\n wrappedSeed\n wrappedSalt\n createdAt\n }\n}": types.GetAppEnvironmentsDocument, @@ -44,7 +46,7 @@ const documents = { "query GetSecretTags($orgId: ID!) {\n secretTags(orgId: $orgId) {\n id\n name\n color\n }\n}": types.GetSecretTagsDocument, "query GetSecrets($appId: ID!, $envId: ID!) {\n secrets(envId: $envId) {\n id\n key\n value\n tags {\n id\n name\n color\n }\n comment\n createdAt\n history {\n id\n key\n value\n tags {\n id\n name\n color\n }\n version\n comment\n timestamp\n user {\n email\n username\n }\n eventType\n }\n }\n appEnvironments(appId: $appId, environmentId: $envId) {\n id\n name\n envType\n identityKey\n }\n environmentKeys(environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n}": types.GetSecretsDocument, "query GetServiceTokens($appId: ID!) {\n serviceTokens(appId: $appId) {\n id\n name\n createdAt\n expiresAt\n keys {\n id\n }\n }\n}": types.GetServiceTokensDocument, - "query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n }\n}": types.GetUserTokensDocument, + "query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n expiresAt\n }\n}": types.GetUserTokensDocument, }; /** @@ -113,6 +115,10 @@ export function graphql(source: "mutation UpdateSecret($id: ID!, $secretData: Se * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "mutation InitAppEnvironments($devEnv: EnvironmentInput!, $stagingEnv: EnvironmentInput!, $prodEnv: EnvironmentInput!) {\n devEnvironment: createEnvironment(environmentData: $devEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n stagingEnvironment: createEnvironment(environmentData: $stagingEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n prodEnvironment: createEnvironment(environmentData: $prodEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n}"): (typeof documents)["mutation InitAppEnvironments($devEnv: EnvironmentInput!, $stagingEnv: EnvironmentInput!, $prodEnv: EnvironmentInput!) {\n devEnvironment: createEnvironment(environmentData: $devEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n stagingEnvironment: createEnvironment(environmentData: $stagingEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n prodEnvironment: createEnvironment(environmentData: $prodEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "mutation InviteMember($orgId: ID!, $email: String!, $apps: [String]) {\n inviteOrganisationMember(orgId: $orgId, email: $email, apps: $apps) {\n invite {\n id\n }\n }\n}"): (typeof documents)["mutation InviteMember($orgId: ID!, $email: String!, $apps: [String]) {\n inviteOrganisationMember(orgId: $orgId, email: $email, apps: $apps) {\n invite {\n id\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -120,7 +126,7 @@ export function graphql(source: "mutation RotateAppKey($id: ID!, $appToken: Stri /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n ) {\n ok\n }\n}"): (typeof documents)["mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n ) {\n ok\n }\n}"]; +export function graphql(source: "mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!, $expiry: BigInt) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n expiry: $expiry\n ) {\n ok\n }\n}"): (typeof documents)["mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!, $expiry: BigInt) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n expiry: $expiry\n ) {\n ok\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -149,6 +155,10 @@ export function graphql(source: "query GetApps($organisationId: ID!, $appId: ID! * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query GetOrganisations {\n organisations {\n id\n name\n identityKey\n createdAt\n plan\n }\n}"): (typeof documents)["query GetOrganisations {\n organisations {\n id\n name\n identityKey\n createdAt\n plan\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query GetInvites($orgId: ID!) {\n organisationInvites(orgId: $orgId) {\n id\n createdAt\n expiresAt\n invitedBy {\n email\n }\n inviteeEmail\n }\n}"): (typeof documents)["query GetInvites($orgId: ID!) {\n organisationInvites(orgId: $orgId) {\n id\n createdAt\n expiresAt\n invitedBy {\n email\n }\n inviteeEmail\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -188,7 +198,7 @@ export function graphql(source: "query GetServiceTokens($appId: ID!) {\n servic /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n }\n}"): (typeof documents)["query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n }\n}"]; +export function graphql(source: "query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n expiresAt\n }\n}"): (typeof documents)["query GetUserTokens($organisationId: ID!) {\n userTokens(organisationId: $organisationId) {\n id\n name\n wrappedKeyShare\n createdAt\n expiresAt\n }\n}"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/frontend/apollo/graphql.ts b/frontend/apollo/graphql.ts index 8b10a1aa..97611143 100644 --- a/frontend/apollo/graphql.ts +++ b/frontend/apollo/graphql.ts @@ -213,6 +213,11 @@ export type EnvironmentType = { wrappedSeed: Scalars['String']; }; +export type InviteOrganisationMemberMutation = { + __typename?: 'InviteOrganisationMemberMutation'; + invite?: Maybe; +}; + export type KmsLogType = Node & { __typename?: 'KMSLogType'; appId?: Maybe; @@ -248,6 +253,7 @@ export type Mutation = { deleteServiceToken?: Maybe; deleteUserToken?: Maybe; editSecret?: Maybe; + inviteOrganisationMember?: Maybe; rotateAppKeys?: Maybe; }; @@ -361,6 +367,13 @@ export type MutationEditSecretArgs = { }; +export type MutationInviteOrganisationMemberArgs = { + apps?: InputMaybe>>; + email: Scalars['String']; + orgId: Scalars['ID']; +}; + + export type MutationRotateAppKeysArgs = { appToken: Scalars['String']; id: Scalars['ID']; @@ -373,6 +386,17 @@ export type Node = { id: Scalars['ID']; }; +export type OrganisationMemberInviteType = { + __typename?: 'OrganisationMemberInviteType'; + createdAt?: Maybe; + expiresAt: Scalars['DateTime']; + id: Scalars['String']; + invitedBy: OrganisationMemberType; + inviteeEmail: Scalars['String']; + updatedAt: Scalars['DateTime']; + valid: Scalars['Boolean']; +}; + export type OrganisationMemberType = { __typename?: 'OrganisationMemberType'; createdAt?: Maybe; @@ -404,6 +428,7 @@ export type Query = { logs?: Maybe>>; logsCount?: Maybe; organisationAdminsAndSelf?: Maybe>>; + organisationInvites?: Maybe>>; organisationMembers?: Maybe>>; organisations?: Maybe>>; secretHistory?: Maybe>>; @@ -460,6 +485,11 @@ export type QueryOrganisationAdminsAndSelfArgs = { }; +export type QueryOrganisationInvitesArgs = { + orgId?: InputMaybe; +}; + + export type QueryOrganisationMembersArgs = { organisationId?: InputMaybe; role?: InputMaybe>>; @@ -704,6 +734,15 @@ export type InitAppEnvironmentsMutationVariables = Exact<{ export type InitAppEnvironmentsMutation = { __typename?: 'Mutation', devEnvironment?: { __typename?: 'CreateEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, createdAt?: any | null, identityKey: string } | null } | null, stagingEnvironment?: { __typename?: 'CreateEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, createdAt?: any | null, identityKey: string } | null } | null, prodEnvironment?: { __typename?: 'CreateEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, createdAt?: any | null, identityKey: string } | null } | null }; +export type InviteMemberMutationVariables = Exact<{ + orgId: Scalars['ID']; + email: Scalars['String']; + apps?: InputMaybe> | InputMaybe>; +}>; + + +export type InviteMemberMutation = { __typename?: 'Mutation', inviteOrganisationMember?: { __typename?: 'InviteOrganisationMemberMutation', invite?: { __typename?: 'OrganisationMemberInviteType', id: string } | null } | null }; + export type RotateAppKeyMutationVariables = Exact<{ id: Scalars['ID']; appToken: Scalars['String']; @@ -719,6 +758,7 @@ export type CreateNewUserTokenMutationVariables = Exact<{ identityKey: Scalars['String']; token: Scalars['String']; wrappedKeyShare: Scalars['String']; + expiry?: InputMaybe; }>; @@ -777,6 +817,13 @@ export type GetOrganisationsQueryVariables = Exact<{ [key: string]: never; }>; export type GetOrganisationsQuery = { __typename?: 'Query', organisations?: Array<{ __typename?: 'OrganisationType', id: string, name: string, identityKey: string, createdAt?: any | null, plan: ApiOrganisationPlanChoices } | null> | null }; +export type GetInvitesQueryVariables = Exact<{ + orgId: Scalars['ID']; +}>; + + +export type GetInvitesQuery = { __typename?: 'Query', organisationInvites?: Array<{ __typename?: 'OrganisationMemberInviteType', id: string, createdAt?: any | null, expiresAt: any, inviteeEmail: string, invitedBy: { __typename?: 'OrganisationMemberType', email?: string | null } } | null> | null }; + export type GetOrganisationAdminsAndSelfQueryVariables = Exact<{ organisationId: Scalars['ID']; }>; @@ -847,7 +894,7 @@ export type GetUserTokensQueryVariables = Exact<{ }>; -export type GetUserTokensQuery = { __typename?: 'Query', userTokens?: Array<{ __typename?: 'UserTokenType', id: string, name: string, wrappedKeyShare: string, createdAt?: any | null } | null> | null }; +export type GetUserTokensQuery = { __typename?: 'Query', userTokens?: Array<{ __typename?: 'UserTokenType', id: string, name: string, wrappedKeyShare: string, createdAt?: any | null, expiresAt?: any | null } | null> | null }; export const CreateApplicationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateApplication"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appSeed"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appVersion"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createApp"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"appToken"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}}},{"kind":"Argument","name":{"kind":"Name","value":"appSeed"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appSeed"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}},{"kind":"Argument","name":{"kind":"Name","value":"appVersion"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appVersion"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -863,8 +910,9 @@ export const DeleteSecretOpDocument = {"kind":"Document","definitions":[{"kind": export const RevokeServiceTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeServiceToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteServiceToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"tokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const UpdateSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSecret"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SecretInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"editSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"secretData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secret"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const InitAppEnvironmentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InitAppEnvironments"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"devEnv"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stagingEnv"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"prodEnv"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"devEnvironment"},"name":{"kind":"Name","value":"createEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"devEnv"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"stagingEnvironment"},"name":{"kind":"Name","value":"createEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stagingEnv"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"prodEnvironment"},"name":{"kind":"Name","value":"createEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"prodEnv"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]}}]} as unknown as DocumentNode; +export const InviteMemberDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InviteMember"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"apps"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inviteOrganisationMember"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"Argument","name":{"kind":"Name","value":"apps"},"value":{"kind":"Variable","name":{"kind":"Name","value":"apps"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"invite"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const RotateAppKeyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RotateAppKey"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rotateAppKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"appToken"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const CreateNewUserTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewUserToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createUserToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const CreateNewUserTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewUserToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"expiry"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createUserToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}},{"kind":"Argument","name":{"kind":"Name","value":"expiry"},"value":{"kind":"Variable","name":{"kind":"Name","value":"expiry"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const RevokeUserTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeUserToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteUserToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"tokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const GetAppActivityChartDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppActivityChart"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"period"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TimeRange"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appActivityChart"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"period"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"index"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}}]}}]} as unknown as DocumentNode; export const GetAppDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"appToken"}},{"kind":"Field","name":{"kind":"Name","value":"appSeed"}},{"kind":"Field","name":{"kind":"Name","value":"appVersion"}}]}}]}}]} as unknown as DocumentNode; @@ -872,6 +920,7 @@ export const GetAppLogCountDocument = {"kind":"Document","definitions":[{"kind": export const GetAppLogsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppLogs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"start"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"end"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"start"},"value":{"kind":"Variable","name":{"kind":"Name","value":"start"}}},{"kind":"Argument","name":{"kind":"Name","value":"end"},"value":{"kind":"Variable","name":{"kind":"Name","value":"end"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"phaseNode"}},{"kind":"Field","name":{"kind":"Name","value":"eventType"}},{"kind":"Field","name":{"kind":"Name","value":"ipAddress"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"city"}},{"kind":"Field","name":{"kind":"Name","value":"phSize"}}]}},{"kind":"Field","name":{"kind":"Name","value":"logsCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}]}]}}]} as unknown as DocumentNode; export const GetAppsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetApps"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; export const GetOrganisationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}}]}}]}}]} as unknown as DocumentNode; +export const GetInvitesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetInvites"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationInvites"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inviteeEmail"}}]}}]}}]} as unknown as DocumentNode; export const GetOrganisationAdminsAndSelfDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationAdminsAndSelf"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationAdminsAndSelf"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]} as unknown as DocumentNode; export const GetOrganisationMembersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationMembers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"role"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationMembers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"role"},"value":{"kind":"Variable","name":{"kind":"Name","value":"role"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]} as unknown as DocumentNode; export const GetAppEnvironmentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppEnvironments"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; @@ -881,4 +930,4 @@ export const GetSecretNamesDocument = {"kind":"Document","definitions":[{"kind": export const GetSecretTagsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSecretTags"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secretTags"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]} as unknown as DocumentNode; export const GetSecretsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSecrets"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secrets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"envId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"eventType"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}},{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}}]}}]}}]} as unknown as DocumentNode; export const GetServiceTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetServiceTokens"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serviceTokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"keys"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetUserTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserTokens"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userTokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedKeyShare"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const GetUserTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserTokens"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userTokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedKeyShare"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/apollo/schema.graphql b/frontend/apollo/schema.graphql index 5ab8b83d..9a2f54eb 100644 --- a/frontend/apollo/schema.graphql +++ b/frontend/apollo/schema.graphql @@ -2,6 +2,7 @@ type Query { organisations: [OrganisationType] organisationMembers(organisationId: ID, userId: ID, role: [String]): [OrganisationMemberType] organisationAdminsAndSelf(organisationId: ID): [OrganisationMemberType] + organisationInvites(orgId: ID): [OrganisationMemberInviteType] apps(organisationId: ID, appId: ID): [AppType] logs(appId: ID, start: BigInt, end: BigInt): [KMSLogType] logsCount(appId: ID, thisMonth: Boolean): Int @@ -66,6 +67,16 @@ enum ApiOrganisationMemberRoleChoices { DEV } +type OrganisationMemberInviteType { + id: String! + invitedBy: OrganisationMemberType! + inviteeEmail: String! + valid: Boolean! + createdAt: DateTime + updatedAt: DateTime! + expiresAt: DateTime! +} + type AppType { id: String! name: String! @@ -245,6 +256,7 @@ type ServiceTokenType { type Mutation { createOrganisation(id: ID!, identityKey: String!, name: String!): CreateOrganisationMutation + inviteOrganisationMember(apps: [String], email: String!, orgId: ID!): InviteOrganisationMemberMutation createApp(appSeed: String!, appToken: String!, appVersion: Int!, id: ID!, identityKey: String!, name: String!, organisationId: ID!, wrappedKeyShare: String!): CreateAppMutation rotateAppKeys(appToken: String!, id: ID!, wrappedKeyShare: String!): RotateAppKeysMutation deleteApp(id: ID!): DeleteAppMutation @@ -266,6 +278,10 @@ type CreateOrganisationMutation { organisation: OrganisationType } +type InviteOrganisationMemberMutation { + invite: OrganisationMemberInviteType +} + type CreateAppMutation { app: AppType } From 9d9ee77c1bb8afb8fc8c843de52251397963704f Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Tue, 12 Sep 2023 19:09:25 +0530 Subject: [PATCH 003/131] feat: add invites query and mutation --- .../mutations/organisation/inviteNewMember.gql | 7 +++++++ frontend/graphql/queries/organisation/getInvites.gql | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 frontend/graphql/mutations/organisation/inviteNewMember.gql create mode 100644 frontend/graphql/queries/organisation/getInvites.gql diff --git a/frontend/graphql/mutations/organisation/inviteNewMember.gql b/frontend/graphql/mutations/organisation/inviteNewMember.gql new file mode 100644 index 00000000..d0bdbe07 --- /dev/null +++ b/frontend/graphql/mutations/organisation/inviteNewMember.gql @@ -0,0 +1,7 @@ +mutation InviteMember($orgId: ID!, $email: String!, $apps: [String]) { + inviteOrganisationMember(orgId: $orgId, email: $email, apps: $apps) { + invite { + id + } + } +} diff --git a/frontend/graphql/queries/organisation/getInvites.gql b/frontend/graphql/queries/organisation/getInvites.gql new file mode 100644 index 00000000..46e8b532 --- /dev/null +++ b/frontend/graphql/queries/organisation/getInvites.gql @@ -0,0 +1,11 @@ +query GetInvites($orgId: ID!) { + organisationInvites(orgId: $orgId) { + id + createdAt + expiresAt + invitedBy { + email + } + inviteeEmail + } +} From 61b69836e76b3c072b24e541cbdd6c1577b055cb Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Tue, 12 Sep 2023 19:16:17 +0530 Subject: [PATCH 004/131] feat: add organisation context --- frontend/app/[team]/layout.tsx | 25 +++++++------ frontend/contexts/organisationContext.tsx | 44 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 frontend/contexts/organisationContext.tsx diff --git a/frontend/app/[team]/layout.tsx b/frontend/app/[team]/layout.tsx index 4d73dcc0..018a15df 100644 --- a/frontend/app/[team]/layout.tsx +++ b/frontend/app/[team]/layout.tsx @@ -4,6 +4,7 @@ import '@/app/globals.css' import { HeroPattern } from '@/components/common/HeroPattern' import { NavBar } from '@/components/layout/Navbar' import Sidebar from '@/components/layout/Sidebar' +import { OrganisationProvider } from '@/contexts/organisationContext' import clsx from 'clsx' import { usePathname } from 'next/navigation' @@ -19,16 +20,18 @@ export default function RootLayout({ const showNav = !path?.split('/').includes('newdevice') return ( -
- - {showNav && } - {showNav && } -
{children}
-
+ +
+ + {showNav && } + {showNav && } +
{children}
+
+
) } diff --git a/frontend/contexts/organisationContext.tsx b/frontend/contexts/organisationContext.tsx new file mode 100644 index 00000000..b71bbe00 --- /dev/null +++ b/frontend/contexts/organisationContext.tsx @@ -0,0 +1,44 @@ +import { OrganisationType } from '@/apollo/graphql' +import { createContext, useEffect, useState } from 'react' +import GetOrganisations from '@/graphql/queries/getOrganisations.gql' +import { useQuery } from '@apollo/client' + +interface OrganisationContextValue { + activeOrganisation: OrganisationType | null + organisations: OrganisationType[] + setOrganisation: (organisation: OrganisationType) => void +} + +export const organisationContext = createContext({ + activeOrganisation: null, + organisations: [], + setOrganisation: () => {}, +}) + +interface OrganisationProviderProps { + children: React.ReactNode +} + +export const OrganisationProvider: React.FC = ({ children }) => { + const { data: orgsData } = useQuery(GetOrganisations) + + const [organisation, setOrganisation] = useState(null) + + useEffect(() => { + if (organisation === null && orgsData) { + setOrganisation(orgsData.organisations[0]) + } + }, [organisation, orgsData]) + + return ( + + {children} + + ) +} From 69a4fa1c39470d546b3e57b5000c7384ed42f688 Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Wed, 13 Sep 2023 15:09:12 +0530 Subject: [PATCH 005/131] feat: increase free app limit to 5 --- backend/ee/feature_flags.py | 9 +++++---- frontend/components/apps/NewAppDialog.tsx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/backend/ee/feature_flags.py b/backend/ee/feature_flags.py index df8d3728..c1ea1107 100644 --- a/backend/ee/feature_flags.py +++ b/backend/ee/feature_flags.py @@ -11,13 +11,14 @@ def allow_new_app(organisation): Returns: bool: Whether or not to allow creating an app for the given org """ - FREE_APP_LIMIT = 1 + FREE_APP_LIMIT = 5 PRO_APP_LIMIT = 10 - current_app_count = App.objects.filter(organisation=organisation, is_deleted=False).count() - + current_app_count = App.objects.filter( + organisation=organisation, is_deleted=False).count() + if organisation.plan == Organisation.FREE_PLAN and current_app_count >= FREE_APP_LIMIT: return False elif organisation.plan == Organisation.PRO_PLAN and current_app_count >= PRO_APP_LIMIT: return False - return True \ No newline at end of file + return True diff --git a/frontend/components/apps/NewAppDialog.tsx b/frontend/components/apps/NewAppDialog.tsx index 104e0584..ec70a7e2 100644 --- a/frontend/components/apps/NewAppDialog.tsx +++ b/frontend/components/apps/NewAppDialog.tsx @@ -18,7 +18,7 @@ import { import { splitSecret } from '@/utils/keyshares' import { UpgradeRequestForm } from '../forms/UpgradeRequestForm' -const FREE_APP_LIMIT = 1 +const FREE_APP_LIMIT = 5 const PRO_APP_LIMIT = 10 export default function NewAppDialog(props: { From 7bc5426865e970aec528879d4f494fdb3cc71dd3 Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Thu, 14 Sep 2023 20:18:57 +0530 Subject: [PATCH 006/131] feat: add role to invite model --- .../0033_organisationmemberinvite_role.py | 18 +++++++++++++ backend/api/models.py | 5 ++++ .../graphene/mutations/organisation.py | 25 +++++++++++++++++-- backend/backend/graphene/types.py | 2 +- 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 backend/api/migrations/0033_organisationmemberinvite_role.py diff --git a/backend/api/migrations/0033_organisationmemberinvite_role.py b/backend/api/migrations/0033_organisationmemberinvite_role.py new file mode 100644 index 00000000..31b73a6a --- /dev/null +++ b/backend/api/migrations/0033_organisationmemberinvite_role.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.3 on 2023-09-14 08:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0032_organisationmemberinvite_apps'), + ] + + operations = [ + migrations.AddField( + model_name='organisationmemberinvite', + name='role', + field=models.CharField(choices=[('owner', 'Owner'), ('admin', 'Admin'), ('dev', 'Developer')], default='dev', max_length=5), + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index 168d119c..2ffb8c4c 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -157,6 +157,11 @@ class OrganisationMemberInvite(models.Model): organisation = models.ForeignKey( Organisation, related_name='invites', on_delete=models.CASCADE) apps = models.ManyToManyField(App) + role = models.CharField( + max_length=5, + choices=OrganisationMember.USER_ROLES, + default=OrganisationMember.DEVELOPER, + ) invited_by = models.ForeignKey( OrganisationMember, on_delete=models.CASCADE) invitee_email = models.EmailField() diff --git a/backend/backend/graphene/mutations/organisation.py b/backend/backend/graphene/mutations/organisation.py index 07260ea0..af8ca618 100644 --- a/backend/backend/graphene/mutations/organisation.py +++ b/backend/backend/graphene/mutations/organisation.py @@ -36,11 +36,12 @@ class Arguments: org_id = graphene.ID(required=True) email = graphene.String(required=True) apps = graphene.List(graphene.String) + role = graphene.String() invite = graphene.Field(OrganisationMemberInviteType) @classmethod - def mutate(cls, root, info, org_id, email, apps): + def mutate(cls, root, info, org_id, email, apps, role): if user_is_admin(info.context.user, org_id): user_already_exists = OrganisationMember.objects.filter( organisation_id=org_id, user__email=email).exists() @@ -56,7 +57,7 @@ def mutate(cls, root, info, org_id, email, apps): app_scope = App.objects.filter(id__in=apps) invite = OrganisationMemberInvite.objects.create( - organisation_id=org_id, invited_by=invited_by, invitee_email=email, expires_at=expiry) + organisation_id=org_id, invited_by=invited_by, role=role, invitee_email=email, expires_at=expiry) invite.apps.set(app_scope) @@ -66,6 +67,26 @@ def mutate(cls, root, info, org_id, email, apps): "You don't have permission to perform this action") +class DeleteInviteMutation(graphene.Mutation): + class Arguments: + invite_id = graphene.ID(required=True) + + ok = graphene.Boolean() + + @classmethod + def mutate(cls, rooot, info, invite_id): + invite = OrganisationMemberInvite.objects.get(id=invite_id) + + if user_is_admin(info.context.user, invite.organisation.id): + invite.delete() + + return DeleteInviteMutation(ok=True) + + else: + raise GraphQLError( + "You don't have permission to perform this action") + + class CreateOrganisationMemberMutation(graphene.Mutation): class Arguments: org_id = graphene.ID(required=True) diff --git a/backend/backend/graphene/types.py b/backend/backend/graphene/types.py index 10631f6e..32f877ee 100644 --- a/backend/backend/graphene/types.py +++ b/backend/backend/graphene/types.py @@ -33,7 +33,7 @@ def resolve_username(self, info): class OrganisationMemberInviteType(DjangoObjectType): class Meta: model = OrganisationMemberInvite - fields = ('id', 'invited_by', 'invitee_email', 'valid', + fields = ('id', 'invited_by', 'invitee_email', 'valid', 'organisation', 'apps', 'role', 'created_at', 'updated_at', 'expires_at') From e466a8c9bfd15bf66480e212c7fd9603481e122c Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Thu, 14 Sep 2023 20:19:07 +0530 Subject: [PATCH 007/131] feat: add invite validation query --- backend/backend/schema.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/backend/backend/schema.py b/backend/backend/schema.py index a23596a5..55e981f5 100644 --- a/backend/backend/schema.py +++ b/backend/backend/schema.py @@ -1,7 +1,7 @@ from .graphene.mutations.environment import CreateEnvironmentKeyMutation, CreateEnvironmentMutation, CreateEnvironmentTokenMutation, CreateSecretFolderMutation, CreateSecretMutation, CreateSecretTagMutation, CreateServiceTokenMutation, CreateUserTokenMutation, DeleteSecretMutation, DeleteServiceTokenMutation, DeleteUserTokenMutation, EditSecretMutation from .graphene.utils.permissions import user_can_access_app, user_can_access_environment, user_is_admin, user_is_org_member from .graphene.mutations.app import CreateAppMutation, DeleteAppMutation, RotateAppKeysMutation -from .graphene.mutations.organisation import CreateOrganisationMutation, InviteOrganisationMemberMutation +from .graphene.mutations.organisation import CreateOrganisationMutation, DeleteInviteMutation, InviteOrganisationMemberMutation from .graphene.types import AppType, ChartDataPointType, EnvironmentKeyType, EnvironmentTokenType, EnvironmentType, KMSLogType, OrganisationMemberInviteType, OrganisationMemberType, OrganisationType, SecretEventType, SecretTagType, SecretType, ServiceTokenType, TimeRange, UserTokenType import graphene from graphql import GraphQLError @@ -11,6 +11,7 @@ from django.conf import settings from logs.models import KMSDBLog from itertools import chain +from django.utils import timezone CLOUD_HOSTED = settings.APP_HOST == 'cloud' @@ -23,6 +24,8 @@ class Query(graphene.ObjectType): OrganisationMemberType, organisation_id=graphene.ID()) organisation_invites = graphene.List( OrganisationMemberInviteType, org_id=graphene.ID()) + validate_invite = graphene.Field( + OrganisationMemberInviteType, invite_id=graphene.ID()) apps = graphene.List( AppType, organisation_id=graphene.ID(), app_id=graphene.ID()) logs = graphene.List(KMSLogType, app_id=graphene.ID(), @@ -54,9 +57,15 @@ def resolve_organisation_members(root, info, organisation_id, role, user_id=None if not user_is_org_member(info.context.user.userId, organisation_id): raise GraphQLError("You don't have access to this organisation") - roles = [user_role.lower() for user_role in role] + filter = { + "organisation_id": organisation_id + } + + if role: + roles = [user_role.lower() for user_role in role] + filter["roles__in"] = roles - return OrganisationMember.objects.filter(organisation_id=organisation_id, role__in=roles) + return OrganisationMember.objects.filter(**filter) def resolve_organisation_admins_and_self(root, info, organisation_id): if not user_is_org_member(info.context.user.userId, organisation_id): @@ -83,6 +92,21 @@ def resolve_organisation_invites(root, info, org_id): return invites + def resolve_validate_invite(root, info, invite_id): + try: + invite = OrganisationMemberInvite.objects.get( + id=invite_id, valid=True) + except: + raise GraphQLError("This invite is invalid") + + if invite.expires_at < timezone.now(): + raise GraphQLError("This invite has expired") + + if invite.invitee_email == info.context.user.email: + return invite + else: + raise GraphQLError("This invite is for another user") + def resolve_apps(root, info, organisation_id, app_id): filter = { 'organisation_id': organisation_id, @@ -278,6 +302,7 @@ def resolve_app_activity_chart(root, info, app_id, period=TimeRange.DAY): class Mutation(graphene.ObjectType): create_organisation = CreateOrganisationMutation.Field() invite_organisation_member = InviteOrganisationMemberMutation.Field() + delete_invitation = DeleteInviteMutation.Field() create_app = CreateAppMutation.Field() rotate_app_keys = RotateAppKeysMutation.Field() delete_app = DeleteAppMutation.Field() From d74c9a469c74e79bdc06be6ca78bc7fbde1e08df Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Thu, 14 Sep 2023 20:19:31 +0530 Subject: [PATCH 008/131] chore: regenerate schema and types --- frontend/apollo/gql.ts | 14 ++++++++-- frontend/apollo/graphql.ts | 51 ++++++++++++++++++++++++++++++++-- frontend/apollo/schema.graphql | 23 ++++++++++++++- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/frontend/apollo/gql.ts b/frontend/apollo/gql.ts index 377ae59b..53a2ce6e 100644 --- a/frontend/apollo/gql.ts +++ b/frontend/apollo/gql.ts @@ -26,6 +26,7 @@ const documents = { "mutation RevokeServiceToken($tokenId: ID!) {\n deleteServiceToken(tokenId: $tokenId) {\n ok\n }\n}": types.RevokeServiceTokenDocument, "mutation UpdateSecret($id: ID!, $secretData: SecretInput!) {\n editSecret(id: $id, secretData: $secretData) {\n secret {\n id\n updatedAt\n }\n }\n}": types.UpdateSecretDocument, "mutation InitAppEnvironments($devEnv: EnvironmentInput!, $stagingEnv: EnvironmentInput!, $prodEnv: EnvironmentInput!) {\n devEnvironment: createEnvironment(environmentData: $devEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n stagingEnvironment: createEnvironment(environmentData: $stagingEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n prodEnvironment: createEnvironment(environmentData: $prodEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n}": types.InitAppEnvironmentsDocument, + "mutation DeleteInvite($inviteId: ID!) {\n deleteInvitation(inviteId: $inviteId) {\n ok\n }\n}": types.DeleteInviteDocument, "mutation InviteMember($orgId: ID!, $email: String!, $apps: [String]) {\n inviteOrganisationMember(orgId: $orgId, email: $email, apps: $apps) {\n invite {\n id\n }\n }\n}": types.InviteMemberDocument, "mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) {\n rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) {\n app {\n id\n }\n }\n}": types.RotateAppKeyDocument, "mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!, $expiry: BigInt) {\n createUserToken(\n orgId: $orgId\n name: $name\n identityKey: $identityKey\n token: $token\n wrappedKeyShare: $wrappedKeyShare\n expiry: $expiry\n ) {\n ok\n }\n}": types.CreateNewUserTokenDocument, @@ -38,7 +39,8 @@ const documents = { "query GetOrganisations {\n organisations {\n id\n name\n identityKey\n createdAt\n plan\n }\n}": types.GetOrganisationsDocument, "query GetInvites($orgId: ID!) {\n organisationInvites(orgId: $orgId) {\n id\n createdAt\n expiresAt\n invitedBy {\n email\n }\n inviteeEmail\n }\n}": types.GetInvitesDocument, "query GetOrganisationAdminsAndSelf($organisationId: ID!) {\n organisationAdminsAndSelf(organisationId: $organisationId) {\n id\n role\n identityKey\n }\n}": types.GetOrganisationAdminsAndSelfDocument, - "query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n role\n identityKey\n }\n}": types.GetOrganisationMembersDocument, + "query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n id\n role\n identityKey\n email\n username\n createdAt\n }\n}": types.GetOrganisationMembersDocument, + "query VerifyInvite($inviteId: ID!) {\n validateInvite(inviteId: $inviteId) {\n id\n inviteeEmail\n apps {\n id\n name\n }\n organisation {\n id\n }\n }\n}": types.VerifyInviteDocument, "query GetAppEnvironments($appId: ID!) {\n appEnvironments(appId: $appId, environmentId: null) {\n id\n name\n envType\n identityKey\n wrappedSeed\n wrappedSalt\n createdAt\n }\n}": types.GetAppEnvironmentsDocument, "query GetEnvironmentKey($envId: ID!) {\n environmentKeys(environmentId: $envId) {\n id\n identityKey\n wrappedSeed\n wrappedSalt\n }\n}": types.GetEnvironmentKeyDocument, "query GetEnvironmentTokens($envId: ID!) {\n environmentTokens(environmentId: $envId) {\n id\n name\n wrappedKeyShare\n createdAt\n }\n}": types.GetEnvironmentTokensDocument, @@ -115,6 +117,10 @@ export function graphql(source: "mutation UpdateSecret($id: ID!, $secretData: Se * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "mutation InitAppEnvironments($devEnv: EnvironmentInput!, $stagingEnv: EnvironmentInput!, $prodEnv: EnvironmentInput!) {\n devEnvironment: createEnvironment(environmentData: $devEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n stagingEnvironment: createEnvironment(environmentData: $stagingEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n prodEnvironment: createEnvironment(environmentData: $prodEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n}"): (typeof documents)["mutation InitAppEnvironments($devEnv: EnvironmentInput!, $stagingEnv: EnvironmentInput!, $prodEnv: EnvironmentInput!) {\n devEnvironment: createEnvironment(environmentData: $devEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n stagingEnvironment: createEnvironment(environmentData: $stagingEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n prodEnvironment: createEnvironment(environmentData: $prodEnv) {\n environment {\n id\n name\n createdAt\n identityKey\n }\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "mutation DeleteInvite($inviteId: ID!) {\n deleteInvitation(inviteId: $inviteId) {\n ok\n }\n}"): (typeof documents)["mutation DeleteInvite($inviteId: ID!) {\n deleteInvitation(inviteId: $inviteId) {\n ok\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -166,7 +172,11 @@ export function graphql(source: "query GetOrganisationAdminsAndSelf($organisatio /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n role\n identityKey\n }\n}"): (typeof documents)["query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n role\n identityKey\n }\n}"]; +export function graphql(source: "query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n id\n role\n identityKey\n email\n username\n createdAt\n }\n}"): (typeof documents)["query GetOrganisationMembers($organisationId: ID!, $role: [String]) {\n organisationMembers(organisationId: $organisationId, role: $role) {\n id\n role\n identityKey\n email\n username\n createdAt\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query VerifyInvite($inviteId: ID!) {\n validateInvite(inviteId: $inviteId) {\n id\n inviteeEmail\n apps {\n id\n name\n }\n organisation {\n id\n }\n }\n}"): (typeof documents)["query VerifyInvite($inviteId: ID!) {\n validateInvite(inviteId: $inviteId) {\n id\n inviteeEmail\n apps {\n id\n name\n }\n organisation {\n id\n }\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/frontend/apollo/graphql.ts b/frontend/apollo/graphql.ts index 97611143..ffa9914d 100644 --- a/frontend/apollo/graphql.ts +++ b/frontend/apollo/graphql.ts @@ -36,6 +36,16 @@ export enum ApiEnvironmentEnvTypeChoices { Staging = 'STAGING' } +/** An enumeration. */ +export enum ApiOrganisationMemberInviteRoleChoices { + /** Admin */ + Admin = 'ADMIN', + /** Developer */ + Dev = 'DEV', + /** Owner */ + Owner = 'OWNER' +} + /** An enumeration. */ export enum ApiOrganisationMemberRoleChoices { /** Admin */ @@ -143,6 +153,11 @@ export type DeleteAppMutation = { app?: Maybe; }; +export type DeleteInviteMutation = { + __typename?: 'DeleteInviteMutation'; + ok?: Maybe; +}; + export type DeleteSecretMutation = { __typename?: 'DeleteSecretMutation'; secret?: Maybe; @@ -249,6 +264,7 @@ export type Mutation = { createServiceToken?: Maybe; createUserToken?: Maybe; deleteApp?: Maybe; + deleteInvitation?: Maybe; deleteSecret?: Maybe; deleteServiceToken?: Maybe; deleteUserToken?: Maybe; @@ -346,6 +362,11 @@ export type MutationDeleteAppArgs = { }; +export type MutationDeleteInvitationArgs = { + inviteId: Scalars['ID']; +}; + + export type MutationDeleteSecretArgs = { id: Scalars['ID']; }; @@ -371,6 +392,7 @@ export type MutationInviteOrganisationMemberArgs = { apps?: InputMaybe>>; email: Scalars['String']; orgId: Scalars['ID']; + role?: InputMaybe; }; @@ -388,11 +410,14 @@ export type Node = { export type OrganisationMemberInviteType = { __typename?: 'OrganisationMemberInviteType'; + apps: Array; createdAt?: Maybe; expiresAt: Scalars['DateTime']; id: Scalars['String']; invitedBy: OrganisationMemberType; inviteeEmail: Scalars['String']; + organisation: OrganisationType; + role: ApiOrganisationMemberInviteRoleChoices; updatedAt: Scalars['DateTime']; valid: Scalars['Boolean']; }; @@ -436,6 +461,7 @@ export type Query = { secrets?: Maybe>>; serviceTokens?: Maybe>>; userTokens?: Maybe>>; + validateInvite?: Maybe; }; @@ -521,6 +547,11 @@ export type QueryUserTokensArgs = { organisationId?: InputMaybe; }; + +export type QueryValidateInviteArgs = { + inviteId?: InputMaybe; +}; + export type RotateAppKeysMutation = { __typename?: 'RotateAppKeysMutation'; app?: Maybe; @@ -734,6 +765,13 @@ export type InitAppEnvironmentsMutationVariables = Exact<{ export type InitAppEnvironmentsMutation = { __typename?: 'Mutation', devEnvironment?: { __typename?: 'CreateEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, createdAt?: any | null, identityKey: string } | null } | null, stagingEnvironment?: { __typename?: 'CreateEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, createdAt?: any | null, identityKey: string } | null } | null, prodEnvironment?: { __typename?: 'CreateEnvironmentMutation', environment?: { __typename?: 'EnvironmentType', id: string, name: string, createdAt?: any | null, identityKey: string } | null } | null }; +export type DeleteInviteMutationVariables = Exact<{ + inviteId: Scalars['ID']; +}>; + + +export type DeleteInviteMutation = { __typename?: 'Mutation', deleteInvitation?: { __typename?: 'DeleteInviteMutation', ok?: boolean | null } | null }; + export type InviteMemberMutationVariables = Exact<{ orgId: Scalars['ID']; email: Scalars['String']; @@ -837,7 +875,14 @@ export type GetOrganisationMembersQueryVariables = Exact<{ }>; -export type GetOrganisationMembersQuery = { __typename?: 'Query', organisationMembers?: Array<{ __typename?: 'OrganisationMemberType', role: ApiOrganisationMemberRoleChoices, identityKey?: string | null } | null> | null }; +export type GetOrganisationMembersQuery = { __typename?: 'Query', organisationMembers?: Array<{ __typename?: 'OrganisationMemberType', id: string, role: ApiOrganisationMemberRoleChoices, identityKey?: string | null, email?: string | null, username?: string | null, createdAt?: any | null } | null> | null }; + +export type VerifyInviteQueryVariables = Exact<{ + inviteId: Scalars['ID']; +}>; + + +export type VerifyInviteQuery = { __typename?: 'Query', validateInvite?: { __typename?: 'OrganisationMemberInviteType', id: string, inviteeEmail: string, apps: Array<{ __typename?: 'AppType', id: string, name: string }>, organisation: { __typename?: 'OrganisationType', id: string } } | null }; export type GetAppEnvironmentsQueryVariables = Exact<{ appId: Scalars['ID']; @@ -910,6 +955,7 @@ export const DeleteSecretOpDocument = {"kind":"Document","definitions":[{"kind": export const RevokeServiceTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeServiceToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteServiceToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"tokenId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tokenId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const UpdateSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSecret"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"secretData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SecretInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"editSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"secretData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"secretData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"secret"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]}}]} as unknown as DocumentNode; export const InitAppEnvironmentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InitAppEnvironments"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"devEnv"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stagingEnv"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"prodEnv"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EnvironmentInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"devEnvironment"},"name":{"kind":"Name","value":"createEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"devEnv"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"stagingEnvironment"},"name":{"kind":"Name","value":"createEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stagingEnv"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"prodEnvironment"},"name":{"kind":"Name","value":"createEnvironment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentData"},"value":{"kind":"Variable","name":{"kind":"Name","value":"prodEnv"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DeleteInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteInvite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteInvitation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"inviteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const InviteMemberDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InviteMember"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"apps"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inviteOrganisationMember"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"Argument","name":{"kind":"Name","value":"apps"},"value":{"kind":"Variable","name":{"kind":"Name","value":"apps"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"invite"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const RotateAppKeyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RotateAppKey"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rotateAppKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"appToken"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appToken"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNewUserTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNewUserToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"expiry"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createUserToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"identityKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identityKey"}}},{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}},{"kind":"Argument","name":{"kind":"Name","value":"wrappedKeyShare"},"value":{"kind":"Variable","name":{"kind":"Name","value":"wrappedKeyShare"}}},{"kind":"Argument","name":{"kind":"Name","value":"expiry"},"value":{"kind":"Variable","name":{"kind":"Name","value":"expiry"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; @@ -922,7 +968,8 @@ export const GetAppsDocument = {"kind":"Document","definitions":[{"kind":"Operat export const GetOrganisationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}}]}}]}}]} as unknown as DocumentNode; export const GetInvitesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetInvites"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationInvites"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orgId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orgId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inviteeEmail"}}]}}]}}]} as unknown as DocumentNode; export const GetOrganisationAdminsAndSelfDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationAdminsAndSelf"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationAdminsAndSelf"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]} as unknown as DocumentNode; -export const GetOrganisationMembersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationMembers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"role"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationMembers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"role"},"value":{"kind":"Variable","name":{"kind":"Name","value":"role"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}}]}}]}}]} as unknown as DocumentNode; +export const GetOrganisationMembersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOrganisationMembers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"role"}},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organisationMembers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"organisationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organisationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"role"},"value":{"kind":"Variable","name":{"kind":"Name","value":"role"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; +export const VerifyInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"VerifyInvite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"validateInvite"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"inviteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"inviteId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"inviteeEmail"}},{"kind":"Field","name":{"kind":"Name","value":"apps"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"organisation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetAppEnvironmentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAppEnvironments"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"appId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"appEnvironments"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"appId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"appId"}}},{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"envType"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; export const GetEnvironmentKeyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetEnvironmentKey"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environmentKeys"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"identityKey"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSeed"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedSalt"}}]}}]}}]} as unknown as DocumentNode; export const GetEnvironmentTokensDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetEnvironmentTokens"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"envId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"environmentTokens"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"environmentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"envId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"wrappedKeyShare"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; diff --git a/frontend/apollo/schema.graphql b/frontend/apollo/schema.graphql index 9a2f54eb..f408f470 100644 --- a/frontend/apollo/schema.graphql +++ b/frontend/apollo/schema.graphql @@ -3,6 +3,7 @@ type Query { organisationMembers(organisationId: ID, userId: ID, role: [String]): [OrganisationMemberType] organisationAdminsAndSelf(organisationId: ID): [OrganisationMemberType] organisationInvites(orgId: ID): [OrganisationMemberInviteType] + validateInvite(inviteId: ID): OrganisationMemberInviteType apps(organisationId: ID, appId: ID): [AppType] logs(appId: ID, start: BigInt, end: BigInt): [KMSLogType] logsCount(appId: ID, thisMonth: Boolean): Int @@ -69,6 +70,9 @@ enum ApiOrganisationMemberRoleChoices { type OrganisationMemberInviteType { id: String! + organisation: OrganisationType! + apps: [AppType!]! + role: ApiOrganisationMemberInviteRoleChoices! invitedBy: OrganisationMemberType! inviteeEmail: String! valid: Boolean! @@ -88,6 +92,18 @@ type AppType { createdAt: DateTime } +"""An enumeration.""" +enum ApiOrganisationMemberInviteRoleChoices { + """Owner""" + OWNER + + """Admin""" + ADMIN + + """Developer""" + DEV +} + type KMSLogType implements Node { id: ID! timestamp: BigInt @@ -256,7 +272,8 @@ type ServiceTokenType { type Mutation { createOrganisation(id: ID!, identityKey: String!, name: String!): CreateOrganisationMutation - inviteOrganisationMember(apps: [String], email: String!, orgId: ID!): InviteOrganisationMemberMutation + inviteOrganisationMember(apps: [String], email: String!, orgId: ID!, role: String): InviteOrganisationMemberMutation + deleteInvitation(inviteId: ID!): DeleteInviteMutation createApp(appSeed: String!, appToken: String!, appVersion: Int!, id: ID!, identityKey: String!, name: String!, organisationId: ID!, wrappedKeyShare: String!): CreateAppMutation rotateAppKeys(appToken: String!, id: ID!, wrappedKeyShare: String!): RotateAppKeysMutation deleteApp(id: ID!): DeleteAppMutation @@ -282,6 +299,10 @@ type InviteOrganisationMemberMutation { invite: OrganisationMemberInviteType } +type DeleteInviteMutation { + ok: Boolean +} + type CreateAppMutation { app: AppType } From 2537295751b46e165142df085b27494c9e486462 Mon Sep 17 00:00:00 2001 From: rohan-chaturvedi Date: Thu, 14 Sep 2023 20:21:22 +0530 Subject: [PATCH 009/131] feat: members page --- frontend/app/[team]/members/page.tsx | 525 ++++++++++++++++++ frontend/components/layout/Sidebar.tsx | 20 +- .../mutations/organisation/deleteInvite.gql | 5 + .../organisation/inviteNewMember.gql | 4 +- .../organisation/getOrganisationMembers.gql | 4 + frontend/utils/auth.ts | 19 +- 6 files changed, 564 insertions(+), 13 deletions(-) create mode 100644 frontend/app/[team]/members/page.tsx create mode 100644 frontend/graphql/mutations/organisation/deleteInvite.gql diff --git a/frontend/app/[team]/members/page.tsx b/frontend/app/[team]/members/page.tsx new file mode 100644 index 00000000..72371341 --- /dev/null +++ b/frontend/app/[team]/members/page.tsx @@ -0,0 +1,525 @@ +'use client' + +import GetOrganisationMembers from '@/graphql/queries/organisation/getOrganisationMembers.gql' +import GetInvites from '@/graphql/queries/organisation/getInvites.gql' +import GetApps from '@/graphql/queries/getApps.gql' +import InviteMember from '@/graphql/mutations/organisation/inviteNewMember.gql' +import DeleteInvite from '@/graphql/mutations/organisation/deleteInvite.gql' +import { useLazyQuery, useMutation, useQuery } from '@apollo/client' +import { Fragment, useContext, useEffect, useState } from 'react' +import { + OrganisationMemberInviteType, + OrganisationMemberType, + AppType, + ApiOrganisationMemberRoleChoices, +} from '@/apollo/graphql' +import { Button } from '@/components/common/Button' +import { organisationContext } from '@/contexts/organisationContext' +import { relativeTimeFromDates } from '@/utils/time' +import { Dialog, Disclosure, RadioGroup, Transition } from '@headlessui/react' +import { + FaCheckSquare, + FaChevronDown, + FaCircle, + FaCopy, + FaDotCircle, + FaPlus, + FaSquare, + FaTimes, + FaTrashAlt, +} from 'react-icons/fa' +import clsx from 'clsx' +import { cryptoUtils } from '@/utils/auth' +import { copyToClipBoard } from '@/utils/clipboard' +import { toast } from 'react-toastify' + +const handleCopy = (val: string) => { + copyToClipBoard(val) + toast.info('Copied', { autoClose: 2000 }) +} + +const InviteDialog = (props: { organisationId: string }) => { + const { organisationId } = props + + const { data: invitesData, loading: invitesLoading } = useQuery(GetInvites, { + variables: { orgId: organisationId }, + }) + const { data: appsData, loading: appsLoading } = useQuery(GetApps, { + variables: { organisationId, appId: '' }, + }) + const [createInvite, { data }] = useMutation(InviteMember) + const [deleteInvite] = useMutation(DeleteInvite) + + const [isOpen, setIsOpen] = useState(false) + + const [email, setEmail] = useState('') + const [role, setRole] = useState('Dev') + const [apps, setApps] = useState[]>([]) + + const [inviteLink, setInviteLink] = useState('') + + const roleOptions = Object.keys(ApiOrganisationMemberRoleChoices).filter( + (option) => option !== 'Owner' + ) + + const isLoading = invitesLoading || appsLoading + + const reset = () => { + setEmail('') + setRole('Dev') + setApps([]) + setInviteLink('') + } + + const closeModal = () => { + reset() + setIsOpen(false) + } + + const openModal = () => { + setIsOpen(true) + } + + const handleClose = () => { + closeModal() + } + + const handleInvite = async (event: { preventDefault: () => void }) => { + event.preventDefault() + await createInvite({ + variables: { + email, + orgId: organisationId, + apps: apps.map((app) => app.id), + role, + }, + refetchQueries: [ + { + query: GetInvites, + variables: { + orgId: organisationId, + }, + }, + ], + }) + + setInviteLink(cryptoUtils.getInviteLink(data?.inviteOrganisationMember.invite.id)) + } + + const handleDeleteInvite = async (inviteId: string) => { + await deleteInvite({ + variables: { + inviteId, + }, + refetchQueries: [ + { + query: GetInvites, + variables: { + orgId: organisationId, + }, + }, + ], + }) + } + + const AppSelector = (props: { app: AppType }) => { + const { id: appId, name: appName } = props.app + + const isSelected = apps.map((app) => app.name).includes(appName) + + const handleAppClick = () => { + if (isSelected) { + setApps(apps.filter((app) => app.name !== appName)) + } else setApps([...apps, ...[{ id: appId, name: appName }]]) + } + + return ( +
+ {isSelected ? ( + + ) : ( + + )} +
+ {appName} +
+
+ ) + } + + const sortedInvites: OrganisationMemberInviteType[] = + invitesData?.organisationInvites + ?.slice() // Create a shallow copy of the array to avoid modifying the original + .sort((a: OrganisationMemberInviteType, b: OrganisationMemberInviteType) => { + // Compare the createdAt timestamps in descending order + return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + }) || [] + + const DeleteInviteConfirmDialog = (props: { inviteId: string }) => { + const { inviteId } = props + + const [isOpen, setIsOpen] = useState(false) + + const closeModal = () => { + setIsOpen(false) + } + + const openModal = () => { + setIsOpen(true) + } + + return ( + <> +
+ +
+ + + + +
+ + +
+
+ + + +

+ Delete Invite +

+ + +
+ +
+

+ Are you sure you want to delete this invite? +

+
+ + +
+
+
+
+
+
+
+
+ + ) + } + + return ( + <> +
+ +
+ + + + +
+ + +
+
+ + + +

+ Invite a new member +

+ + +
+ + {!isLoading && ( +
+
+ {!inviteLink && ( +
+
+
+ + setEmail(e.target.value)} + /> +
+
+ + + + +
+ {roleOptions.map((option) => ( + + {({ active, checked }) => ( +
+ {checked ? ( + + ) : ( + + )} + {option} +
+ )} +
+ ))} +
+
+
+
+ +
+ + {appsData.apps.map((appOption: AppType) => ( + + ))} +
+ +
+ + +
+
+ )} + {inviteLink && ( +
+
+

Invite sent

+

+ An invite link has been sent by email to {email}. You can also share + the link below to invite the user to your organisation. +

+
+
+
+ {inviteLink} +
+ +
+
+ )} +
+ +
+ + {({ open }) => ( + <> + +
+ + Invite history +
+
+ + +
+ + + + + + + + + + + + {sortedInvites.map( + (invite: OrganisationMemberInviteType) => ( + + + + + + + + ) + )} + +
+ Email + + Invited by + + Invited + + Expires +
+ {invite.inviteeEmail} + + {invite.invitedBy.email} + + {relativeTimeFromDates(new Date(invite.createdAt))} + + {relativeTimeFromDates(new Date(invite.expiresAt))} + + +
+
+
+
+ + )} +
+
+
+ )} +
+
+
+
+
+
+ + ) +} + +export default function Members({ params }: { params: { team: string } }) { + const [getMembers, { data: membersData }] = useLazyQuery(GetOrganisationMembers) + + const { activeOrganisation: organisation } = useContext(organisationContext) + + useEffect(() => { + if (organisation) { + getMembers({ + variables: { + organisationId: organisation.id, + role: null, + }, + }) + } + }, [organisation]) + + return ( +
+

{params.team} Members

+ +
+
+ {organisation && } +
+ + + + + + + + + + + + {membersData?.organisationMembers.map((member: OrganisationMemberType) => ( + + + + + + + ))} + +
+ Email + + Username + + Role + + Joined +
{member.email}{member.username}{member.role} + {relativeTimeFromDates(new Date(member.createdAt))} +
+
+
+ ) +} diff --git a/frontend/components/layout/Sidebar.tsx b/frontend/components/layout/Sidebar.tsx index 749dd5b3..a4b12779 100644 --- a/frontend/components/layout/Sidebar.tsx +++ b/frontend/components/layout/Sidebar.tsx @@ -4,7 +4,7 @@ import Link from 'next/link' import UserMenu from '../UserMenu' import { usePathname } from 'next/navigation' import clsx from 'clsx' -import { FaCog, FaCubes, FaHome } from 'react-icons/fa' +import { FaCog, FaCubes, FaHome, FaUsersCog } from 'react-icons/fa' export type SidebarLinkT = { name: string @@ -47,6 +47,12 @@ const Sidebar = () => { icon: , active: usePathname() === `/${team}/apps`, }, + { + name: 'Members', + href: `/${team}/members`, + icon: , + active: usePathname() === `/${team}/apps`, + }, { name: 'Settings', href: `/${team}/settings`, @@ -58,7 +64,7 @@ const Sidebar = () => { return (