From b6799cbb017d089204fa88c3106f4db436016171 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Sun, 4 Jan 2026 16:25:44 +0100 Subject: [PATCH] Add membership source Signed-off-by: Bryan Frimin --- ...MemberListFragment_RefetchQuery.graphql.ts | 13 ++- .../iam/MemberListItemFragment.graphql.ts | 13 ++- .../iam/MembersPageQuery.graphql.ts | 13 ++- .../settings/_components/MemberListItem.tsx | 12 ++- pkg/coredata/membership.go | 31 +++++-- pkg/coredata/membership_source.go | 57 +++++++++++++ pkg/coredata/migrations/20260104T151807Z.sql | 2 + pkg/iam/account_service.go | 1 + pkg/iam/organization_service.go | 1 + pkg/iam/saml/service.go | 1 + pkg/server/api/connect/v1/schema.graphql | 8 ++ pkg/server/api/connect/v1/schema/schema.go | 85 +++++++++++++++++++ pkg/server/api/connect/v1/types/membership.go | 7 +- pkg/server/api/connect/v1/types/types.go | 17 ++-- 14 files changed, 225 insertions(+), 36 deletions(-) create mode 100644 pkg/coredata/membership_source.go create mode 100644 pkg/coredata/migrations/20260104T151807Z.sql diff --git a/apps/console/src/__generated__/iam/MemberListFragment_RefetchQuery.graphql.ts b/apps/console/src/__generated__/iam/MemberListFragment_RefetchQuery.graphql.ts index 3e64cb659..186d3b6e1 100644 --- a/apps/console/src/__generated__/iam/MemberListFragment_RefetchQuery.graphql.ts +++ b/apps/console/src/__generated__/iam/MemberListFragment_RefetchQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<1a9ee1bf35493db9d5edbbd07f917ff5>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -229,6 +229,13 @@ return { "name": "role", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null + }, { "alias": null, "args": null, @@ -389,12 +396,12 @@ return { ] }, "params": { - "cacheID": "7d90790bce5773e286196cec19c376c9", + "cacheID": "bdedd349fa3a3dec43d7cb6171d1cc6d", "id": null, "metadata": {}, "name": "MemberListFragment_RefetchQuery", "operationKind": "query", - "text": "query MemberListFragment_RefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: MembershipOrder = {direction: ASC, field: CREATED_AT}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MemberListFragment_16fISc\n id\n }\n}\n\nfragment MemberListFragment_16fISc on Organization {\n members(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n" + "text": "query MemberListFragment_RefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: MembershipOrder = {direction: ASC, field: CREATED_AT}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MemberListFragment_16fISc\n id\n }\n}\n\nfragment MemberListFragment_16fISc on Organization {\n members(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n source\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n" } }; })(); diff --git a/apps/console/src/__generated__/iam/MemberListItemFragment.graphql.ts b/apps/console/src/__generated__/iam/MemberListItemFragment.graphql.ts index 52735956a..fd4112573 100644 --- a/apps/console/src/__generated__/iam/MemberListItemFragment.graphql.ts +++ b/apps/console/src/__generated__/iam/MemberListItemFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<8ffe3696f618050456f80b7a7098a882>> * @lightSyntaxTransform * @nogrep */ @@ -10,6 +10,7 @@ import { ReaderFragment } from 'relay-runtime'; export type MembershipRole = "ADMIN" | "AUDITOR" | "EMPLOYEE" | "OWNER" | "VIEWER"; +export type MembershipSource = "MANUAL" | "SAML"; import { FragmentRefs } from "relay-runtime"; export type MemberListItemFragment$data = { readonly canDelete: boolean; @@ -23,6 +24,7 @@ export type MemberListItemFragment$data = { readonly fullName: string; }; readonly role: MembershipRole; + readonly source: MembershipSource; readonly " $fragmentType": "MemberListItemFragment"; }; export type MemberListItemFragment$key = { @@ -50,6 +52,13 @@ const node: ReaderFragment = { "name": "role", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null + }, { "kind": "RequiredField", "field": { @@ -132,6 +141,6 @@ const node: ReaderFragment = { "abstractKey": null }; -(node as any).hash = "a7adb3da099816d296abd56c0b8dde16"; +(node as any).hash = "573655b969ddacac10dc8beb4585a4a1"; export default node; diff --git a/apps/console/src/__generated__/iam/MembersPageQuery.graphql.ts b/apps/console/src/__generated__/iam/MembersPageQuery.graphql.ts index 4289fad88..4f01330b3 100644 --- a/apps/console/src/__generated__/iam/MembersPageQuery.graphql.ts +++ b/apps/console/src/__generated__/iam/MembersPageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3ba2ace33d45535d6c6981f283be9643>> + * @generated SignedSource<<0f7c89bd92b5743593efd542812568a7>> * @lightSyntaxTransform * @nogrep */ @@ -335,6 +335,13 @@ return { "selections": [ (v10/*: any*/), (v11/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null + }, { "alias": null, "args": null, @@ -509,12 +516,12 @@ return { ] }, "params": { - "cacheID": "a5ff95870e5a269d1b03a123a459678e", + "cacheID": "b7d449bd737c6165219640affcc0260a", "id": null, "metadata": {}, "name": "MembersPageQuery", "operationKind": "query", - "text": "query MembersPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...InviteUserDialog_currentRoleFragment\n ...MemberListFragment_1jRT0c\n members(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n }\n ...InvitationListFragment_1jRT0c\n invitations(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n }\n canInviteUser: permission(action: \"iam:invitation:create\")\n }\n id\n }\n}\n\nfragment InvitationListFragment_1jRT0c on Organization {\n invitations(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n ...InvitationListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment InvitationListItemFragment on Invitation {\n id\n fullName\n email\n role\n status\n createdAt\n expiresAt\n acceptedAt\n canDelete: permission(action: \"iam:invitation:delete\")\n}\n\nfragment InviteUserDialog_currentRoleFragment on Organization {\n viewerMembership {\n role\n id\n }\n}\n\nfragment MemberListFragment_1jRT0c on Organization {\n members(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n" + "text": "query MembersPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...InviteUserDialog_currentRoleFragment\n ...MemberListFragment_1jRT0c\n members(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n }\n ...InvitationListFragment_1jRT0c\n invitations(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n }\n canInviteUser: permission(action: \"iam:invitation:create\")\n }\n id\n }\n}\n\nfragment InvitationListFragment_1jRT0c on Organization {\n invitations(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n ...InvitationListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment InvitationListItemFragment on Invitation {\n id\n fullName\n email\n role\n status\n createdAt\n expiresAt\n acceptedAt\n canDelete: permission(action: \"iam:invitation:delete\")\n}\n\nfragment InviteUserDialog_currentRoleFragment on Organization {\n viewerMembership {\n role\n id\n }\n}\n\nfragment MemberListFragment_1jRT0c on Organization {\n members(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n source\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n" } }; })(); diff --git a/apps/console/src/pages/iam/organizations/settings/_components/MemberListItem.tsx b/apps/console/src/pages/iam/organizations/settings/_components/MemberListItem.tsx index 6585e9e98..70eadded8 100644 --- a/apps/console/src/pages/iam/organizations/settings/_components/MemberListItem.tsx +++ b/apps/console/src/pages/iam/organizations/settings/_components/MemberListItem.tsx @@ -24,6 +24,7 @@ const fragment = graphql` fragment MemberListItemFragment on Membership { id role + source profile @required(action: THROW) { fullName } @@ -70,7 +71,7 @@ export function MemberListItem(props: { { successMessage: __("Member removed successfully"), errorMessage: __("Failed to remove member"), - }, + } ); const handleRemove = async () => { @@ -89,9 +90,9 @@ export function MemberListItem(props: { { message: sprintf( __("Are you sure you want to remove %s?"), - membership.profile.fullName, + membership.profile.fullName ), - }, + } ); }; @@ -104,10 +105,7 @@ export function MemberListItem(props: {
{membership.identity.email} - {/* FIXME: put back */} - {/* {membership.authMethod === "SAML" && ( - SAML - )} */} + {membership.source}
diff --git a/pkg/coredata/membership.go b/pkg/coredata/membership.go index d4ccecb0e..4a9ba6b41 100644 --- a/pkg/coredata/membership.go +++ b/pkg/coredata/membership.go @@ -31,14 +31,15 @@ import ( type ( Membership struct { - ID gid.GID `db:"id"` - IdentityID gid.GID `db:"identity_id"` - OrganizationID gid.GID `db:"organization_id"` - Role MembershipRole `db:"role"` - FullName string `db:"full_name"` - EmailAddress mail.Addr `db:"email_address"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID gid.GID `db:"id"` + IdentityID gid.GID `db:"identity_id"` + OrganizationID gid.GID `db:"organization_id"` + Role MembershipRole `db:"role"` + Source MembershipSource `db:"source"` + FullName string `db:"full_name"` + EmailAddress mail.Addr `db:"email_address"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } Memberships []*Membership @@ -67,6 +68,7 @@ WITH mbr AS ( identity_id, organization_id, role, + source, created_at, updated_at FROM @@ -80,6 +82,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, + mbr.source, COALESCE(mp.full_name, i.full_name, '') as full_name, i.email_address, mbr.created_at, @@ -122,6 +125,7 @@ INSERT INTO identity_id, organization_id, role, + source, created_at, updated_at ) @@ -131,6 +135,7 @@ VALUES ( @identity_id, @organization_id, @role, + @source, @created_at, @updated_at ); @@ -142,6 +147,7 @@ VALUES ( "identity_id": m.IdentityID, "organization_id": m.OrganizationID, "role": m.Role, + "source": m.Source, "created_at": m.CreatedAt, "updated_at": m.UpdatedAt, } @@ -176,6 +182,7 @@ WITH mbr AS ( identity_id, organization_id, role, + source, created_at, updated_at FROM @@ -189,6 +196,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, + mbr.source, COALESCE(mp.full_name, i.full_name, '') as full_name, i.email_address, mbr.created_at, @@ -325,6 +333,7 @@ WITH mbr AS ( am.identity_id, am.organization_id, am.role, + am.source, am.created_at, am.updated_at FROM @@ -339,6 +348,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, + mbr.source, COALESCE(mp.full_name, i.full_name, '') as full_name, i.email_address, mbr.created_at, @@ -452,6 +462,7 @@ WITH mbr AS ( identity_id, organization_id, role, + source, created_at, updated_at FROM @@ -467,6 +478,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, + mbr.source, COALESCE(mp.full_name, i.full_name, '') as full_name, i.email_address, mbr.created_at, @@ -517,6 +529,7 @@ WITH membership_with_profile AS ( m.identity_id, m.organization_id, m.role, + m.source, COALESCE(mp.full_name, i.full_name, '') AS full_name, i.email_address, m.created_at, @@ -536,6 +549,7 @@ SELECT identity_id, organization_id, role, + source, full_name, email_address, created_at, @@ -633,6 +647,7 @@ SELECT identity_id, organization_id, role, + source, '' as full_name, NULL as email_address, created_at, diff --git a/pkg/coredata/membership_source.go b/pkg/coredata/membership_source.go new file mode 100644 index 000000000..52bd39ea8 --- /dev/null +++ b/pkg/coredata/membership_source.go @@ -0,0 +1,57 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package coredata + +import ( + "database/sql/driver" + "fmt" +) + +type MembershipSource string + +const ( + MembershipSourceManual MembershipSource = "MANUAL" + MembershipSourceSAML MembershipSource = "SAML" +) + +func (s MembershipSource) String() string { + return string(s) +} + +func (s *MembershipSource) Scan(value any) error { + var str string + switch v := value.(type) { + case string: + str = v + case []byte: + str = string(v) + default: + return fmt.Errorf("unsupported type for MembershipSource: %T", value) + } + + switch str { + case "MANUAL": + *s = MembershipSourceManual + case "SAML": + *s = MembershipSourceSAML + default: + return fmt.Errorf("invalid MembershipSource value: %q", str) + } + return nil +} + +func (s MembershipSource) Value() (driver.Value, error) { + return s.String(), nil +} diff --git a/pkg/coredata/migrations/20260104T151807Z.sql b/pkg/coredata/migrations/20260104T151807Z.sql new file mode 100644 index 000000000..09f101ddb --- /dev/null +++ b/pkg/coredata/migrations/20260104T151807Z.sql @@ -0,0 +1,2 @@ +ALTER TABLE iam_memberships ADD COLUMN source TEXT NOT NULL DEFAULT 'MANUAL'; +ALTER TABLE iam_memberships ALTER COLUMN source DROP DEFAULT; diff --git a/pkg/iam/account_service.go b/pkg/iam/account_service.go index 14c513bed..e90acffa0 100644 --- a/pkg/iam/account_service.go +++ b/pkg/iam/account_service.go @@ -248,6 +248,7 @@ func (s *AccountService) AcceptInvitation( IdentityID: identityID, OrganizationID: invitation.OrganizationID, Role: invitation.Role, + Source: coredata.MembershipSourceManual, CreatedAt: now, UpdatedAt: now, } diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index 72c6b00d2..134a8fd60 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -489,6 +489,7 @@ func (s *OrganizationService) CreateOrganization( IdentityID: identityID, OrganizationID: organizationID, Role: coredata.MembershipRoleOwner, + Source: coredata.MembershipSourceManual, CreatedAt: now, UpdatedAt: now, } diff --git a/pkg/iam/saml/service.go b/pkg/iam/saml/service.go index 665adaaaf..8fbf7dc9f 100644 --- a/pkg/iam/saml/service.go +++ b/pkg/iam/saml/service.go @@ -298,6 +298,7 @@ func (s *Service) HandleAssertion( IdentityID: identity.ID, OrganizationID: config.OrganizationID, Role: coredata.MembershipRoleViewer, + Source: coredata.MembershipSourceSAML, CreatedAt: now, UpdatedAt: now, } diff --git a/pkg/server/api/connect/v1/schema.graphql b/pkg/server/api/connect/v1/schema.graphql index 4469c6165..c530bfe48 100644 --- a/pkg/server/api/connect/v1/schema.graphql +++ b/pkg/server/api/connect/v1/schema.graphql @@ -234,6 +234,13 @@ enum MembershipRole @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAuditor") } +enum MembershipSource + @goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipSource") { + MANUAL + @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipSourceManual") + SAML @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipSourceSAML") +} + type Membership implements Node { id: ID! createdAt: Datetime! @@ -241,6 +248,7 @@ type Membership implements Node { profile: MembershipProfile @goField(forceResolver: true) organization: Organization @goField(forceResolver: true) role: MembershipRole! + source: MembershipSource! lastSession: Session @goField(forceResolver: true) @isViewer diff --git a/pkg/server/api/connect/v1/schema/schema.go b/pkg/server/api/connect/v1/schema/schema.go index b1f0f3bac..892ee9344 100644 --- a/pkg/server/api/connect/v1/schema/schema.go +++ b/pkg/server/api/connect/v1/schema/schema.go @@ -170,6 +170,7 @@ type ComplexityRoot struct { Permission func(childComplexity int, action string) int Profile func(childComplexity int) int Role func(childComplexity int) int + Source func(childComplexity int) int } MembershipConnection struct { @@ -862,6 +863,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Membership.Role(childComplexity), true + case "Membership.source": + if e.complexity.Membership.Source == nil { + break + } + + return e.complexity.Membership.Source(childComplexity), true case "MembershipConnection.edges": if e.complexity.MembershipConnection.Edges == nil { @@ -2198,6 +2205,13 @@ enum MembershipRole @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAuditor") } +enum MembershipSource + @goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipSource") { + MANUAL + @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipSourceManual") + SAML @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipSourceSAML") +} + type Membership implements Node { id: ID! createdAt: Datetime! @@ -2205,6 +2219,7 @@ type Membership implements Node { profile: MembershipProfile @goField(forceResolver: true) organization: Organization @goField(forceResolver: true) role: MembershipRole! + source: MembershipSource! lastSession: Session @goField(forceResolver: true) @isViewer @@ -5163,6 +5178,35 @@ func (ec *executionContext) fieldContext_Membership_role(_ context.Context, fiel return fc, nil } +func (ec *executionContext) _Membership_source(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + ec.fieldContext_Membership_source, + func(ctx context.Context) (any, error) { + return obj.Source, nil + }, + nil, + ec.marshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource, + true, + true, + ) +} + +func (ec *executionContext) fieldContext_Membership_source(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Membership", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type MembershipSource does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Membership_lastSession(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -5421,6 +5465,8 @@ func (ec *executionContext) fieldContext_MembershipEdge_node(_ context.Context, return ec.fieldContext_Membership_organization(ctx, field) case "role": return ec.fieldContext_Membership_role(ctx, field) + case "source": + return ec.fieldContext_Membership_source(ctx, field) case "lastSession": return ec.fieldContext_Membership_lastSession(ctx, field) case "permission": @@ -7711,6 +7757,8 @@ func (ec *executionContext) fieldContext_Organization_viewerMembership(_ context return ec.fieldContext_Membership_organization(ctx, field) case "role": return ec.fieldContext_Membership_role(ctx, field) + case "source": + return ec.fieldContext_Membership_source(ctx, field) case "lastSession": return ec.fieldContext_Membership_lastSession(ctx, field) case "permission": @@ -7864,6 +7912,8 @@ func (ec *executionContext) fieldContext_OrganizationSessionCreated_membership(_ return ec.fieldContext_Membership_organization(ctx, field) case "role": return ec.fieldContext_Membership_role(ctx, field) + case "source": + return ec.fieldContext_Membership_source(ctx, field) case "lastSession": return ec.fieldContext_Membership_lastSession(ctx, field) case "permission": @@ -10496,6 +10546,8 @@ func (ec *executionContext) fieldContext_UpdateMembershipPayload_membership(_ co return ec.fieldContext_Membership_organization(ctx, field) case "role": return ec.fieldContext_Membership_role(ctx, field) + case "source": + return ec.fieldContext_Membership_source(ctx, field) case "lastSession": return ec.fieldContext_Membership_lastSession(ctx, field) case "permission": @@ -14408,6 +14460,11 @@ func (ec *executionContext) _Membership(ctx context.Context, sel ast.SelectionSe if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "source": + out.Values[i] = ec._Membership_source(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } case "lastSession": field := field @@ -17574,6 +17631,34 @@ var ( } ) +func (ec *executionContext) unmarshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource(ctx context.Context, v any) (coredata.MembershipSource, error) { + tmp, err := graphql.UnmarshalString(v) + res := unmarshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource[tmp] + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource(ctx context.Context, sel ast.SelectionSet, v coredata.MembershipSource) graphql.Marshaler { + _ = sel + res := graphql.MarshalString(marshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource[v]) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +var ( + unmarshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource = map[string]coredata.MembershipSource{ + "MANUAL": coredata.MembershipSourceManual, + "SAML": coredata.MembershipSourceSAML, + } + marshalNMembershipSource2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐMembershipSource = map[coredata.MembershipSource]string{ + coredata.MembershipSourceManual: "MANUAL", + coredata.MembershipSourceSAML: "SAML", + } +) + func (ec *executionContext) unmarshalNOrderDirection2goᚗproboᚗincᚋproboᚋpkgᚋpageᚐOrderDirection(ctx context.Context, v any) (page.OrderDirection, error) { tmp, err := graphql.UnmarshalString(v) res := unmarshalNOrderDirection2goᚗproboᚗincᚋproboᚋpkgᚋpageᚐOrderDirection[tmp] diff --git a/pkg/server/api/connect/v1/types/membership.go b/pkg/server/api/connect/v1/types/membership.go index b5adced31..5025957e3 100644 --- a/pkg/server/api/connect/v1/types/membership.go +++ b/pkg/server/api/connect/v1/types/membership.go @@ -72,10 +72,7 @@ func NewMembership(membership *coredata.Membership) *Membership { Profile: &MembershipProfile{ ID: membership.ID, }, - Role: membership.Role, - // Permissions: membership.Permissions, - // ProvisionedBy: membership.ProvisionedBy, - // Active: membership.Active, - // LastSyncedAt: membership.LastSyncedAt, + Role: membership.Role, + Source: membership.Source, } } diff --git a/pkg/server/api/connect/v1/types/types.go b/pkg/server/api/connect/v1/types/types.go index 9434ef58a..6d55c60a4 100644 --- a/pkg/server/api/connect/v1/types/types.go +++ b/pkg/server/api/connect/v1/types/types.go @@ -186,14 +186,15 @@ type InviteMemberPayload struct { } type Membership struct { - ID gid.GID `json:"id"` - CreatedAt time.Time `json:"createdAt"` - Identity *Identity `json:"identity,omitempty"` - Profile *MembershipProfile `json:"profile,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Role coredata.MembershipRole `json:"role"` - LastSession *Session `json:"lastSession,omitempty"` - Permission bool `json:"permission"` + ID gid.GID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + Identity *Identity `json:"identity,omitempty"` + Profile *MembershipProfile `json:"profile,omitempty"` + Organization *Organization `json:"organization,omitempty"` + Role coredata.MembershipRole `json:"role"` + Source coredata.MembershipSource `json:"source"` + LastSession *Session `json:"lastSession,omitempty"` + Permission bool `json:"permission"` } func (Membership) IsNode() {}