diff --git a/apps/console/src/layouts/MainLayout.tsx b/apps/console/src/layouts/MainLayout.tsx deleted file mode 100644 index a6548d535..000000000 --- a/apps/console/src/layouts/MainLayout.tsx +++ /dev/null @@ -1,564 +0,0 @@ -import { useTranslate } from "@probo/i18n"; -import { - Avatar, - Badge, - Button, - Dropdown, - DropdownItem, - DropdownSeparator, - IconArrowBoxLeft, - IconBank, - IconBook, - IconBox, - IconCalendar2, - IconCheckmark1, - IconChevronGrabberVertical, - IconCircleProgress, - IconCircleQuestionmark, - IconClock, - IconCrossLargeX, - IconFire3, - IconGroup1, - IconInboxEmpty, - IconKey, - IconListStack, - IconPageCheck, - IconLock, - IconMagnifyingGlass, - IconMedal, - IconPageTextLine, - IconPeopleAdd, - IconPlusLarge, - IconRotateCw, - IconSettingsGear2, - IconShield, - IconStore, - IconTodo, - Input, - Layout, - SidebarItem, - Skeleton, - UserDropdownItem, - UserDropdown as UserDropdownRoot, - useToast, -} from "@probo/ui"; -import { Suspense, use, useEffect, useMemo, useState } from "react"; -import { ErrorBoundary } from "react-error-boundary"; -import { useLazyLoadQuery } from "react-relay"; -import { Link, Navigate, Outlet, useParams } from "react-router"; -import { graphql } from "relay-runtime"; -import type { MainLayoutQuery as MainLayoutQueryType } from "./__generated__/MainLayoutQuery.graphql"; -import { PageError } from "/components/PageError"; -import { PermissionsProvider } from "/providers/PermissionsProvider"; -import { PermissionsContext } from "/providers/PermissionsContext"; - -const MainLayoutQuery = graphql` - query MainLayoutQuery($organizationId: ID!) { - viewer { - id - } - organization: node(id: $organizationId) { - ... on Organization { - id - name - logoUrl - } - } - } -`; - -/** - * Site layout with a header and a sidebar - */ -export function MainLayout() { - const { organizationId } = useParams(); - - const prefix = `/organizations/${organizationId}`; - - if (!organizationId) { - return ; - } - - return ( - }> - - - - - ); -} - -function MainLayoutContent({ - organizationId, - prefix, -}: { - organizationId: string; - prefix: string; -}) { - const { __ } = useTranslate(); - const { isAuthorized } = use(PermissionsContext); - const data = useLazyLoadQuery(MainLayoutQuery, { - organizationId, - }); - - return ( - -
- -
- }> - - - - } - sidebar={ -
    - {isAuthorized("Organization", "listMeetings") && ( - - )} - {isAuthorized("Organization", "listTasks") && ( - - )} - {isAuthorized("Organization", "listMeasures") && ( - - )} - {isAuthorized("Organization", "listRisks") && ( - - )} - {isAuthorized("Organization", "listFrameworks") && ( - - )} - {isAuthorized("Organization", "listPeople") && ( - - )} - {isAuthorized("Organization", "listVendors") && ( - - )} - {isAuthorized("Organization", "listDocuments") && ( - - )} - {isAuthorized("Organization", "listAssets") && ( - - )} - {isAuthorized("Organization", "listData") && ( - - )} - {isAuthorized("Organization", "listAudits") && ( - - )} - {isAuthorized("Organization", "listNonconformities") && ( - - )} - {isAuthorized("Organization", "listObligations") && ( - - )} - {isAuthorized("Organization", "listContinualImprovements") && ( - - )} - {isAuthorized("Organization", "listProcessingActivities") && ( - - )} - {isAuthorized("Organization", "listRightsRequests") && ( - - )} - {isAuthorized("Organization", "listStatesOfApplicability") && ( - - )} - {isAuthorized("Organization", "listSnapshots") && ( - - )} - {isAuthorized("Organization", "getTrustCenter") && ( - - )} - {isAuthorized("Organization", "listMembers") && ( - - )} -
- } - > - - - -
- ); -} - -function UserDropdown({ organizationId }: { organizationId: string }) { - const { __ } = useTranslate(); - const { toast } = useToast(); - const { isAuthorized } = use(PermissionsContext); - // const user = useLazyLoadQuery(MainLayoutQuery, { - // organizationId, - // }).viewer.user; - const user = { - fullName: "", - email: "", - }; - - const handleLogout: React.MouseEventHandler = async ( - e - ) => { - e.preventDefault(); - - fetch("/connect/logout", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({}), - }) - .then(async (res) => { - if (!res.ok) { - const error = await res.json(); - throw new Error(error.message || __("Failed to login")); - } - - window.location.reload(); - }) - .catch((e) => { - toast({ - title: __("Error"), - description: e.message as string, - variant: "error", - }); - }); - }; - - return ( - - {isAuthorized("Organization", "deleteOrganization") && ( - - )} - {isAuthorized("Organization", "listSignableDocuments") && ( - - )} - - - - - ); -} - -interface Organization { - id: string; - name: string; - logoUrl?: string | null; - authenticationMethod: string; - authStatus: "authenticated" | "unauthenticated" | "expired"; - loginUrl: string; -} - -interface OrganizationsResponse { - organizations: Organization[]; -} - -interface Invitation { - id: string; - email: string; - fullName: string; - role: string; - expiresAt: string; - acceptedAt?: string | null; - createdAt: string; - organization: { - id: string; - name: string; - }; -} - -interface InvitationsResponse { - invitations: Invitation[]; -} - -function OrganizationSelector({ - currentOrganization, -}: { - currentOrganization: MainLayoutQueryType["response"]["organization"]; -}) { - const [organizations, setOrganizations] = useState([]); - const [pendingInvitationsCount, setPendingInvitationsCount] = useState(0); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - const [search, setSearch] = useState(""); - const { __ } = useTranslate(); - - const filteredOrganizations = useMemo(() => { - if (!search.trim()) { - return organizations; - } - return organizations.filter((org) => - org.name.toLowerCase().includes(search.toLowerCase()) - ); - }, [organizations, search]); - - useEffect(() => { - const fetchData = async () => { - try { - setIsLoading(true); - - const [orgsResponse, invitationsResponse] = await Promise.all([ - fetch("/connect/organizations", { credentials: "include" }), - fetch("/connect/invitations", { credentials: "include" }), - ]); - - if (!orgsResponse.ok) { - throw new Error("Failed to fetch organizations"); - } - - if (!invitationsResponse.ok) { - throw new Error("Failed to fetch invitations"); - } - - const orgsData: OrganizationsResponse = await orgsResponse.json(); - const invitationsData: InvitationsResponse = - await invitationsResponse.json(); - - const pendingCount = invitationsData.invitations.filter( - (inv) => !inv.acceptedAt - ).length; - - setOrganizations(orgsData.organizations); - setPendingInvitationsCount(pendingCount); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Unknown error"); - console.error("Failed to fetch data:", err); - } finally { - setIsLoading(false); - } - }; - - fetchData(); - }, []); - - if (error) { - return ( -
- -
- ); - } - - return ( -
- - {isLoading ? __("Loading...") : currentOrganization?.name || ""} - - } - > -
- { - e.stopPropagation(); - }} - autoFocus - /> -
-
- {isLoading ? ( -
- {__("Loading organizations...")} -
- ) : filteredOrganizations.length === 0 ? ( -
- {__("No organizations found")} -
- ) : ( - filteredOrganizations.map((organization) => { - const isAuthenticated = - organization.authStatus === "authenticated"; - const isExpired = organization.authStatus === "expired"; - const needsAuth = organization.authStatus === "unauthenticated"; - - const targetUrl = isAuthenticated - ? `/organizations/${organization.id}` - : organization.loginUrl; - - const isSAMLUrl = targetUrl.includes("/connect/saml/"); - - // Use organization endpoint for all logos for consistency - const logoUrl = organization.logoUrl; - - return ( - - {isSAMLUrl ? ( - - - {organization.name} - {isAuthenticated && ( - - )} - {isExpired && ( - - )} - {needsAuth && ( - - )} - - ) : ( - - - {organization.name} - {isAuthenticated && ( - - )} - {isExpired && ( - - )} - {needsAuth && ( - - )} - - )} - - ); - }) - )} -
- - {pendingInvitationsCount > 0 && ( - - - - {__("Invitations")} - - {pendingInvitationsCount} - - - - )} - - - - {__("Add organization")} - - -
- {pendingInvitationsCount > 0 && ( - -
- ); -} diff --git a/apps/console/src/pages/iam/memberships/_components/Sidebar.tsx b/apps/console/src/pages/iam/memberships/_components/Sidebar.tsx index c4c9aa86b..d8e48eb67 100644 --- a/apps/console/src/pages/iam/memberships/_components/Sidebar.tsx +++ b/apps/console/src/pages/iam/memberships/_components/Sidebar.tsx @@ -13,6 +13,7 @@ import { IconInboxEmpty, IconListStack, IconMedal, + IconPageCheck, IconPageTextLine, IconRotateCw, IconSettingsGear2, @@ -139,6 +140,13 @@ export function Sidebar() { to={`${prefix}/processing-activities`} /> )} + {isAuthorized("Organization", "listStatesOfApplicability") && ( + + )} {isAuthorized("Organization", "listSnapshots") && ( - loadQuery(consoleEnvironment, rightsRequestsQuery, { + loadQuery(coreEnvironment, rightsRequestsQuery, { organizationId, }), ), @@ -24,7 +24,7 @@ export const rightsRequestRoutes = [ path: "rights-requests/:requestId", Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ requestId }) => - loadQuery(consoleEnvironment, rightsRequestNodeQuery, { + loadQuery(coreEnvironment, rightsRequestNodeQuery, { rightsRequestId: requestId!, }), ), diff --git a/apps/console/src/routes/statesOfApplicabilityRoutes.ts b/apps/console/src/routes/statesOfApplicabilityRoutes.ts index bd998c448..09978fc95 100644 --- a/apps/console/src/routes/statesOfApplicabilityRoutes.ts +++ b/apps/console/src/routes/statesOfApplicabilityRoutes.ts @@ -1,6 +1,6 @@ import { lazy } from "@probo/react-lazy"; import { loadQuery } from "react-relay"; -import { consoleEnvironment } from "/environments"; +import { coreEnvironment } from "/environments"; import { PageSkeleton } from "/components/skeletons/PageSkeleton.tsx"; import { paginatedStateOfApplicabilityQuery, @@ -16,7 +16,7 @@ export const statesOfApplicabilityRoutes = [ Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery( - consoleEnvironment, + coreEnvironment, paginatedStateOfApplicabilityQuery, { organizationId: organizationId! }, ), @@ -30,7 +30,7 @@ export const statesOfApplicabilityRoutes = [ Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery( - consoleEnvironment, + coreEnvironment, paginatedStateOfApplicabilityQuery, { organizationId: organizationId! }, ), @@ -44,7 +44,7 @@ export const statesOfApplicabilityRoutes = [ Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ stateOfApplicabilityId }) => loadQuery( - consoleEnvironment, + coreEnvironment, stateOfApplicabilityNodeQuery, { stateOfApplicabilityId: stateOfApplicabilityId! }, ), @@ -58,7 +58,7 @@ export const statesOfApplicabilityRoutes = [ Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ stateOfApplicabilityId }) => loadQuery( - consoleEnvironment, + coreEnvironment, stateOfApplicabilityNodeQuery, { stateOfApplicabilityId: stateOfApplicabilityId! }, ), diff --git a/pkg/coredata/entity_type_reg.go b/pkg/coredata/entity_type_reg.go index 83cd618ee..35460d726 100644 --- a/pkg/coredata/entity_type_reg.go +++ b/pkg/coredata/entity_type_reg.go @@ -72,6 +72,7 @@ const ( RightsRequestEntityType uint16 = 48 StateOfApplicabilityEntityType uint16 = 49 StateOfApplicabilityControlEntityType uint16 = 50 + IdentityProfileEntityType uint16 = 51 ) type EntityInfo struct { @@ -284,6 +285,10 @@ var entityRegistry = map[uint16]EntityInfo{ Model: "StateOfApplicabilityControl", Table: "states_of_applicability_controls", }, + IdentityProfileEntityType: { + Model: "IdentityProfile", + Table: "iam_identity_profiles", + }, } func EntityTable(entityType uint16) (string, bool) { diff --git a/pkg/coredata/identity.go b/pkg/coredata/identity.go index 84dcb41fc..ea11f7b11 100644 --- a/pkg/coredata/identity.go +++ b/pkg/coredata/identity.go @@ -35,7 +35,6 @@ type ( ID gid.GID `db:"id"` EmailAddress mail.Addr `db:"email_address"` HashedPassword []byte `db:"hashed_password"` - FullName string `db:"fullname"` EmailAddressVerified bool `db:"email_address_verified"` SAMLSubject *string `db:"saml_subject"` CreatedAt time.Time `db:"created_at"` @@ -66,9 +65,8 @@ SELECT email_address, hashed_password, email_address_verified, - fullname, - created_at, - updated_at + created_at, + updated_at FROM identities WHERE @@ -143,7 +141,6 @@ SELECT email_address, hashed_password, email_address_verified, - fullname, saml_subject, created_at, updated_at @@ -186,8 +183,7 @@ SELECT id, email_address, hashed_password, - email_address_verified, - fullname, + email_address_verified, saml_subject, created_at, updated_at @@ -225,13 +221,12 @@ func (i *Identity) Insert( ) error { q := ` INSERT INTO - identities (id, email_address, hashed_password, email_address_verified, fullname, saml_subject, created_at, updated_at) + identities (id, email_address, hashed_password, email_address_verified, saml_subject, created_at, updated_at) VALUES ( @identity_id, @email_address, @hashed_password, @email_address_verified, - @fullname, @saml_subject, @created_at, @updated_at @@ -242,7 +237,6 @@ VALUES ( "identity_id": i.ID, "email_address": i.EmailAddress, "hashed_password": i.HashedPassword, - "fullname": i.FullName, "saml_subject": i.SAMLSubject, "created_at": i.CreatedAt, "updated_at": i.UpdatedAt, @@ -273,8 +267,7 @@ SET email_address = @email_address, email_address_verified = @email_address_verified, saml_subject = @saml_subject, - fullname = @fullname, - hashed_password = @hashed_password, + hashed_password = @hashed_password, updated_at = @updated_at WHERE id = @identity_id @@ -286,7 +279,6 @@ WHERE "email_address_verified": i.EmailAddressVerified, "saml_subject": i.SAMLSubject, "updated_at": i.UpdatedAt, - "fullname": i.FullName, "hashed_password": i.HashedPassword, } @@ -314,7 +306,6 @@ SELECT email_address, hashed_password, email_address_verified, - fullname, saml_subject, created_at, updated_at diff --git a/pkg/coredata/identity_profile.go b/pkg/coredata/identity_profile.go new file mode 100644 index 000000000..705934f7f --- /dev/null +++ b/pkg/coredata/identity_profile.go @@ -0,0 +1,293 @@ +// 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 ( + "context" + "errors" + "fmt" + "maps" + "time" + + "github.com/jackc/pgx/v5" + "go.gearno.de/kit/pg" + "go.probo.inc/probo/pkg/gid" +) + +type ( + IdentityProfile struct { + ID gid.GID `db:"id"` + IdentityID gid.GID `db:"identity_id"` + MembershipID *gid.GID `db:"membership_id"` + FullName string `db:"full_name"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` + } + + IdentityProfiles []*IdentityProfile +) + +func (p *IdentityProfile) IsDefault() bool { + return p.MembershipID == nil +} + +// LoadDefaultByIdentityID loads the default profile for an identity (where membership_id is NULL) +func (p *IdentityProfile) LoadDefaultByIdentityID( + ctx context.Context, + conn pg.Conn, + identityID gid.GID, +) error { + q := ` +SELECT + id, + identity_id, + membership_id, + full_name, + created_at, + updated_at +FROM + iam_identity_profiles +WHERE + tenant_id IS NULL + AND identity_id = @identity_id + AND membership_id IS NULL +LIMIT 1; +` + + args := pgx.StrictNamedArgs{"identity_id": identityID} + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query default identity profile: %w", err) + } + + profile, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[IdentityProfile]) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return ErrResourceNotFound + } + + return fmt.Errorf("cannot collect default identity profile: %w", err) + } + + *p = profile + + return nil +} + +// LoadByMembershipID loads the profile for a specific membership +func (p *IdentityProfile) LoadByMembershipID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + membershipID gid.GID, +) error { + q := ` +SELECT + id, + identity_id, + membership_id, + full_name, + created_at, + updated_at +FROM + iam_identity_profiles +WHERE + %s + AND membership_id = @membership_id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"membership_id": membershipID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query identity profile: %w", err) + } + + profile, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[IdentityProfile]) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return ErrResourceNotFound + } + + return fmt.Errorf("cannot collect identity profile: %w", err) + } + + *p = profile + + return nil +} + +func (p *IdentityProfile) LoadByID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + profileID gid.GID, +) error { + q := ` +SELECT + id, + identity_id, + membership_id, + full_name, + created_at, + updated_at +FROM + iam_identity_profiles +WHERE + %s + AND id = @profile_id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"profile_id": profileID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query identity profile: %w", err) + } + + profile, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[IdentityProfile]) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return ErrResourceNotFound + } + + return fmt.Errorf("cannot collect identity profile: %w", err) + } + + *p = profile + + return nil +} + +func (p *IdentityProfile) Insert( + ctx context.Context, + conn pg.Conn, +) error { + q := ` +INSERT INTO + iam_identity_profiles ( + tenant_id, + id, + identity_id, + membership_id, + full_name, + created_at, + updated_at + ) +VALUES ( + @tenant_id, + @id, + @identity_id, + @membership_id, + @full_name, + @created_at, + @updated_at +) +` + + args := pgx.StrictNamedArgs{ + "tenant_id": p.ID.TenantID().String(), + "id": p.ID, + "identity_id": p.IdentityID, + "membership_id": p.MembershipID, + "full_name": p.FullName, + "created_at": p.CreatedAt, + "updated_at": p.UpdatedAt, + } + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot insert identity profile: %w", err) + } + + return nil +} + +func (p *IdentityProfile) Update( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +UPDATE + iam_identity_profiles +SET + full_name = @full_name, + updated_at = @updated_at +WHERE + id = @id + AND %s +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "id": p.ID, + "full_name": p.FullName, + "updated_at": p.UpdatedAt, + } + maps.Copy(args, scope.SQLArguments()) + + result, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot update identity profile: %w", err) + } + + if result.RowsAffected() == 0 { + return ErrResourceNotFound + } + + return nil +} + +func (p *IdentityProfile) Delete( + ctx context.Context, + conn pg.Conn, + scope Scoper, + profileID gid.GID, +) error { + q := ` +DELETE FROM + iam_identity_profiles +WHERE + id = @profile_id + AND %s +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"profile_id": profileID} + maps.Copy(args, scope.SQLArguments()) + + result, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot delete identity profile: %w", err) + } + + if result.RowsAffected() == 0 { + return ErrResourceNotFound + } + + return nil +} diff --git a/pkg/coredata/membership.go b/pkg/coredata/membership.go index 086095112..17fefba7a 100644 --- a/pkg/coredata/membership.go +++ b/pkg/coredata/membership.go @@ -189,7 +189,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, - i.fullname as full_name, + COALESCE(mp.full_name, dp.full_name, '') as full_name, i.email_address, mbr.created_at, mbr.updated_at @@ -197,6 +197,10 @@ FROM mbr JOIN identities i ON mbr.identity_id = i.id +LEFT JOIN + iam_identity_profiles mp ON mp.membership_id = mbr.id +LEFT JOIN + iam_identity_profiles dp ON dp.identity_id = mbr.identity_id AND dp.membership_id IS NULL ` query = fmt.Sprintf(query, scope.SQLFragment()) @@ -329,7 +333,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, - i.fullname as full_name, + COALESCE(mp.full_name, dp.full_name, '') as full_name, i.email_address, mbr.created_at, mbr.updated_at @@ -337,6 +341,10 @@ FROM mbr JOIN identities i ON mbr.identity_id = i.id +LEFT JOIN + iam_identity_profiles mp ON mp.membership_id = mbr.id +LEFT JOIN + iam_identity_profiles dp ON dp.identity_id = mbr.identity_id AND dp.membership_id IS NULL ` q = fmt.Sprintf(q, scope.SQLFragment()) @@ -455,7 +463,7 @@ SELECT mbr.identity_id, mbr.organization_id, mbr.role, - i.fullname as full_name, + COALESCE(mp.full_name, dp.full_name, '') as full_name, i.email_address, mbr.created_at, mbr.updated_at @@ -463,6 +471,10 @@ FROM mbr JOIN identities i ON mbr.identity_id = i.id +LEFT JOIN + iam_identity_profiles mp ON mp.membership_id = mbr.id +LEFT JOIN + iam_identity_profiles dp ON dp.identity_id = mbr.identity_id AND dp.membership_id IS NULL ORDER BY mbr.created_at DESC ` @@ -520,19 +532,23 @@ SELECT created_at, updated_at FROM ( - SELECT - mbr.id, - mbr.identity_id, - mbr.organization_id, - mbr.role, - i.fullname as full_name, - i.email_address, - mbr.created_at, - mbr.updated_at - FROM - mbr - JOIN - identities i ON mbr.identity_id = i.id + SELECT + mbr.id, + mbr.identity_id, + mbr.organization_id, + mbr.role, + COALESCE(mp.full_name, dp.full_name, '') as full_name, + i.email_address, + mbr.created_at, + mbr.updated_at + FROM + mbr + JOIN + identities i ON mbr.identity_id = i.id + LEFT JOIN + iam_identity_profiles mp ON mp.membership_id = mbr.id + LEFT JOIN + iam_identity_profiles dp ON dp.identity_id = mbr.identity_id AND dp.membership_id IS NULL ) AS membership_with_identity WHERE %s ` diff --git a/pkg/coredata/migrations/20251220T140915Z.sql b/pkg/coredata/migrations/20251220T140915Z.sql new file mode 100644 index 000000000..97cd15be2 --- /dev/null +++ b/pkg/coredata/migrations/20251220T140915Z.sql @@ -0,0 +1,12 @@ +CREATE TABLE iam_identity_profiles ( + tenant_id TEXT NOT NULL, + id TEXT NOT NULL PRIMARY KEY, + identity_id TEXT NOT NULL REFERENCES identities(id) ON DELETE CASCADE, + membership_id TEXT REFERENCES iam_memberships(id) ON DELETE CASCADE, + full_name TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL, + updated_at TIMESTAMPTZ NOT NULL +); + +CREATE UNIQUE INDEX idx_iam_identity_profiles_default ON iam_identity_profiles(identity_id) WHERE membership_id IS NULL; +CREATE UNIQUE INDEX idx_iam_identity_profiles_membership ON iam_identity_profiles(membership_id) WHERE membership_id IS NOT NULL; diff --git a/pkg/coredata/migrations/20251221T222519Z.sql b/pkg/coredata/migrations/20251221T222519Z.sql new file mode 100644 index 000000000..4dbf8582b --- /dev/null +++ b/pkg/coredata/migrations/20251221T222519Z.sql @@ -0,0 +1,32 @@ +INSERT INTO iam_identity_profiles (tenant_id, id, identity_id, membership_id, full_name, created_at, updated_at) +SELECT + '', + generate_gid('\x0000000000000000'::bytea, 51), + i.id, + NULL, + COALESCE(i.fullname, ''), + i.created_at, + NOW() +FROM identities i +WHERE NOT EXISTS ( + SELECT 1 FROM iam_identity_profiles p + WHERE p.identity_id = i.id AND p.membership_id IS NULL +); + +INSERT INTO iam_identity_profiles (tenant_id, id, identity_id, membership_id, full_name, created_at, updated_at) +SELECT + m.tenant_id, + generate_gid(decode_base64_unpadded(m.tenant_id), 51), + m.identity_id, + m.id, + COALESCE(i.fullname, ''), + m.created_at, + NOW() +FROM iam_memberships m +JOIN identities i ON i.id = m.identity_id +WHERE NOT EXISTS ( + SELECT 1 FROM iam_identity_profiles p + WHERE p.membership_id = m.id +); + +ALTER TABLE identities DROP COLUMN fullname; \ No newline at end of file diff --git a/pkg/iam/account_service.go b/pkg/iam/account_service.go index bfd64a963..c608b6a01 100644 --- a/pkg/iam/account_service.go +++ b/pkg/iam/account_service.go @@ -125,9 +125,14 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req return fmt.Errorf("cannot update identity: %w", err) } + profile := &coredata.IdentityProfile{} + if err := profile.LoadDefaultByIdentityID(ctx, tx, identityID); err != nil { + return fmt.Errorf("cannot load default profile: %w", err) + } + subject, textBody, htmlBody, err := emails.RenderConfirmEmail( s.baseURL, - identity.FullName, + profile.FullName, confirmationUrl, ) if err != nil { @@ -135,7 +140,7 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req } confirmationEmail := coredata.NewEmail( - identity.FullName, + profile.FullName, identity.EmailAddress, subject, textBody, @@ -714,3 +719,157 @@ func (s AccountService) ListOrganizations(ctx context.Context, identityID gid.GI return organizations, nil } + +func (s AccountService) GetProfileForMembership(ctx context.Context, membershipID gid.GID) (*coredata.IdentityProfile, error) { + var ( + scope = coredata.NewScopeFromObjectID(membershipID) + profile = &coredata.IdentityProfile{} + ) + + err := s.pg.WithConn( + ctx, + func(conn pg.Conn) error { + membership := &coredata.Membership{} + err := membership.LoadByID(ctx, conn, scope, membershipID) + if err != nil { + if err == coredata.ErrResourceNotFound { + return NewMembershipNotFoundError(membershipID) + } + + return fmt.Errorf("cannot load membership: %w", err) + } + + err = profile.LoadByMembershipID(ctx, conn, scope, membershipID) + if err != nil { + if err == coredata.ErrResourceNotFound { + return NewProfileNotFoundError(membershipID) + } + + return fmt.Errorf("cannot load identity profile: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return profile, nil +} + +func (s AccountService) GetDefaultProfile(ctx context.Context, identityID gid.GID) (*coredata.IdentityProfile, error) { + var profile = &coredata.IdentityProfile{} + + err := s.pg.WithConn( + ctx, + func(conn pg.Conn) error { + err := profile.LoadDefaultByIdentityID(ctx, conn, identityID) + if err != nil { + if err == coredata.ErrResourceNotFound { + return NewProfileNotFoundError(identityID) + } + + return fmt.Errorf("cannot load default profile: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return profile, nil +} + +type UpdateIdentityProfileRequest struct { + MembershipID gid.GID + FullName *string +} + +func (s AccountService) UpdateIdentityProfile( + ctx context.Context, + identityID gid.GID, + req *UpdateIdentityProfileRequest, +) (*coredata.IdentityProfile, error) { + // var ( + // scope = coredata.NewScopeFromObjectID(req.MembershipID) + // profile = &coredata.IdentityProfile{} + // ) + + // err := s.pg.WithTx( + // ctx, + // func(tx pg.Conn) error { + // // First verify the membership belongs to the identity + // membership := &coredata.Membership{} + // err := membership.LoadByID(ctx, tx, scope, req.MembershipID) + // if err != nil { + // if err == coredata.ErrResourceNotFound { + // return NewMembershipNotFoundError(req.MembershipID) + // } + + // return fmt.Errorf("cannot load membership: %w", err) + // } + + // if membership.IdentityID != identityID { + // return NewMembershipNotFoundError(req.MembershipID) + // } + + // // Try to load existing membership profile + // err = profile.LoadByMembershipID(ctx, tx, scope, req.MembershipID) + // if err != nil && err != coredata.ErrResourceNotFound { + // return fmt.Errorf("cannot load identity profile: %w", err) + // } + + // now := time.Now() + + // if err == coredata.ErrResourceNotFound { + // // Create new membership profile, optionally inheriting from default + // tenantID := req.MembershipID.TenantID() + // membershipID := req.MembershipID + + // // Try to get default profile to inherit FullName + // defaultProfile := &coredata.IdentityProfile{} + // defaultFullName := "" + // if loadErr := defaultProfile.LoadDefaultByIdentityID(ctx, tx, identityID); loadErr == nil { + // defaultFullName = defaultProfile.FullName + // } + + // tenantIDStr := tenantID.String() + // profile = &coredata.IdentityProfile{ + // ID: gid.New(tenantID, coredata.IdentityProfileEntityType), + // TenantID: &tenantIDStr, + // IdentityID: identityID, + // MembershipID: &membershipID, + // FullName: defaultFullName, + // CreatedAt: now, + // UpdatedAt: now, + // } + // } + + // // Apply updates + // if req.FullName != nil { + // profile.FullName = *req.FullName + // } + // profile.UpdatedAt = now + + // // Upsert the membership profile + // err = profile.UpsertMembership(ctx, tx) + // if err != nil { + // return fmt.Errorf("cannot upsert identity profile: %w", err) + // } + + // return nil + // }, + // ) + + // if err != nil { + // return nil, err + // } + + // return profile, nil + return nil, nil +} diff --git a/pkg/iam/auth_service.go b/pkg/iam/auth_service.go index e1daea7fb..9f5eb56ba 100644 --- a/pkg/iam/auth_service.go +++ b/pkg/iam/auth_service.go @@ -158,7 +158,6 @@ func (s *AuthService) CreateIdentityFromInvitation( EmailAddress: invitation.Email, HashedPassword: hashedPassword, EmailAddressVerified: true, - FullName: invitation.FullName, CreatedAt: now, UpdatedAt: now, } @@ -172,6 +171,19 @@ func (s *AuthService) CreateIdentityFromInvitation( return fmt.Errorf("cannot insert identity: %w", err) } + defaultProfile := &coredata.IdentityProfile{ + ID: gid.New(gid.NilTenant, coredata.IdentityProfileEntityType), + IdentityID: identity.ID, + FullName: invitation.FullName, + CreatedAt: now, + UpdatedAt: now, + } + + err = defaultProfile.Insert(ctx, tx) + if err != nil { + return fmt.Errorf("cannot insert default profile: %w", err) + } + session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, s.sessionDuration) err = session.Insert(ctx, tx) if err != nil { @@ -273,9 +285,14 @@ func (s AuthService) SendPasswordResetInstructionByEmail( return fmt.Errorf("cannot load identity: %w", err) } + profile := &coredata.IdentityProfile{} + if err := profile.LoadDefaultByIdentityID(ctx, tx, identity.ID); err != nil { + return fmt.Errorf("cannot load default profile: %w", err) + } + subject, textBody, htmlBody, err := emails.RenderPasswordReset( s.baseURL, - identity.FullName, + profile.FullName, resetPasswordUrl, ) if err != nil { @@ -283,7 +300,7 @@ func (s AuthService) SendPasswordResetInstructionByEmail( } passwordResetEmail := coredata.NewEmail( - identity.FullName, + profile.FullName, identity.EmailAddress, subject, textBody, @@ -325,11 +342,18 @@ func (s AuthService) CreateIdentityWithPassword( EmailAddress: req.Email, HashedPassword: hashedPassword, EmailAddressVerified: false, - FullName: req.FullName, CreatedAt: now, UpdatedAt: now, } + defaultProfile = &coredata.IdentityProfile{ + ID: gid.New(gid.NilTenant, coredata.IdentityProfileEntityType), + IdentityID: identity.ID, + FullName: req.FullName, + CreatedAt: now, + UpdatedAt: now, + } + session = coredata.NewRootSession(identity.ID, coredata.AuthMethodPassword, 24*time.Hour*7) ) @@ -358,7 +382,7 @@ func (s AuthService) CreateIdentityWithPassword( subject, textBody, htmlBody, err := emails.RenderConfirmEmail( s.baseURL, - identity.FullName, + req.FullName, confirmationUrl, ) if err != nil { @@ -366,7 +390,7 @@ func (s AuthService) CreateIdentityWithPassword( } confirmationEmail := coredata.NewEmail( - identity.FullName, + req.FullName, identity.EmailAddress, subject, textBody, @@ -385,6 +409,11 @@ func (s AuthService) CreateIdentityWithPassword( return fmt.Errorf("cannot insert identity: %w", err) } + err = defaultProfile.Insert(ctx, tx) + if err != nil { + return fmt.Errorf("cannot insert default profile: %w", err) + } + if err := confirmationEmail.Insert(ctx, tx); err != nil { return fmt.Errorf("cannot insert email: %w", err) } diff --git a/pkg/iam/errors.go b/pkg/iam/errors.go index 25db318d8..de254d80a 100644 --- a/pkg/iam/errors.go +++ b/pkg/iam/errors.go @@ -200,6 +200,16 @@ func (e ErrPersonalAPIKeyNotFound) Error() string { return fmt.Sprintf("personal API key %q not found", e.PersonalAPIKeyID) } +type ErrProfileNotFound struct{ MembershipID gid.GID } + +func NewProfileNotFoundError(membershipID gid.GID) error { + return &ErrProfileNotFound{MembershipID: membershipID} +} + +func (e ErrProfileNotFound) Error() string { + return fmt.Sprintf("profile for membership %q not found", e.MembershipID) +} + type ErrPersonalAPIKeyExpired struct{ PersonalAPIKeyID gid.GID } func NewPersonalAPIKeyExpiredError(personalAPIKeyID gid.GID) error { diff --git a/pkg/iam/saml/service.go b/pkg/iam/saml/service.go index 2e92237b6..c01be801f 100644 --- a/pkg/iam/saml/service.go +++ b/pkg/iam/saml/service.go @@ -260,7 +260,6 @@ func (s *Service) HandleAssertion( EmailAddress: email, HashedPassword: nil, EmailAddressVerified: true, - FullName: fullname, CreatedAt: now, UpdatedAt: now, } @@ -269,11 +268,23 @@ func (s *Service) HandleAssertion( if err != nil { return fmt.Errorf("cannot insert identity: %w", err) } + + defaultProfile := &coredata.IdentityProfile{ + ID: gid.New(gid.NilTenant, coredata.IdentityProfileEntityType), + IdentityID: identity.ID, + FullName: fullname, + CreatedAt: now, + UpdatedAt: now, + } + + err = defaultProfile.Insert(ctx, tx) + if err != nil { + return fmt.Errorf("cannot insert default profile: %w", err) + } } else if err != nil { return fmt.Errorf("cannot load identity: %w", err) } else { identity.SAMLSubject = &assertion.Subject.NameID.Value - identity.FullName = fullname identity.EmailAddress = email identity.EmailAddressVerified = true identity.UpdatedAt = now @@ -304,6 +315,20 @@ func (s *Service) HandleAssertion( if err != nil { return fmt.Errorf("cannot insert membership: %w", err) } + + membershipProfile := &coredata.IdentityProfile{ + ID: gid.New(membership.ID.TenantID(), coredata.IdentityProfileEntityType), + IdentityID: identity.ID, + MembershipID: &membership.ID, + FullName: fullname, + CreatedAt: now, + UpdatedAt: now, + } + + err = membershipProfile.Insert(ctx, tx) + if err != nil { + return fmt.Errorf("cannot insert membership profile: %w", err) + } } if role != nil { @@ -316,6 +341,19 @@ func (s *Service) HandleAssertion( } } + memberProfile := &coredata.IdentityProfile{} + err = memberProfile.LoadByMembershipID(ctx, tx, coredata.NewNoScope(), membership.ID) + if err != nil { + return fmt.Errorf("cannot load membership profile: %w", err) + } + + memberProfile.FullName = fullname + memberProfile.UpdatedAt = now + err = memberProfile.Update(ctx, tx, coredata.NewNoScope()) + if err != nil { + return fmt.Errorf("cannot update membership profile: %w", err) + } + return nil }, ) diff --git a/pkg/server/api/connect/v1/schema.graphql b/pkg/server/api/connect/v1/schema.graphql index bf4585c41..101f82fd8 100644 --- a/pkg/server/api/connect/v1/schema.graphql +++ b/pkg/server/api/connect/v1/schema.graphql @@ -138,6 +138,8 @@ type Identity implements Node { createdAt: Datetime! updatedAt: Datetime! + defaultProfile: IdentityProfile @goField(forceResolver: true) @isViewer + memberships( first: Int after: CursorKey @@ -168,27 +170,12 @@ type Identity implements Node { last: Int before: CursorKey ): PersonalAPIKeyConnection @goField(forceResolver: true) @isViewer - - profileFor(organizationId: ID!): IdentityProfile @isViewer } type IdentityProfile implements Node { id: ID! - displayName: String! - firstName: String - lastName: String - jobTitle: String - department: String - phoneNumber: String - avatarUrl: String - manager: IdentityProfile - timezone: String - locale: String - customAttributes: [CustomAttribute!]! - provisionedBy: ProvisioningSource! - externalId: String + fullName: String! identity: Identity! - organization: Organization! createdAt: Datetime! updatedAt: Datetime! } @@ -244,8 +231,8 @@ enum MembershipRole type Membership implements Node { id: ID! createdAt: Datetime! - profile: IdentityProfile! identity: Identity @goField(forceResolver: true) + profile: IdentityProfile @goField(forceResolver: true) @isViewer organization: Organization @goField(forceResolver: true) role: MembershipRole! permissions: [Permission!]! @@ -382,12 +369,6 @@ enum SAMLEnforcementPolicy ) } -enum AuthMethod { - PASSWORD - SAML - RECOVERY_CODE -} - enum TokenScope { READ_ORGANIZATION WRITE_ORGANIZATION @@ -578,14 +559,7 @@ input AssumeOrganizationSessionInput { input UpdateIdentityProfileInput { membershipId: ID! - displayName: String - firstName: String - lastName: String - jobTitle: String - department: String - phoneNumber: String - timezone: String - locale: String + fullName: String } input RevokeSessionInput { @@ -750,10 +724,6 @@ type DeactivateAccountPayload { success: Boolean! } -type DeleteAccountPayload { - success: Boolean! -} - type UpdateIdentityProfilePayload { profile: IdentityProfile } diff --git a/pkg/server/api/connect/v1/schema/schema.go b/pkg/server/api/connect/v1/schema/schema.go index ee99bbc24..b28a3154e 100644 --- a/pkg/server/api/connect/v1/schema/schema.go +++ b/pkg/server/api/connect/v1/schema/schema.go @@ -56,6 +56,7 @@ type ResolverRoot interface { PersonalAPIKeyConnection() PersonalAPIKeyConnectionResolver Query() QueryResolver SAMLConfigurationConnection() SAMLConfigurationConnectionResolver + Session() SessionResolver SessionConnection() SessionConnectionResolver } @@ -102,19 +103,10 @@ type ComplexityRoot struct { SamlConfigurationEdge func(childComplexity int) int } - CustomAttribute struct { - Key func(childComplexity int) int - Value func(childComplexity int) int - } - DeactivateAccountPayload struct { Success func(childComplexity int) int } - DeleteAccountPayload struct { - Success func(childComplexity int) int - } - DeleteInvitationPayload struct { DeletedInvitationID func(childComplexity int) int } @@ -137,36 +129,23 @@ type ComplexityRoot struct { Identity struct { CreatedAt func(childComplexity int) int + DefaultProfile func(childComplexity int) int Email func(childComplexity int) int EmailVerified func(childComplexity int) int ID func(childComplexity int) int Memberships func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MembershipOrderBy) int PendingInvitations func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.InvitationOrderBy) int PersonalAPIKeys func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int - ProfileFor func(childComplexity int, organizationID gid.GID) int Sessions func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) int UpdatedAt func(childComplexity int) int } IdentityProfile struct { - AvatarURL func(childComplexity int) int - CreatedAt func(childComplexity int) int - CustomAttributes func(childComplexity int) int - Department func(childComplexity int) int - DisplayName func(childComplexity int) int - ExternalID func(childComplexity int) int - FirstName func(childComplexity int) int - ID func(childComplexity int) int - Identity func(childComplexity int) int - JobTitle func(childComplexity int) int - LastName func(childComplexity int) int - Locale func(childComplexity int) int - Manager func(childComplexity int) int - Organization func(childComplexity int) int - PhoneNumber func(childComplexity int) int - ProvisionedBy func(childComplexity int) int - Timezone func(childComplexity int) int - UpdatedAt func(childComplexity int) int + CreatedAt func(childComplexity int) int + FullName func(childComplexity int) int + ID func(childComplexity int) int + Identity func(childComplexity int) int + UpdatedAt func(childComplexity int) int } Invitation struct { @@ -196,18 +175,14 @@ type ComplexityRoot struct { } Membership struct { - Active func(childComplexity int) int - CreatedAt func(childComplexity int) int - ID func(childComplexity int) int - Identity func(childComplexity int) int - IdentityID func(childComplexity int) int - LastSession func(childComplexity int) int - LastSyncedAt func(childComplexity int) int - Organization func(childComplexity int) int - Permissions func(childComplexity int) int - Profile func(childComplexity int) int - ProvisionedBy func(childComplexity int) int - Role func(childComplexity int) int + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + Identity func(childComplexity int) int + LastSession func(childComplexity int) int + Organization func(childComplexity int) int + Permissions func(childComplexity int) int + Profile func(childComplexity int) int + Role func(childComplexity int) int } MembershipConnection struct { @@ -394,13 +369,13 @@ type ComplexityRoot struct { } Session struct { - CreatedAt func(childComplexity int) int - ExpiresAt func(childComplexity int) int - ID func(childComplexity int) int - IPAddress func(childComplexity int) int - IdentityID func(childComplexity int) int - UpdatedAt func(childComplexity int) int - UserAgent func(childComplexity int) int + CreatedAt func(childComplexity int) int + ExpiresAt func(childComplexity int) int + ID func(childComplexity int) int + IPAddress func(childComplexity int) int + Identity func(childComplexity int) int + UpdatedAt func(childComplexity int) int + UserAgent func(childComplexity int) int } SessionConnection struct { @@ -414,13 +389,6 @@ type ComplexityRoot struct { Node func(childComplexity int) int } - SessionPolicy struct { - IdleTimeoutMinutes func(childComplexity int) int - MaxConcurrentSessions func(childComplexity int) int - MaxSessionDurationHours func(childComplexity int) int - RequireReauthForSensitiveActions func(childComplexity int) int - } - SignInPayload struct { Identity func(childComplexity int) int Session func(childComplexity int) int @@ -460,6 +428,7 @@ type ComplexityRoot struct { } type IdentityResolver interface { + DefaultProfile(ctx context.Context, obj *types.Identity) (*types.IdentityProfile, error) Memberships(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MembershipOrderBy) (*types.MembershipConnection, error) PendingInvitations(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.InvitationOrderBy) (*types.InvitationConnection, error) Sessions(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) (*types.SessionConnection, error) @@ -473,6 +442,7 @@ type InvitationConnectionResolver interface { } type MembershipResolver interface { Identity(ctx context.Context, obj *types.Membership) (*types.Identity, error) + Profile(ctx context.Context, obj *types.Membership) (*types.IdentityProfile, error) Organization(ctx context.Context, obj *types.Membership) (*types.Organization, error) LastSession(ctx context.Context, obj *types.Membership) (*types.Session, error) @@ -528,6 +498,9 @@ type QueryResolver interface { type SAMLConfigurationConnectionResolver interface { TotalCount(ctx context.Context, obj *types.SAMLConfigurationConnection) (*int, error) } +type SessionResolver interface { + Identity(ctx context.Context, obj *types.Session) (*types.Identity, error) +} type SessionConnectionResolver interface { TotalCount(ctx context.Context, obj *types.SessionConnection) (*int, error) } @@ -637,19 +610,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.CreateSAMLConfigurationPayload.SamlConfigurationEdge(childComplexity), true - case "CustomAttribute.key": - if e.complexity.CustomAttribute.Key == nil { - break - } - - return e.complexity.CustomAttribute.Key(childComplexity), true - case "CustomAttribute.value": - if e.complexity.CustomAttribute.Value == nil { - break - } - - return e.complexity.CustomAttribute.Value(childComplexity), true - case "DeactivateAccountPayload.success": if e.complexity.DeactivateAccountPayload.Success == nil { break @@ -657,13 +617,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.DeactivateAccountPayload.Success(childComplexity), true - case "DeleteAccountPayload.success": - if e.complexity.DeleteAccountPayload.Success == nil { - break - } - - return e.complexity.DeleteAccountPayload.Success(childComplexity), true - case "DeleteInvitationPayload.deletedInvitationId": if e.complexity.DeleteInvitationPayload.DeletedInvitationID == nil { break @@ -705,6 +658,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Identity.CreatedAt(childComplexity), true + case "Identity.defaultProfile": + if e.complexity.Identity.DefaultProfile == nil { + break + } + + return e.complexity.Identity.DefaultProfile(childComplexity), true case "Identity.email": if e.complexity.Identity.Email == nil { break @@ -756,17 +715,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Identity.PersonalAPIKeys(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey)), true - case "Identity.profileFor": - if e.complexity.Identity.ProfileFor == nil { - break - } - - args, err := ec.field_Identity_profileFor_args(ctx, rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Identity.ProfileFor(childComplexity, args["organizationId"].(gid.GID)), true case "Identity.sessions": if e.complexity.Identity.Sessions == nil { break @@ -785,48 +733,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Identity.UpdatedAt(childComplexity), true - case "IdentityProfile.avatarUrl": - if e.complexity.IdentityProfile.AvatarURL == nil { - break - } - - return e.complexity.IdentityProfile.AvatarURL(childComplexity), true case "IdentityProfile.createdAt": if e.complexity.IdentityProfile.CreatedAt == nil { break } return e.complexity.IdentityProfile.CreatedAt(childComplexity), true - case "IdentityProfile.customAttributes": - if e.complexity.IdentityProfile.CustomAttributes == nil { + case "IdentityProfile.fullName": + if e.complexity.IdentityProfile.FullName == nil { break } - return e.complexity.IdentityProfile.CustomAttributes(childComplexity), true - case "IdentityProfile.department": - if e.complexity.IdentityProfile.Department == nil { - break - } - - return e.complexity.IdentityProfile.Department(childComplexity), true - case "IdentityProfile.displayName": - if e.complexity.IdentityProfile.DisplayName == nil { - break - } - - return e.complexity.IdentityProfile.DisplayName(childComplexity), true - case "IdentityProfile.externalId": - if e.complexity.IdentityProfile.ExternalID == nil { - break - } - - return e.complexity.IdentityProfile.ExternalID(childComplexity), true - case "IdentityProfile.firstName": - if e.complexity.IdentityProfile.FirstName == nil { - break - } - - return e.complexity.IdentityProfile.FirstName(childComplexity), true + return e.complexity.IdentityProfile.FullName(childComplexity), true case "IdentityProfile.id": if e.complexity.IdentityProfile.ID == nil { break @@ -839,54 +757,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.IdentityProfile.Identity(childComplexity), true - case "IdentityProfile.jobTitle": - if e.complexity.IdentityProfile.JobTitle == nil { - break - } - - return e.complexity.IdentityProfile.JobTitle(childComplexity), true - case "IdentityProfile.lastName": - if e.complexity.IdentityProfile.LastName == nil { - break - } - - return e.complexity.IdentityProfile.LastName(childComplexity), true - case "IdentityProfile.locale": - if e.complexity.IdentityProfile.Locale == nil { - break - } - - return e.complexity.IdentityProfile.Locale(childComplexity), true - case "IdentityProfile.manager": - if e.complexity.IdentityProfile.Manager == nil { - break - } - - return e.complexity.IdentityProfile.Manager(childComplexity), true - case "IdentityProfile.organization": - if e.complexity.IdentityProfile.Organization == nil { - break - } - - return e.complexity.IdentityProfile.Organization(childComplexity), true - case "IdentityProfile.phoneNumber": - if e.complexity.IdentityProfile.PhoneNumber == nil { - break - } - - return e.complexity.IdentityProfile.PhoneNumber(childComplexity), true - case "IdentityProfile.provisionedBy": - if e.complexity.IdentityProfile.ProvisionedBy == nil { - break - } - - return e.complexity.IdentityProfile.ProvisionedBy(childComplexity), true - case "IdentityProfile.timezone": - if e.complexity.IdentityProfile.Timezone == nil { - break - } - - return e.complexity.IdentityProfile.Timezone(childComplexity), true case "IdentityProfile.updatedAt": if e.complexity.IdentityProfile.UpdatedAt == nil { break @@ -982,12 +852,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.InviteMemberPayload.InvitationEdge(childComplexity), true - case "Membership.active": - if e.complexity.Membership.Active == nil { - break - } - - return e.complexity.Membership.Active(childComplexity), true case "Membership.createdAt": if e.complexity.Membership.CreatedAt == nil { break @@ -1006,24 +870,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Membership.Identity(childComplexity), true - case "Membership.identityId": - if e.complexity.Membership.IdentityID == nil { - break - } - - return e.complexity.Membership.IdentityID(childComplexity), true case "Membership.lastSession": if e.complexity.Membership.LastSession == nil { break } return e.complexity.Membership.LastSession(childComplexity), true - case "Membership.lastSyncedAt": - if e.complexity.Membership.LastSyncedAt == nil { - break - } - - return e.complexity.Membership.LastSyncedAt(childComplexity), true case "Membership.organization": if e.complexity.Membership.Organization == nil { break @@ -1042,12 +894,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Membership.Profile(childComplexity), true - case "Membership.provisionedBy": - if e.complexity.Membership.ProvisionedBy == nil { - break - } - - return e.complexity.Membership.ProvisionedBy(childComplexity), true case "Membership.role": if e.complexity.Membership.Role == nil { break @@ -1919,12 +1765,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Session.IPAddress(childComplexity), true - case "Session.identityId": - if e.complexity.Session.IdentityID == nil { + case "Session.identity": + if e.complexity.Session.Identity == nil { break } - return e.complexity.Session.IdentityID(childComplexity), true + return e.complexity.Session.Identity(childComplexity), true case "Session.updatedAt": if e.complexity.Session.UpdatedAt == nil { break @@ -1970,31 +1816,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.SessionEdge.Node(childComplexity), true - case "SessionPolicy.idleTimeoutMinutes": - if e.complexity.SessionPolicy.IdleTimeoutMinutes == nil { - break - } - - return e.complexity.SessionPolicy.IdleTimeoutMinutes(childComplexity), true - case "SessionPolicy.maxConcurrentSessions": - if e.complexity.SessionPolicy.MaxConcurrentSessions == nil { - break - } - - return e.complexity.SessionPolicy.MaxConcurrentSessions(childComplexity), true - case "SessionPolicy.maxSessionDurationHours": - if e.complexity.SessionPolicy.MaxSessionDurationHours == nil { - break - } - - return e.complexity.SessionPolicy.MaxSessionDurationHours(childComplexity), true - case "SessionPolicy.requireReauthForSensitiveActions": - if e.complexity.SessionPolicy.RequireReauthForSensitiveActions == nil { - break - } - - return e.complexity.SessionPolicy.RequireReauthForSensitiveActions(childComplexity), true - case "SignInPayload.identity": if e.complexity.SignInPayload.Identity == nil { break @@ -2073,15 +1894,12 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( ec.unmarshalInputAcceptInvitationInput, - ec.unmarshalInputAddIPAllowlistEntryInput, ec.unmarshalInputAssumeOrganizationSessionInput, ec.unmarshalInputChangeEmailInput, ec.unmarshalInputChangePasswordInput, ec.unmarshalInputCreateOrganizationInput, ec.unmarshalInputCreatePersonalAPIKeyInput, ec.unmarshalInputCreateSAMLConfigurationInput, - ec.unmarshalInputDeactivateAccountInput, - ec.unmarshalInputDeleteAccountInput, ec.unmarshalInputDeleteInvitationInput, ec.unmarshalInputDeleteOrganizationHorizontalLogoInput, ec.unmarshalInputDeleteOrganizationInput, @@ -2090,14 +1908,12 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputInvitationOrder, ec.unmarshalInputInviteMemberInput, ec.unmarshalInputMembershipOrder, - ec.unmarshalInputRemoveIPAllowlistEntryInput, ec.unmarshalInputRemoveMemberInput, ec.unmarshalInputResetPasswordInput, ec.unmarshalInputRevokePersonalAPIKeyInput, ec.unmarshalInputRevokeSessionInput, ec.unmarshalInputSAMLAttributeMappingsInput, ec.unmarshalInputSessionOrder, - ec.unmarshalInputSessionPolicyInput, ec.unmarshalInputSignInInput, ec.unmarshalInputSignUpFromInvitationInput, ec.unmarshalInputSignUpInput, @@ -2343,6 +2159,8 @@ type Identity implements Node { createdAt: Datetime! updatedAt: Datetime! + defaultProfile: IdentityProfile @goField(forceResolver: true) @isViewer + memberships( first: Int after: CursorKey @@ -2373,36 +2191,16 @@ type Identity implements Node { last: Int before: CursorKey ): PersonalAPIKeyConnection @goField(forceResolver: true) @isViewer - - profileFor(organizationId: ID!): IdentityProfile @isViewer } type IdentityProfile implements Node { id: ID! - displayName: String! - firstName: String - lastName: String - jobTitle: String - department: String - phoneNumber: String - avatarUrl: String - manager: IdentityProfile - timezone: String - locale: String - customAttributes: [CustomAttribute!]! - provisionedBy: ProvisioningSource! - externalId: String + fullName: String! identity: Identity! - organization: Organization! createdAt: Datetime! updatedAt: Datetime! } -type CustomAttribute { - key: String! - value: String! -} - type Organization implements Node { id: ID! name: String! @@ -2453,16 +2251,12 @@ enum MembershipRole type Membership implements Node { id: ID! - identityId: ID! createdAt: Datetime! - profile: IdentityProfile! identity: Identity @goField(forceResolver: true) + profile: IdentityProfile @goField(forceResolver: true) @isViewer organization: Organization @goField(forceResolver: true) role: MembershipRole! permissions: [Permission!]! - provisionedBy: ProvisioningSource! - active: Boolean! - lastSyncedAt: Datetime lastSession: Session @goField(forceResolver: true) @isViewer } @@ -2480,7 +2274,7 @@ type Invitation implements Node { type Session implements Node { id: ID! - identityId: ID! + identity: Identity @goField(forceResolver: true) @isViewer ipAddress: String! userAgent: String! updatedAt: Datetime! @@ -2520,13 +2314,6 @@ type Application { availableAccessLevels: [AccessLevel!]! } -type SessionPolicy { - maxSessionDurationHours: Int! - idleTimeoutMinutes: Int! - maxConcurrentSessions: Int - requireReauthForSensitiveActions: Boolean! -} - type SAMLConfiguration implements Node { id: ID! emailDomain: String! @@ -2603,12 +2390,6 @@ enum SAMLEnforcementPolicy ) } -enum AuthMethod { - PASSWORD - SAML - RECOVERY_CODE -} - enum TokenScope { READ_ORGANIZATION WRITE_ORGANIZATION @@ -2625,12 +2406,6 @@ enum TokenScope { ADMIN } -enum ProvisioningSource { - MANUAL - INVITATION - SAML -} - enum ReauthenticationReason { SESSION_EXPIRED SENSITIVE_ACTION @@ -2803,25 +2578,9 @@ input AssumeOrganizationSessionInput { organizationId: ID! } -input DeactivateAccountInput { - password: String! -} - -input DeleteAccountInput { - password: String! - confirmation: String! -} - input UpdateIdentityProfileInput { membershipId: ID! - displayName: String - firstName: String - lastName: String - jobTitle: String - department: String - phoneNumber: String - timezone: String - locale: String + fullName: String } input RevokeSessionInput { @@ -3003,10 +2762,6 @@ type DeactivateAccountPayload { success: Boolean! } -type DeleteAccountPayload { - success: Boolean! -} - type UpdateIdentityProfilePayload { profile: IdentityProfile } @@ -3183,17 +2938,6 @@ func (ec *executionContext) field_Identity_personalAPIKeys_args(ctx context.Cont return args, nil } -func (ec *executionContext) field_Identity_profileFor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { - var err error - args := map[string]any{} - arg0, err := graphql.ProcessArgField(ctx, rawArgs, "organizationId", ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID) - if err != nil { - return nil, err - } - args["organizationId"] = arg0 - return args, nil -} - func (ec *executionContext) field_Identity_sessions_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -4099,64 +3843,6 @@ func (ec *executionContext) fieldContext_CreateSAMLConfigurationPayload_samlConf return fc, nil } -func (ec *executionContext) _CustomAttribute_key(ctx context.Context, field graphql.CollectedField, obj *types.CustomAttribute) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_CustomAttribute_key, - func(ctx context.Context) (any, error) { - return obj.Key, nil - }, - nil, - ec.marshalNString2string, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_CustomAttribute_key(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "CustomAttribute", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _CustomAttribute_value(ctx context.Context, field graphql.CollectedField, obj *types.CustomAttribute) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_CustomAttribute_value, - func(ctx context.Context) (any, error) { - return obj.Value, nil - }, - nil, - ec.marshalNString2string, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_CustomAttribute_value(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "CustomAttribute", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _DeactivateAccountPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.DeactivateAccountPayload) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -4186,35 +3872,6 @@ func (ec *executionContext) fieldContext_DeactivateAccountPayload_success(_ cont return fc, nil } -func (ec *executionContext) _DeleteAccountPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.DeleteAccountPayload) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_DeleteAccountPayload_success, - func(ctx context.Context) (any, error) { - return obj.Success, nil - }, - nil, - ec.marshalNBoolean2bool, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_DeleteAccountPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DeleteAccountPayload", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _DeleteInvitationPayload_deletedInvitationId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteInvitationPayload) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -4535,6 +4192,60 @@ func (ec *executionContext) fieldContext_Identity_updatedAt(_ context.Context, f return fc, nil } +func (ec *executionContext) _Identity_defaultProfile(ctx context.Context, field graphql.CollectedField, obj *types.Identity) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + ec.fieldContext_Identity_defaultProfile, + func(ctx context.Context) (any, error) { + return ec.resolvers.Identity().DefaultProfile(ctx, obj) + }, + func(ctx context.Context, next graphql.Resolver) graphql.Resolver { + directive0 := next + + directive1 := func(ctx context.Context) (any, error) { + if ec.directives.IsViewer == nil { + var zeroVal *types.IdentityProfile + return zeroVal, errors.New("directive isViewer is not implemented") + } + return ec.directives.IsViewer(ctx, obj, directive0) + } + + next = directive1 + return next + }, + ec.marshalOIdentityProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentityProfile, + true, + false, + ) +} + +func (ec *executionContext) fieldContext_Identity_defaultProfile(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Identity", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_IdentityProfile_id(ctx, field) + case "fullName": + return ec.fieldContext_IdentityProfile_fullName(ctx, field) + case "identity": + return ec.fieldContext_IdentityProfile_identity(ctx, field) + case "createdAt": + return ec.fieldContext_IdentityProfile_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_IdentityProfile_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type IdentityProfile", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Identity_memberships(ctx context.Context, field graphql.CollectedField, obj *types.Identity) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -4783,97 +4494,6 @@ func (ec *executionContext) fieldContext_Identity_personalAPIKeys(ctx context.Co return fc, nil } -func (ec *executionContext) _Identity_profileFor(ctx context.Context, field graphql.CollectedField, obj *types.Identity) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_Identity_profileFor, - func(ctx context.Context) (any, error) { - return obj.ProfileFor, nil - }, - func(ctx context.Context, next graphql.Resolver) graphql.Resolver { - directive0 := next - - directive1 := func(ctx context.Context) (any, error) { - if ec.directives.IsViewer == nil { - var zeroVal *types.IdentityProfile - return zeroVal, errors.New("directive isViewer is not implemented") - } - return ec.directives.IsViewer(ctx, obj, directive0) - } - - next = directive1 - return next - }, - ec.marshalOIdentityProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentityProfile, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_Identity_profileFor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Identity", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_IdentityProfile_id(ctx, field) - case "displayName": - return ec.fieldContext_IdentityProfile_displayName(ctx, field) - case "firstName": - return ec.fieldContext_IdentityProfile_firstName(ctx, field) - case "lastName": - return ec.fieldContext_IdentityProfile_lastName(ctx, field) - case "jobTitle": - return ec.fieldContext_IdentityProfile_jobTitle(ctx, field) - case "department": - return ec.fieldContext_IdentityProfile_department(ctx, field) - case "phoneNumber": - return ec.fieldContext_IdentityProfile_phoneNumber(ctx, field) - case "avatarUrl": - return ec.fieldContext_IdentityProfile_avatarUrl(ctx, field) - case "manager": - return ec.fieldContext_IdentityProfile_manager(ctx, field) - case "timezone": - return ec.fieldContext_IdentityProfile_timezone(ctx, field) - case "locale": - return ec.fieldContext_IdentityProfile_locale(ctx, field) - case "customAttributes": - return ec.fieldContext_IdentityProfile_customAttributes(ctx, field) - case "provisionedBy": - return ec.fieldContext_IdentityProfile_provisionedBy(ctx, field) - case "externalId": - return ec.fieldContext_IdentityProfile_externalId(ctx, field) - case "identity": - return ec.fieldContext_IdentityProfile_identity(ctx, field) - case "organization": - return ec.fieldContext_IdentityProfile_organization(ctx, field) - case "createdAt": - return ec.fieldContext_IdentityProfile_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_IdentityProfile_updatedAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type IdentityProfile", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Identity_profileFor_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - func (ec *executionContext) _IdentityProfile_id(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -4903,14 +4523,14 @@ func (ec *executionContext) fieldContext_IdentityProfile_id(_ context.Context, f return fc, nil } -func (ec *executionContext) _IdentityProfile_displayName(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { +func (ec *executionContext) _IdentityProfile_fullName(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, - ec.fieldContext_IdentityProfile_displayName, + ec.fieldContext_IdentityProfile_fullName, func(ctx context.Context) (any, error) { - return obj.DisplayName, nil + return obj.FullName, nil }, nil, ec.marshalNString2string, @@ -4919,399 +4539,7 @@ func (ec *executionContext) _IdentityProfile_displayName(ctx context.Context, fi ) } -func (ec *executionContext) fieldContext_IdentityProfile_displayName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_firstName(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_firstName, - func(ctx context.Context) (any, error) { - return obj.FirstName, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_firstName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_lastName(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_lastName, - func(ctx context.Context) (any, error) { - return obj.LastName, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_lastName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_jobTitle(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_jobTitle, - func(ctx context.Context) (any, error) { - return obj.JobTitle, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_jobTitle(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_department(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_department, - func(ctx context.Context) (any, error) { - return obj.Department, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_department(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_phoneNumber(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_phoneNumber, - func(ctx context.Context) (any, error) { - return obj.PhoneNumber, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_phoneNumber(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_avatarUrl(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_avatarUrl, - func(ctx context.Context) (any, error) { - return obj.AvatarURL, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_avatarUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_manager(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_manager, - func(ctx context.Context) (any, error) { - return obj.Manager, nil - }, - nil, - ec.marshalOIdentityProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentityProfile, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_manager(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_IdentityProfile_id(ctx, field) - case "displayName": - return ec.fieldContext_IdentityProfile_displayName(ctx, field) - case "firstName": - return ec.fieldContext_IdentityProfile_firstName(ctx, field) - case "lastName": - return ec.fieldContext_IdentityProfile_lastName(ctx, field) - case "jobTitle": - return ec.fieldContext_IdentityProfile_jobTitle(ctx, field) - case "department": - return ec.fieldContext_IdentityProfile_department(ctx, field) - case "phoneNumber": - return ec.fieldContext_IdentityProfile_phoneNumber(ctx, field) - case "avatarUrl": - return ec.fieldContext_IdentityProfile_avatarUrl(ctx, field) - case "manager": - return ec.fieldContext_IdentityProfile_manager(ctx, field) - case "timezone": - return ec.fieldContext_IdentityProfile_timezone(ctx, field) - case "locale": - return ec.fieldContext_IdentityProfile_locale(ctx, field) - case "customAttributes": - return ec.fieldContext_IdentityProfile_customAttributes(ctx, field) - case "provisionedBy": - return ec.fieldContext_IdentityProfile_provisionedBy(ctx, field) - case "externalId": - return ec.fieldContext_IdentityProfile_externalId(ctx, field) - case "identity": - return ec.fieldContext_IdentityProfile_identity(ctx, field) - case "organization": - return ec.fieldContext_IdentityProfile_organization(ctx, field) - case "createdAt": - return ec.fieldContext_IdentityProfile_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_IdentityProfile_updatedAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type IdentityProfile", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_timezone(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_timezone, - func(ctx context.Context) (any, error) { - return obj.Timezone, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_timezone(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_locale(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_locale, - func(ctx context.Context) (any, error) { - return obj.Locale, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_locale(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_customAttributes(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_customAttributes, - func(ctx context.Context) (any, error) { - return obj.CustomAttributes, nil - }, - nil, - ec.marshalNCustomAttribute2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐCustomAttributeᚄ, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_customAttributes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "key": - return ec.fieldContext_CustomAttribute_key(ctx, field) - case "value": - return ec.fieldContext_CustomAttribute_value(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type CustomAttribute", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_provisionedBy(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_provisionedBy, - func(ctx context.Context) (any, error) { - return obj.ProvisionedBy, nil - }, - nil, - ec.marshalNProvisioningSource2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProvisioningSource, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_provisionedBy(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ProvisioningSource does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _IdentityProfile_externalId(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_externalId, - func(ctx context.Context) (any, error) { - return obj.ExternalID, nil - }, - nil, - ec.marshalOString2ᚖstring, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_externalId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_IdentityProfile_fullName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "IdentityProfile", Field: field, @@ -5358,6 +4586,8 @@ func (ec *executionContext) fieldContext_IdentityProfile_identity(_ context.Cont return ec.fieldContext_Identity_createdAt(ctx, field) case "updatedAt": return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) case "memberships": return ec.fieldContext_Identity_memberships(ctx, field) case "pendingInvitations": @@ -5366,8 +4596,6 @@ func (ec *executionContext) fieldContext_IdentityProfile_identity(_ context.Cont return ec.fieldContext_Identity_sessions(ctx, field) case "personalAPIKeys": return ec.fieldContext_Identity_personalAPIKeys(ctx, field) - case "profileFor": - return ec.fieldContext_Identity_profileFor(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, @@ -5375,65 +4603,6 @@ func (ec *executionContext) fieldContext_IdentityProfile_identity(_ context.Cont return fc, nil } -func (ec *executionContext) _IdentityProfile_organization(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_IdentityProfile_organization, - func(ctx context.Context) (any, error) { - return obj.Organization, nil - }, - nil, - ec.marshalNOrganization2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐOrganization, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_IdentityProfile_organization(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "IdentityProfile", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Organization_id(ctx, field) - case "name": - return ec.fieldContext_Organization_name(ctx, field) - case "logoUrl": - return ec.fieldContext_Organization_logoUrl(ctx, field) - case "horizontalLogoUrl": - return ec.fieldContext_Organization_horizontalLogoUrl(ctx, field) - case "email": - return ec.fieldContext_Organization_email(ctx, field) - case "description": - return ec.fieldContext_Organization_description(ctx, field) - case "websiteUrl": - return ec.fieldContext_Organization_websiteUrl(ctx, field) - case "headquarterAddress": - return ec.fieldContext_Organization_headquarterAddress(ctx, field) - case "createdAt": - return ec.fieldContext_Organization_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_Organization_updatedAt(ctx, field) - case "members": - return ec.fieldContext_Organization_members(ctx, field) - case "invitations": - return ec.fieldContext_Organization_invitations(ctx, field) - case "samlConfigurations": - return ec.fieldContext_Organization_samlConfigurations(ctx, field) - case "availableApplications": - return ec.fieldContext_Organization_availableApplications(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _IdentityProfile_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.IdentityProfile) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -5997,35 +5166,6 @@ func (ec *executionContext) fieldContext_Membership_id(_ context.Context, field return fc, nil } -func (ec *executionContext) _Membership_identityId(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_Membership_identityId, - func(ctx context.Context) (any, error) { - return obj.IdentityID, nil - }, - nil, - ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_Membership_identityId(_ 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 ID does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _Membership_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -6055,73 +5195,6 @@ func (ec *executionContext) fieldContext_Membership_createdAt(_ context.Context, return fc, nil } -func (ec *executionContext) _Membership_profile(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_Membership_profile, - func(ctx context.Context) (any, error) { - return obj.Profile, nil - }, - nil, - ec.marshalNIdentityProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentityProfile, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_Membership_profile(_ 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) { - switch field.Name { - case "id": - return ec.fieldContext_IdentityProfile_id(ctx, field) - case "displayName": - return ec.fieldContext_IdentityProfile_displayName(ctx, field) - case "firstName": - return ec.fieldContext_IdentityProfile_firstName(ctx, field) - case "lastName": - return ec.fieldContext_IdentityProfile_lastName(ctx, field) - case "jobTitle": - return ec.fieldContext_IdentityProfile_jobTitle(ctx, field) - case "department": - return ec.fieldContext_IdentityProfile_department(ctx, field) - case "phoneNumber": - return ec.fieldContext_IdentityProfile_phoneNumber(ctx, field) - case "avatarUrl": - return ec.fieldContext_IdentityProfile_avatarUrl(ctx, field) - case "manager": - return ec.fieldContext_IdentityProfile_manager(ctx, field) - case "timezone": - return ec.fieldContext_IdentityProfile_timezone(ctx, field) - case "locale": - return ec.fieldContext_IdentityProfile_locale(ctx, field) - case "customAttributes": - return ec.fieldContext_IdentityProfile_customAttributes(ctx, field) - case "provisionedBy": - return ec.fieldContext_IdentityProfile_provisionedBy(ctx, field) - case "externalId": - return ec.fieldContext_IdentityProfile_externalId(ctx, field) - case "identity": - return ec.fieldContext_IdentityProfile_identity(ctx, field) - case "organization": - return ec.fieldContext_IdentityProfile_organization(ctx, field) - case "createdAt": - return ec.fieldContext_IdentityProfile_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_IdentityProfile_updatedAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type IdentityProfile", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _Membership_identity(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -6156,6 +5229,8 @@ func (ec *executionContext) fieldContext_Membership_identity(_ context.Context, return ec.fieldContext_Identity_createdAt(ctx, field) case "updatedAt": return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) case "memberships": return ec.fieldContext_Identity_memberships(ctx, field) case "pendingInvitations": @@ -6164,8 +5239,6 @@ func (ec *executionContext) fieldContext_Membership_identity(_ context.Context, return ec.fieldContext_Identity_sessions(ctx, field) case "personalAPIKeys": return ec.fieldContext_Identity_personalAPIKeys(ctx, field) - case "profileFor": - return ec.fieldContext_Identity_profileFor(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, @@ -6173,6 +5246,60 @@ func (ec *executionContext) fieldContext_Membership_identity(_ context.Context, return fc, nil } +func (ec *executionContext) _Membership_profile(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + ec.fieldContext_Membership_profile, + func(ctx context.Context) (any, error) { + return ec.resolvers.Membership().Profile(ctx, obj) + }, + func(ctx context.Context, next graphql.Resolver) graphql.Resolver { + directive0 := next + + directive1 := func(ctx context.Context) (any, error) { + if ec.directives.IsViewer == nil { + var zeroVal *types.IdentityProfile + return zeroVal, errors.New("directive isViewer is not implemented") + } + return ec.directives.IsViewer(ctx, obj, directive0) + } + + next = directive1 + return next + }, + ec.marshalOIdentityProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentityProfile, + true, + false, + ) +} + +func (ec *executionContext) fieldContext_Membership_profile(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Membership", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_IdentityProfile_id(ctx, field) + case "fullName": + return ec.fieldContext_IdentityProfile_fullName(ctx, field) + case "identity": + return ec.fieldContext_IdentityProfile_identity(ctx, field) + case "createdAt": + return ec.fieldContext_IdentityProfile_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_IdentityProfile_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type IdentityProfile", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Membership_organization(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -6306,93 +5433,6 @@ func (ec *executionContext) fieldContext_Membership_permissions(_ context.Contex return fc, nil } -func (ec *executionContext) _Membership_provisionedBy(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_Membership_provisionedBy, - func(ctx context.Context) (any, error) { - return obj.ProvisionedBy, nil - }, - nil, - ec.marshalNProvisioningSource2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProvisioningSource, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_Membership_provisionedBy(_ 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 ProvisioningSource does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Membership_active(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_Membership_active, - func(ctx context.Context) (any, error) { - return obj.Active, nil - }, - nil, - ec.marshalNBoolean2bool, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_Membership_active(_ 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 Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Membership_lastSyncedAt(ctx context.Context, field graphql.CollectedField, obj *types.Membership) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_Membership_lastSyncedAt, - func(ctx context.Context) (any, error) { - return obj.LastSyncedAt, nil - }, - nil, - ec.marshalODatetime2ᚖtimeᚐTime, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_Membership_lastSyncedAt(_ 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 Datetime 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, @@ -6432,8 +5472,8 @@ func (ec *executionContext) fieldContext_Membership_lastSession(_ context.Contex switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) - case "identityId": - return ec.fieldContext_Session_identityId(ctx, field) + case "identity": + return ec.fieldContext_Session_identity(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -6580,26 +5620,18 @@ func (ec *executionContext) fieldContext_MembershipEdge_node(_ context.Context, switch field.Name { case "id": return ec.fieldContext_Membership_id(ctx, field) - case "identityId": - return ec.fieldContext_Membership_identityId(ctx, field) case "createdAt": return ec.fieldContext_Membership_createdAt(ctx, field) - case "profile": - return ec.fieldContext_Membership_profile(ctx, field) case "identity": return ec.fieldContext_Membership_identity(ctx, field) + case "profile": + return ec.fieldContext_Membership_profile(ctx, field) case "organization": return ec.fieldContext_Membership_organization(ctx, field) case "role": return ec.fieldContext_Membership_role(ctx, field) case "permissions": return ec.fieldContext_Membership_permissions(ctx, field) - case "provisionedBy": - return ec.fieldContext_Membership_provisionedBy(ctx, field) - case "active": - return ec.fieldContext_Membership_active(ctx, field) - case "lastSyncedAt": - return ec.fieldContext_Membership_lastSyncedAt(ctx, field) case "lastSession": return ec.fieldContext_Membership_lastSession(ctx, field) } @@ -8823,8 +7855,8 @@ func (ec *executionContext) fieldContext_OrganizationSessionCreated_session(_ co switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) - case "identityId": - return ec.fieldContext_Session_identityId(ctx, field) + case "identity": + return ec.fieldContext_Session_identity(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -8868,26 +7900,18 @@ func (ec *executionContext) fieldContext_OrganizationSessionCreated_membership(_ switch field.Name { case "id": return ec.fieldContext_Membership_id(ctx, field) - case "identityId": - return ec.fieldContext_Membership_identityId(ctx, field) case "createdAt": return ec.fieldContext_Membership_createdAt(ctx, field) - case "profile": - return ec.fieldContext_Membership_profile(ctx, field) case "identity": return ec.fieldContext_Membership_identity(ctx, field) + case "profile": + return ec.fieldContext_Membership_profile(ctx, field) case "organization": return ec.fieldContext_Membership_organization(ctx, field) case "role": return ec.fieldContext_Membership_role(ctx, field) case "permissions": return ec.fieldContext_Membership_permissions(ctx, field) - case "provisionedBy": - return ec.fieldContext_Membership_provisionedBy(ctx, field) - case "active": - return ec.fieldContext_Membership_active(ctx, field) - case "lastSyncedAt": - return ec.fieldContext_Membership_lastSyncedAt(ctx, field) case "lastSession": return ec.fieldContext_Membership_lastSession(ctx, field) } @@ -9874,6 +8898,8 @@ func (ec *executionContext) fieldContext_Query_viewer(_ context.Context, field g return ec.fieldContext_Identity_createdAt(ctx, field) case "updatedAt": return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) case "memberships": return ec.fieldContext_Identity_memberships(ctx, field) case "pendingInvitations": @@ -9882,8 +8908,6 @@ func (ec *executionContext) fieldContext_Query_viewer(_ context.Context, field g return ec.fieldContext_Identity_sessions(ctx, field) case "personalAPIKeys": return ec.fieldContext_Identity_personalAPIKeys(ctx, field) - case "profileFor": - return ec.fieldContext_Identity_profileFor(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, @@ -11145,30 +10169,65 @@ func (ec *executionContext) fieldContext_Session_id(_ context.Context, field gra return fc, nil } -func (ec *executionContext) _Session_identityId(ctx context.Context, field graphql.CollectedField, obj *types.Session) (ret graphql.Marshaler) { +func (ec *executionContext) _Session_identity(ctx context.Context, field graphql.CollectedField, obj *types.Session) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, - ec.fieldContext_Session_identityId, + ec.fieldContext_Session_identity, func(ctx context.Context) (any, error) { - return obj.IdentityID, nil + return ec.resolvers.Session().Identity(ctx, obj) }, - nil, - ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID, - true, + func(ctx context.Context, next graphql.Resolver) graphql.Resolver { + directive0 := next + + directive1 := func(ctx context.Context) (any, error) { + if ec.directives.IsViewer == nil { + var zeroVal *types.Identity + return zeroVal, errors.New("directive isViewer is not implemented") + } + return ec.directives.IsViewer(ctx, obj, directive0) + } + + next = directive1 + return next + }, + ec.marshalOIdentity2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentity, true, + false, ) } -func (ec *executionContext) fieldContext_Session_identityId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Session_identity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Session", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_Identity_id(ctx, field) + case "email": + return ec.fieldContext_Identity_email(ctx, field) + case "emailVerified": + return ec.fieldContext_Identity_emailVerified(ctx, field) + case "createdAt": + return ec.fieldContext_Identity_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) + case "memberships": + return ec.fieldContext_Identity_memberships(ctx, field) + case "pendingInvitations": + return ec.fieldContext_Identity_pendingInvitations(ctx, field) + case "sessions": + return ec.fieldContext_Identity_sessions(ctx, field) + case "personalAPIKeys": + return ec.fieldContext_Identity_personalAPIKeys(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, } return fc, nil @@ -11448,8 +10507,8 @@ func (ec *executionContext) fieldContext_SessionEdge_node(_ context.Context, fie switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) - case "identityId": - return ec.fieldContext_Session_identityId(ctx, field) + case "identity": + return ec.fieldContext_Session_identity(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -11496,122 +10555,6 @@ func (ec *executionContext) fieldContext_SessionEdge_cursor(_ context.Context, f return fc, nil } -func (ec *executionContext) _SessionPolicy_maxSessionDurationHours(ctx context.Context, field graphql.CollectedField, obj *types.SessionPolicy) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_SessionPolicy_maxSessionDurationHours, - func(ctx context.Context) (any, error) { - return obj.MaxSessionDurationHours, nil - }, - nil, - ec.marshalNInt2int, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_SessionPolicy_maxSessionDurationHours(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "SessionPolicy", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _SessionPolicy_idleTimeoutMinutes(ctx context.Context, field graphql.CollectedField, obj *types.SessionPolicy) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_SessionPolicy_idleTimeoutMinutes, - func(ctx context.Context) (any, error) { - return obj.IdleTimeoutMinutes, nil - }, - nil, - ec.marshalNInt2int, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_SessionPolicy_idleTimeoutMinutes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "SessionPolicy", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _SessionPolicy_maxConcurrentSessions(ctx context.Context, field graphql.CollectedField, obj *types.SessionPolicy) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_SessionPolicy_maxConcurrentSessions, - func(ctx context.Context) (any, error) { - return obj.MaxConcurrentSessions, nil - }, - nil, - ec.marshalOInt2ᚖint, - true, - false, - ) -} - -func (ec *executionContext) fieldContext_SessionPolicy_maxConcurrentSessions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "SessionPolicy", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _SessionPolicy_requireReauthForSensitiveActions(ctx context.Context, field graphql.CollectedField, obj *types.SessionPolicy) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_SessionPolicy_requireReauthForSensitiveActions, - func(ctx context.Context) (any, error) { - return obj.RequireReauthForSensitiveActions, nil - }, - nil, - ec.marshalNBoolean2bool, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_SessionPolicy_requireReauthForSensitiveActions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "SessionPolicy", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _SignInPayload_identity(ctx context.Context, field graphql.CollectedField, obj *types.SignInPayload) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -11646,6 +10589,8 @@ func (ec *executionContext) fieldContext_SignInPayload_identity(_ context.Contex return ec.fieldContext_Identity_createdAt(ctx, field) case "updatedAt": return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) case "memberships": return ec.fieldContext_Identity_memberships(ctx, field) case "pendingInvitations": @@ -11654,8 +10599,6 @@ func (ec *executionContext) fieldContext_SignInPayload_identity(_ context.Contex return ec.fieldContext_Identity_sessions(ctx, field) case "personalAPIKeys": return ec.fieldContext_Identity_personalAPIKeys(ctx, field) - case "profileFor": - return ec.fieldContext_Identity_profileFor(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, @@ -11689,8 +10632,8 @@ func (ec *executionContext) fieldContext_SignInPayload_session(_ context.Context switch field.Name { case "id": return ec.fieldContext_Session_id(ctx, field) - case "identityId": - return ec.fieldContext_Session_identityId(ctx, field) + case "identity": + return ec.fieldContext_Session_identity(ctx, field) case "ipAddress": return ec.fieldContext_Session_ipAddress(ctx, field) case "userAgent": @@ -11771,6 +10714,8 @@ func (ec *executionContext) fieldContext_SignUpFromInvitationPayload_identity(_ return ec.fieldContext_Identity_createdAt(ctx, field) case "updatedAt": return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) case "memberships": return ec.fieldContext_Identity_memberships(ctx, field) case "pendingInvitations": @@ -11779,8 +10724,6 @@ func (ec *executionContext) fieldContext_SignUpFromInvitationPayload_identity(_ return ec.fieldContext_Identity_sessions(ctx, field) case "personalAPIKeys": return ec.fieldContext_Identity_personalAPIKeys(ctx, field) - case "profileFor": - return ec.fieldContext_Identity_profileFor(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, @@ -11822,6 +10765,8 @@ func (ec *executionContext) fieldContext_SignUpPayload_identity(_ context.Contex return ec.fieldContext_Identity_createdAt(ctx, field) case "updatedAt": return ec.fieldContext_Identity_updatedAt(ctx, field) + case "defaultProfile": + return ec.fieldContext_Identity_defaultProfile(ctx, field) case "memberships": return ec.fieldContext_Identity_memberships(ctx, field) case "pendingInvitations": @@ -11830,8 +10775,6 @@ func (ec *executionContext) fieldContext_SignUpPayload_identity(_ context.Contex return ec.fieldContext_Identity_sessions(ctx, field) case "personalAPIKeys": return ec.fieldContext_Identity_personalAPIKeys(ctx, field) - case "profileFor": - return ec.fieldContext_Identity_profileFor(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Identity", field.Name) }, @@ -11865,36 +10808,10 @@ func (ec *executionContext) fieldContext_UpdateIdentityProfilePayload_profile(_ switch field.Name { case "id": return ec.fieldContext_IdentityProfile_id(ctx, field) - case "displayName": - return ec.fieldContext_IdentityProfile_displayName(ctx, field) - case "firstName": - return ec.fieldContext_IdentityProfile_firstName(ctx, field) - case "lastName": - return ec.fieldContext_IdentityProfile_lastName(ctx, field) - case "jobTitle": - return ec.fieldContext_IdentityProfile_jobTitle(ctx, field) - case "department": - return ec.fieldContext_IdentityProfile_department(ctx, field) - case "phoneNumber": - return ec.fieldContext_IdentityProfile_phoneNumber(ctx, field) - case "avatarUrl": - return ec.fieldContext_IdentityProfile_avatarUrl(ctx, field) - case "manager": - return ec.fieldContext_IdentityProfile_manager(ctx, field) - case "timezone": - return ec.fieldContext_IdentityProfile_timezone(ctx, field) - case "locale": - return ec.fieldContext_IdentityProfile_locale(ctx, field) - case "customAttributes": - return ec.fieldContext_IdentityProfile_customAttributes(ctx, field) - case "provisionedBy": - return ec.fieldContext_IdentityProfile_provisionedBy(ctx, field) - case "externalId": - return ec.fieldContext_IdentityProfile_externalId(ctx, field) + case "fullName": + return ec.fieldContext_IdentityProfile_fullName(ctx, field) case "identity": return ec.fieldContext_IdentityProfile_identity(ctx, field) - case "organization": - return ec.fieldContext_IdentityProfile_organization(ctx, field) case "createdAt": return ec.fieldContext_IdentityProfile_createdAt(ctx, field) case "updatedAt": @@ -13573,47 +12490,6 @@ func (ec *executionContext) unmarshalInputAcceptInvitationInput(ctx context.Cont return it, nil } -func (ec *executionContext) unmarshalInputAddIPAllowlistEntryInput(ctx context.Context, obj any) (types.AddIPAllowlistEntryInput, error) { - var it types.AddIPAllowlistEntryInput - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"organizationId", "cidr", "description"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "organizationId": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId")) - data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v) - if err != nil { - return it, err - } - it.OrganizationID = data - case "cidr": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("cidr")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Cidr = data - case "description": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.Description = data - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputAssumeOrganizationSessionInput(ctx context.Context, obj any) (types.AssumeOrganizationSessionInput, error) { var it types.AssumeOrganizationSessionInput asMap := map[string]any{} @@ -13860,67 +12736,6 @@ func (ec *executionContext) unmarshalInputCreateSAMLConfigurationInput(ctx conte return it, nil } -func (ec *executionContext) unmarshalInputDeactivateAccountInput(ctx context.Context, obj any) (types.DeactivateAccountInput, error) { - var it types.DeactivateAccountInput - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"password"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "password": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Password = data - } - } - - return it, nil -} - -func (ec *executionContext) unmarshalInputDeleteAccountInput(ctx context.Context, obj any) (types.DeleteAccountInput, error) { - var it types.DeleteAccountInput - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"password", "confirmation"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "password": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Password = data - case "confirmation": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("confirmation")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Confirmation = data - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputDeleteInvitationInput(ctx context.Context, obj any) (types.DeleteInvitationInput, error) { var it types.DeleteInvitationInput asMap := map[string]any{} @@ -14179,33 +12994,6 @@ func (ec *executionContext) unmarshalInputMembershipOrder(ctx context.Context, o return it, nil } -func (ec *executionContext) unmarshalInputRemoveIPAllowlistEntryInput(ctx context.Context, obj any) (types.RemoveIPAllowlistEntryInput, error) { - var it types.RemoveIPAllowlistEntryInput - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"entryId"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "entryId": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("entryId")) - data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v) - if err != nil { - return it, err - } - it.EntryID = data - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputRemoveMemberInput(ctx context.Context, obj any) (types.RemoveMemberInput, error) { var it types.RemoveMemberInput asMap := map[string]any{} @@ -14410,54 +13198,6 @@ func (ec *executionContext) unmarshalInputSessionOrder(ctx context.Context, obj return it, nil } -func (ec *executionContext) unmarshalInputSessionPolicyInput(ctx context.Context, obj any) (types.SessionPolicyInput, error) { - var it types.SessionPolicyInput - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"maxSessionDurationHours", "idleTimeoutMinutes", "maxConcurrentSessions", "requireReauthForSensitiveActions"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "maxSessionDurationHours": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("maxSessionDurationHours")) - data, err := ec.unmarshalOInt2ᚖint(ctx, v) - if err != nil { - return it, err - } - it.MaxSessionDurationHours = data - case "idleTimeoutMinutes": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("idleTimeoutMinutes")) - data, err := ec.unmarshalOInt2ᚖint(ctx, v) - if err != nil { - return it, err - } - it.IdleTimeoutMinutes = data - case "maxConcurrentSessions": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("maxConcurrentSessions")) - data, err := ec.unmarshalOInt2ᚖint(ctx, v) - if err != nil { - return it, err - } - it.MaxConcurrentSessions = data - case "requireReauthForSensitiveActions": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("requireReauthForSensitiveActions")) - data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) - if err != nil { - return it, err - } - it.RequireReauthForSensitiveActions = data - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputSignInInput(ctx context.Context, obj any) (types.SignInInput, error) { var it types.SignInInput asMap := map[string]any{} @@ -14574,7 +13314,7 @@ func (ec *executionContext) unmarshalInputUpdateIdentityProfileInput(ctx context asMap[k] = v } - fieldsInOrder := [...]string{"membershipId", "displayName", "firstName", "lastName", "jobTitle", "department", "phoneNumber", "timezone", "locale"} + fieldsInOrder := [...]string{"membershipId", "fullName"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -14588,62 +13328,13 @@ func (ec *executionContext) unmarshalInputUpdateIdentityProfileInput(ctx context return it, err } it.MembershipID = data - case "displayName": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("displayName")) + case "fullName": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fullName")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } - it.DisplayName = data - case "firstName": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("firstName")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.FirstName = data - case "lastName": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lastName")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.LastName = data - case "jobTitle": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("jobTitle")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.JobTitle = data - case "department": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("department")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.Department = data - case "phoneNumber": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phoneNumber")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.PhoneNumber = data - case "timezone": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("timezone")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.Timezone = data - case "locale": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("locale")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.Locale = data + it.FullName = data } } @@ -15314,50 +14005,6 @@ func (ec *executionContext) _CreateSAMLConfigurationPayload(ctx context.Context, return out } -var customAttributeImplementors = []string{"CustomAttribute"} - -func (ec *executionContext) _CustomAttribute(ctx context.Context, sel ast.SelectionSet, obj *types.CustomAttribute) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, customAttributeImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("CustomAttribute") - case "key": - out.Values[i] = ec._CustomAttribute_key(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "value": - out.Values[i] = ec._CustomAttribute_value(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var deactivateAccountPayloadImplementors = []string{"DeactivateAccountPayload"} func (ec *executionContext) _DeactivateAccountPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeactivateAccountPayload) graphql.Marshaler { @@ -15397,45 +14044,6 @@ func (ec *executionContext) _DeactivateAccountPayload(ctx context.Context, sel a return out } -var deleteAccountPayloadImplementors = []string{"DeleteAccountPayload"} - -func (ec *executionContext) _DeleteAccountPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteAccountPayload) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, deleteAccountPayloadImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DeleteAccountPayload") - case "success": - out.Values[i] = ec._DeleteAccountPayload_success(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var deleteInvitationPayloadImplementors = []string{"DeleteInvitationPayload"} func (ec *executionContext) _DeleteInvitationPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteInvitationPayload) graphql.Marshaler { @@ -15667,6 +14275,39 @@ func (ec *executionContext) _Identity(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "defaultProfile": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Identity_defaultProfile(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "memberships": field := field @@ -15799,8 +14440,6 @@ func (ec *executionContext) _Identity(ctx context.Context, sel ast.SelectionSet, } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - case "profileFor": - out.Values[i] = ec._Identity_profileFor(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -15840,51 +14479,16 @@ func (ec *executionContext) _IdentityProfile(ctx context.Context, sel ast.Select if out.Values[i] == graphql.Null { out.Invalids++ } - case "displayName": - out.Values[i] = ec._IdentityProfile_displayName(ctx, field, obj) + case "fullName": + out.Values[i] = ec._IdentityProfile_fullName(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "firstName": - out.Values[i] = ec._IdentityProfile_firstName(ctx, field, obj) - case "lastName": - out.Values[i] = ec._IdentityProfile_lastName(ctx, field, obj) - case "jobTitle": - out.Values[i] = ec._IdentityProfile_jobTitle(ctx, field, obj) - case "department": - out.Values[i] = ec._IdentityProfile_department(ctx, field, obj) - case "phoneNumber": - out.Values[i] = ec._IdentityProfile_phoneNumber(ctx, field, obj) - case "avatarUrl": - out.Values[i] = ec._IdentityProfile_avatarUrl(ctx, field, obj) - case "manager": - out.Values[i] = ec._IdentityProfile_manager(ctx, field, obj) - case "timezone": - out.Values[i] = ec._IdentityProfile_timezone(ctx, field, obj) - case "locale": - out.Values[i] = ec._IdentityProfile_locale(ctx, field, obj) - case "customAttributes": - out.Values[i] = ec._IdentityProfile_customAttributes(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "provisionedBy": - out.Values[i] = ec._IdentityProfile_provisionedBy(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "externalId": - out.Values[i] = ec._IdentityProfile_externalId(ctx, field, obj) case "identity": out.Values[i] = ec._IdentityProfile_identity(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "organization": - out.Values[i] = ec._IdentityProfile_organization(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } case "createdAt": out.Values[i] = ec._IdentityProfile_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -16193,21 +14797,11 @@ func (ec *executionContext) _Membership(ctx context.Context, sel ast.SelectionSe if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } - case "identityId": - out.Values[i] = ec._Membership_identityId(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } case "createdAt": out.Values[i] = ec._Membership_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } - case "profile": - out.Values[i] = ec._Membership_profile(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } case "identity": field := field @@ -16240,6 +14834,39 @@ func (ec *executionContext) _Membership(ctx context.Context, sel ast.SelectionSe continue } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "profile": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Membership_profile(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "organization": field := field @@ -16284,18 +14911,6 @@ func (ec *executionContext) _Membership(ctx context.Context, sel ast.SelectionSe if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } - case "provisionedBy": - out.Values[i] = ec._Membership_provisionedBy(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } - case "active": - out.Values[i] = ec._Membership_active(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } - case "lastSyncedAt": - out.Values[i] = ec._Membership_lastSyncedAt(ctx, field, obj) case "lastSession": field := field @@ -17973,37 +16588,65 @@ func (ec *executionContext) _Session(ctx context.Context, sel ast.SelectionSet, case "id": out.Values[i] = ec._Session_id(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } - case "identityId": - out.Values[i] = ec._Session_identityId(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + case "identity": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Session_identity(ctx, field, obj) + return res } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "ipAddress": out.Values[i] = ec._Session_ipAddress(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "userAgent": out.Values[i] = ec._Session_userAgent(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "updatedAt": out.Values[i] = ec._Session_updatedAt(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "createdAt": out.Values[i] = ec._Session_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "expiresAt": out.Values[i] = ec._Session_expiresAt(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) @@ -18149,57 +16792,6 @@ func (ec *executionContext) _SessionEdge(ctx context.Context, sel ast.SelectionS return out } -var sessionPolicyImplementors = []string{"SessionPolicy"} - -func (ec *executionContext) _SessionPolicy(ctx context.Context, sel ast.SelectionSet, obj *types.SessionPolicy) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, sessionPolicyImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("SessionPolicy") - case "maxSessionDurationHours": - out.Values[i] = ec._SessionPolicy_maxSessionDurationHours(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "idleTimeoutMinutes": - out.Values[i] = ec._SessionPolicy_idleTimeoutMinutes(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "maxConcurrentSessions": - out.Values[i] = ec._SessionPolicy_maxConcurrentSessions(ctx, field, obj) - case "requireReauthForSensitiveActions": - out.Values[i] = ec._SessionPolicy_requireReauthForSensitiveActions(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var signInPayloadImplementors = []string{"SignInPayload"} func (ec *executionContext) _SignInPayload(ctx context.Context, sel ast.SelectionSet, obj *types.SignInPayload) graphql.Marshaler { @@ -19077,60 +17669,6 @@ func (ec *executionContext) marshalNCursorKey2goᚗproboᚗincᚋproboᚋpkgᚋp return res } -func (ec *executionContext) marshalNCustomAttribute2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐCustomAttributeᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.CustomAttribute) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNCustomAttribute2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐCustomAttribute(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalNCustomAttribute2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐCustomAttribute(ctx context.Context, sel ast.SelectionSet, v *types.CustomAttribute) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._CustomAttribute(ctx, sel, v) -} - func (ec *executionContext) unmarshalNDatetime2timeᚐTime(ctx context.Context, v any) (time.Time, error) { res, err := graphql.UnmarshalTime(v) return res, graphql.ErrorOnPath(ctx, err) @@ -19244,16 +17782,6 @@ func (ec *executionContext) marshalNIdentity2ᚖgoᚗproboᚗincᚋproboᚋpkg return ec._Identity(ctx, sel, v) } -func (ec *executionContext) marshalNIdentityProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐIdentityProfile(ctx context.Context, sel ast.SelectionSet, v *types.IdentityProfile) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._IdentityProfile(ctx, sel, v) -} - func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v any) (int, error) { res, err := graphql.UnmarshalInt(v) return res, graphql.ErrorOnPath(ctx, err) @@ -19797,16 +18325,6 @@ func (ec *executionContext) marshalNPrincipalType2goᚗproboᚗincᚋproboᚋpkg return v } -func (ec *executionContext) unmarshalNProvisioningSource2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProvisioningSource(ctx context.Context, v any) (types.ProvisioningSource, error) { - var res types.ProvisioningSource - err := res.UnmarshalGQL(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNProvisioningSource2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProvisioningSource(ctx context.Context, sel ast.SelectionSet, v types.ProvisioningSource) graphql.Marshaler { - return v -} - func (ec *executionContext) unmarshalNReauthenticationReason2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐReauthenticationReason(ctx context.Context, v any) (types.ReauthenticationReason, error) { var res types.ReauthenticationReason err := res.UnmarshalGQL(v) diff --git a/pkg/server/api/connect/v1/types/identity_profile.go b/pkg/server/api/connect/v1/types/identity_profile.go new file mode 100644 index 000000000..e279cda5f --- /dev/null +++ b/pkg/server/api/connect/v1/types/identity_profile.go @@ -0,0 +1,26 @@ +// 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 types + +import "go.probo.inc/probo/pkg/coredata" + +func NewIdentityProfile(profile *coredata.IdentityProfile) *IdentityProfile { + return &IdentityProfile{ + ID: profile.ID, + FullName: profile.FullName, + CreatedAt: profile.CreatedAt, + UpdatedAt: profile.UpdatedAt, + } +} diff --git a/pkg/server/api/connect/v1/types/invitation.go b/pkg/server/api/connect/v1/types/invitation.go index e1751eb42..8b0cc5856 100644 --- a/pkg/server/api/connect/v1/types/invitation.go +++ b/pkg/server/api/connect/v1/types/invitation.go @@ -71,5 +71,8 @@ func NewInvitation(invitation *coredata.Invitation) *Invitation { AcceptedAt: invitation.AcceptedAt, CreatedAt: invitation.CreatedAt, Status: invitation.Status, + Organization: &Organization{ + ID: invitation.OrganizationID, + }, } } diff --git a/pkg/server/api/connect/v1/types/membership.go b/pkg/server/api/connect/v1/types/membership.go index 4f7e7c17f..cd2e58973 100644 --- a/pkg/server/api/connect/v1/types/membership.go +++ b/pkg/server/api/connect/v1/types/membership.go @@ -61,9 +61,14 @@ func NewMembershipEdge(membership *coredata.Membership, orderField coredata.Memb func NewMembership(membership *coredata.Membership) *Membership { return &Membership{ - ID: membership.ID, - IdentityID: membership.IdentityID, - CreatedAt: membership.CreatedAt, + ID: membership.ID, + CreatedAt: membership.CreatedAt, + Identity: &Identity{ + ID: membership.IdentityID, + }, + Organization: &Organization{ + ID: membership.OrganizationID, + }, // Permissions: membership.Permissions, // ProvisionedBy: membership.ProvisionedBy, // Active: membership.Active, diff --git a/pkg/server/api/connect/v1/types/session.go b/pkg/server/api/connect/v1/types/session.go index 36b3d0f72..a915fda6d 100644 --- a/pkg/server/api/connect/v1/types/session.go +++ b/pkg/server/api/connect/v1/types/session.go @@ -61,12 +61,14 @@ func NewSessionEdge(session *coredata.Session, orderField coredata.SessionOrderF func NewSession(session *coredata.Session) *Session { return &Session{ - ID: session.ID, - IPAddress: session.IPAddress.String(), - IdentityID: session.IdentityID, - UserAgent: session.UserAgent, - UpdatedAt: session.UpdatedAt, - CreatedAt: session.CreatedAt, - ExpiresAt: session.ExpiredAt, + ID: session.ID, + Identity: &Identity{ + ID: session.IdentityID, + }, + IPAddress: session.IPAddress.String(), + UserAgent: session.UserAgent, + UpdatedAt: session.UpdatedAt, + CreatedAt: session.CreatedAt, + ExpiresAt: session.ExpiredAt, } } diff --git a/pkg/server/api/connect/v1/types/types.go b/pkg/server/api/connect/v1/types/types.go index 57538b51f..d0e758599 100644 --- a/pkg/server/api/connect/v1/types/types.go +++ b/pkg/server/api/connect/v1/types/types.go @@ -33,12 +33,6 @@ type AcceptInvitationPayload struct { MembershipEdge *MembershipEdge `json:"membershipEdge"` } -type AddIPAllowlistEntryInput struct { - OrganizationID gid.GID `json:"organizationId"` - Cidr string `json:"cidr"` - Description *string `json:"description,omitempty"` -} - type Application struct { ID ApplicationID `json:"id"` Name string `json:"name"` @@ -108,28 +102,10 @@ type CreateSAMLConfigurationPayload struct { SamlConfigurationEdge *SAMLConfigurationEdge `json:"samlConfigurationEdge"` } -type CustomAttribute struct { - Key string `json:"key"` - Value string `json:"value"` -} - -type DeactivateAccountInput struct { - Password string `json:"password"` -} - type DeactivateAccountPayload struct { Success bool `json:"success"` } -type DeleteAccountInput struct { - Password string `json:"password"` - Confirmation string `json:"confirmation"` -} - -type DeleteAccountPayload struct { - Success bool `json:"success"` -} - type DeleteInvitationInput struct { OrganizationID gid.GID `json:"organizationId"` InvitationID gid.GID `json:"invitationId"` @@ -178,35 +154,22 @@ type Identity struct { EmailVerified bool `json:"emailVerified"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` + DefaultProfile *IdentityProfile `json:"defaultProfile,omitempty"` Memberships *MembershipConnection `json:"memberships,omitempty"` PendingInvitations *InvitationConnection `json:"pendingInvitations,omitempty"` Sessions *SessionConnection `json:"sessions,omitempty"` PersonalAPIKeys *PersonalAPIKeyConnection `json:"personalAPIKeys,omitempty"` - ProfileFor *IdentityProfile `json:"profileFor,omitempty"` } func (Identity) IsNode() {} func (this Identity) GetID() gid.GID { return this.ID } type IdentityProfile struct { - ID gid.GID `json:"id"` - DisplayName string `json:"displayName"` - FirstName *string `json:"firstName,omitempty"` - LastName *string `json:"lastName,omitempty"` - JobTitle *string `json:"jobTitle,omitempty"` - Department *string `json:"department,omitempty"` - PhoneNumber *string `json:"phoneNumber,omitempty"` - AvatarURL *string `json:"avatarUrl,omitempty"` - Manager *IdentityProfile `json:"manager,omitempty"` - Timezone *string `json:"timezone,omitempty"` - Locale *string `json:"locale,omitempty"` - CustomAttributes []*CustomAttribute `json:"customAttributes"` - ProvisionedBy ProvisioningSource `json:"provisionedBy"` - ExternalID *string `json:"externalId,omitempty"` - Identity *Identity `json:"identity"` - Organization *Organization `json:"organization"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID gid.GID `json:"id"` + FullName string `json:"fullName"` + Identity *Identity `json:"identity"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } func (IdentityProfile) IsNode() {} @@ -242,18 +205,14 @@ type InviteMemberPayload struct { } type Membership struct { - ID gid.GID `json:"id"` - IdentityID gid.GID `json:"identityId"` - CreatedAt time.Time `json:"createdAt"` - Profile *IdentityProfile `json:"profile"` - Identity *Identity `json:"identity,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Role coredata.MembershipRole `json:"role"` - Permissions []*Permission `json:"permissions"` - ProvisionedBy ProvisioningSource `json:"provisionedBy"` - Active bool `json:"active"` - LastSyncedAt *time.Time `json:"lastSyncedAt,omitempty"` - LastSession *Session `json:"lastSession,omitempty"` + ID gid.GID `json:"id"` + CreatedAt time.Time `json:"createdAt"` + Identity *Identity `json:"identity,omitempty"` + Profile *IdentityProfile `json:"profile,omitempty"` + Organization *Organization `json:"organization,omitempty"` + Role coredata.MembershipRole `json:"role"` + Permissions []*Permission `json:"permissions"` + LastSession *Session `json:"lastSession,omitempty"` } func (Membership) IsNode() {} @@ -346,10 +305,6 @@ type PersonalAPIKeyEdge struct { type Query struct { } -type RemoveIPAllowlistEntryInput struct { - EntryID gid.GID `json:"entryId"` -} - type RemoveMemberInput struct { OrganizationID gid.GID `json:"organizationId"` MembershipID gid.GID `json:"membershipId"` @@ -442,13 +397,13 @@ type SSOAvailability struct { } type Session struct { - ID gid.GID `json:"id"` - IdentityID gid.GID `json:"identityId"` - IPAddress string `json:"ipAddress"` - UserAgent string `json:"userAgent"` - UpdatedAt time.Time `json:"updatedAt"` - CreatedAt time.Time `json:"createdAt"` - ExpiresAt time.Time `json:"expiresAt"` + ID gid.GID `json:"id"` + Identity *Identity `json:"identity,omitempty"` + IPAddress string `json:"ipAddress"` + UserAgent string `json:"userAgent"` + UpdatedAt time.Time `json:"updatedAt"` + CreatedAt time.Time `json:"createdAt"` + ExpiresAt time.Time `json:"expiresAt"` } func (Session) IsNode() {} @@ -464,20 +419,6 @@ type SessionOrder struct { Field coredata.SessionOrderField `json:"field"` } -type SessionPolicy struct { - MaxSessionDurationHours int `json:"maxSessionDurationHours"` - IdleTimeoutMinutes int `json:"idleTimeoutMinutes"` - MaxConcurrentSessions *int `json:"maxConcurrentSessions,omitempty"` - RequireReauthForSensitiveActions bool `json:"requireReauthForSensitiveActions"` -} - -type SessionPolicyInput struct { - MaxSessionDurationHours *int `json:"maxSessionDurationHours,omitempty"` - IdleTimeoutMinutes *int `json:"idleTimeoutMinutes,omitempty"` - MaxConcurrentSessions *int `json:"maxConcurrentSessions,omitempty"` - RequireReauthForSensitiveActions *bool `json:"requireReauthForSensitiveActions,omitempty"` -} - type SignInInput struct { Email mail.Addr `json:"email"` Password string `json:"password"` @@ -513,14 +454,7 @@ type SignUpPayload struct { type UpdateIdentityProfileInput struct { MembershipID gid.GID `json:"membershipId"` - DisplayName *string `json:"displayName,omitempty"` - FirstName *string `json:"firstName,omitempty"` - LastName *string `json:"lastName,omitempty"` - JobTitle *string `json:"jobTitle,omitempty"` - Department *string `json:"department,omitempty"` - PhoneNumber *string `json:"phoneNumber,omitempty"` - Timezone *string `json:"timezone,omitempty"` - Locale *string `json:"locale,omitempty"` + FullName *string `json:"fullName,omitempty"` } type UpdateIdentityProfilePayload struct { @@ -699,63 +633,6 @@ func (e ApplicationID) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } -type AuthMethod string - -const ( - AuthMethodPassword AuthMethod = "PASSWORD" - AuthMethodSaml AuthMethod = "SAML" - AuthMethodRecoveryCode AuthMethod = "RECOVERY_CODE" -) - -var AllAuthMethod = []AuthMethod{ - AuthMethodPassword, - AuthMethodSaml, - AuthMethodRecoveryCode, -} - -func (e AuthMethod) IsValid() bool { - switch e { - case AuthMethodPassword, AuthMethodSaml, AuthMethodRecoveryCode: - return true - } - return false -} - -func (e AuthMethod) String() string { - return string(e) -} - -func (e *AuthMethod) UnmarshalGQL(v any) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = AuthMethod(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid AuthMethod", str) - } - return nil -} - -func (e AuthMethod) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -func (e *AuthMethod) UnmarshalJSON(b []byte) error { - s, err := strconv.Unquote(string(b)) - if err != nil { - return err - } - return e.UnmarshalGQL(s) -} - -func (e AuthMethod) MarshalJSON() ([]byte, error) { - var buf bytes.Buffer - e.MarshalGQL(&buf) - return buf.Bytes(), nil -} - type PrincipalType string const ( @@ -811,63 +688,6 @@ func (e PrincipalType) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } -type ProvisioningSource string - -const ( - ProvisioningSourceManual ProvisioningSource = "MANUAL" - ProvisioningSourceInvitation ProvisioningSource = "INVITATION" - ProvisioningSourceSaml ProvisioningSource = "SAML" -) - -var AllProvisioningSource = []ProvisioningSource{ - ProvisioningSourceManual, - ProvisioningSourceInvitation, - ProvisioningSourceSaml, -} - -func (e ProvisioningSource) IsValid() bool { - switch e { - case ProvisioningSourceManual, ProvisioningSourceInvitation, ProvisioningSourceSaml: - return true - } - return false -} - -func (e ProvisioningSource) String() string { - return string(e) -} - -func (e *ProvisioningSource) UnmarshalGQL(v any) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ProvisioningSource(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ProvisioningSource", str) - } - return nil -} - -func (e ProvisioningSource) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -func (e *ProvisioningSource) UnmarshalJSON(b []byte) error { - s, err := strconv.Unquote(string(b)) - if err != nil { - return err - } - return e.UnmarshalGQL(s) -} - -func (e ProvisioningSource) MarshalJSON() ([]byte, error) { - var buf bytes.Buffer - e.MarshalGQL(&buf) - return buf.Bytes(), nil -} - type ReauthenticationReason string const ( diff --git a/pkg/server/api/connect/v1/v1_resolver.go b/pkg/server/api/connect/v1/v1_resolver.go index 4f74da1eb..190ffc3bf 100644 --- a/pkg/server/api/connect/v1/v1_resolver.go +++ b/pkg/server/api/connect/v1/v1_resolver.go @@ -24,6 +24,17 @@ import ( "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) +// DefaultProfile is the resolver for the defaultProfile field. +func (r *identityResolver) DefaultProfile(ctx context.Context, obj *types.Identity) (*types.IdentityProfile, error) { + profile, err := r.iam.AccountService.GetDefaultProfile(ctx, obj.ID) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot get default profile", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) + } + + return types.NewIdentityProfile(profile), nil +} + // Memberships is the resolver for the memberships field. func (r *identityResolver) Memberships(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MembershipOrderBy) (*types.MembershipConnection, error) { pageOrderBy := page.OrderBy[coredata.MembershipOrderField]{ @@ -41,7 +52,8 @@ func (r *identityResolver) Memberships(ctx context.Context, obj *types.Identity, page, err := r.iam.AccountService.ListMemberships(ctx, obj.ID, cursor) if err != nil { - panic(fmt.Errorf("cannot list memberships: %w", err)) + r.logger.ErrorCtx(ctx, "cannot list memberships", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return types.NewMembershipConnection(page, r, obj.ID), nil @@ -58,7 +70,8 @@ func (r *identityResolver) PendingInvitations(ctx context.Context, obj *types.Id page, err := r.iam.AccountService.ListPendingInvitations(ctx, obj.ID, cursor) if err != nil { - panic(fmt.Errorf("cannot list pending invitations: %w", err)) + r.logger.ErrorCtx(ctx, "cannot list pending invitations", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return types.NewInvitationConnection(page, r, obj.ID, nil), nil @@ -81,7 +94,8 @@ func (r *identityResolver) Sessions(ctx context.Context, obj *types.Identity, fi page, err := r.iam.AccountService.ListSessions(ctx, obj.ID, cursor) if err != nil { - panic(fmt.Errorf("cannot list sessions: %w", err)) + r.logger.ErrorCtx(ctx, "cannot list sessions", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return types.NewSessionConnection(page, r, obj.ID), nil @@ -98,7 +112,8 @@ func (r *identityResolver) PersonalAPIKeys(ctx context.Context, obj *types.Ident page, err := r.iam.AccountService.ListPersonalAPIKeys(ctx, obj.ID, cursor) if err != nil { - panic(fmt.Errorf("cannot list personal api keys: %w", err)) + r.logger.ErrorCtx(ctx, "cannot list personal api keys", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return types.NewPersonalAPIKeyConnection(page, r, obj.ID), nil @@ -108,7 +123,8 @@ func (r *identityResolver) PersonalAPIKeys(ctx context.Context, obj *types.Ident func (r *invitationResolver) Organization(ctx context.Context, obj *types.Invitation) (*types.Organization, error) { organization, err := r.iam.OrganizationService.GetOrganizationForInvitation(ctx, obj.ID) if err != nil { - panic(fmt.Errorf("cannot get organization for invitation: %w", err)) + r.logger.ErrorCtx(ctx, "cannot get organization for invitation", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return types.NewOrganization(organization), nil @@ -120,31 +136,51 @@ func (r *invitationConnectionResolver) TotalCount(ctx context.Context, obj *type case *organizationResolver: count, err := r.iam.OrganizationService.CountInvitations(ctx, obj.ParentID, obj.Filters) if err != nil { - panic(fmt.Errorf("cannot count invitations: %w", err)) + r.logger.ErrorCtx(ctx, "cannot count invitations", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return &count, nil case *identityResolver: count, err := r.iam.AccountService.CountPendingInvitations(ctx, obj.ParentID) if err != nil { - panic(fmt.Errorf("cannot count invitations: %w", err)) + r.logger.ErrorCtx(ctx, "cannot count invitations", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return &count, nil } - panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) + r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver)) + return nil, gqlutils.InternalServerError(ctx) } // Identity is the resolver for the identity field. func (r *membershipResolver) Identity(ctx context.Context, obj *types.Membership) (*types.Identity, error) { identity, err := r.iam.AccountService.GetIdentityForMembership(ctx, obj.ID) if err != nil { - panic(fmt.Errorf("cannot get identity: %w", err)) + r.logger.ErrorCtx(ctx, "cannot get identity for membership", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return types.NewIdentity(identity), nil } +// Profile is the resolver for the profile field. +func (r *membershipResolver) Profile(ctx context.Context, obj *types.Membership) (*types.IdentityProfile, error) { + profile, err := r.iam.AccountService.GetProfileForMembership(ctx, obj.ID) + if err != nil { + var errProfileNotFound *iam.ErrProfileNotFound + if errors.As(err, &errProfileNotFound) { + return nil, nil + } + + r.logger.ErrorCtx(ctx, "cannot get profile for membership", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) + } + + return types.NewIdentityProfile(profile), nil +} + // Organization is the resolver for the organization field. func (r *membershipResolver) Organization(ctx context.Context, obj *types.Membership) (*types.Organization, error) { organization, err := r.iam.OrganizationService.GetOrganizationForMembership(ctx, obj.ID) @@ -517,7 +553,29 @@ func (r *mutationResolver) AssumeOrganizationSession(ctx context.Context, input // UpdateIdentityProfile is the resolver for the updateIdentityProfile field. func (r *mutationResolver) UpdateIdentityProfile(ctx context.Context, input types.UpdateIdentityProfileInput) (*types.UpdateIdentityProfilePayload, error) { - panic(fmt.Errorf("not implemented: UpdateIdentityProfile - updateIdentityProfile")) + identity := IdentityFromContext(ctx) + + profile, err := r.iam.AccountService.UpdateIdentityProfile( + ctx, + identity.ID, + &iam.UpdateIdentityProfileRequest{ + MembershipID: input.MembershipID, + FullName: input.FullName, + }, + ) + if err != nil { + var errMembershipNotFound *iam.ErrMembershipNotFound + if errors.As(err, &errMembershipNotFound) { + return nil, gqlutils.NotFound(err) + } + + r.logger.ErrorCtx(ctx, "cannot update identity profile", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) + } + + return &types.UpdateIdentityProfilePayload{ + Profile: types.NewIdentityProfile(profile), + }, nil } // RevokeSession is the resolver for the revokeSession field. @@ -801,7 +859,8 @@ func (r *mutationResolver) CreateSAMLConfiguration(ctx context.Context, input ty ) if err != nil { - panic(fmt.Errorf("cannot create saml configuration: %w", err)) + r.logger.ErrorCtx(ctx, "cannot create saml configuration", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) } return &types.CreateSAMLConfigurationPayload{ @@ -1095,6 +1154,17 @@ func (r *sAMLConfigurationConnectionResolver) TotalCount(ctx context.Context, ob return nil, gqlutils.InternalServerError(ctx) } +// Identity is the resolver for the identity field. +func (r *sessionResolver) Identity(ctx context.Context, obj *types.Session) (*types.Identity, error) { + identity, err := r.iam.AccountService.GetIdentity(ctx, obj.Identity.ID) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot get identity for session", log.Error(err)) + return nil, gqlutils.InternalServerError(ctx) + } + + return types.NewIdentity(identity), nil +} + // TotalCount is the resolver for the totalCount field. func (r *sessionConnectionResolver) TotalCount(ctx context.Context, obj *types.SessionConnection) (*int, error) { switch obj.Resolver.(type) { @@ -1150,6 +1220,9 @@ func (r *Resolver) SAMLConfigurationConnection() schema.SAMLConfigurationConnect return &sAMLConfigurationConnectionResolver{r} } +// Session returns schema.SessionResolver implementation. +func (r *Resolver) Session() schema.SessionResolver { return &sessionResolver{r} } + // SessionConnection returns schema.SessionConnectionResolver implementation. func (r *Resolver) SessionConnection() schema.SessionConnectionResolver { return &sessionConnectionResolver{r} @@ -1165,4 +1238,5 @@ type organizationResolver struct{ *Resolver } type personalAPIKeyConnectionResolver struct{ *Resolver } type queryResolver struct{ *Resolver } type sAMLConfigurationConnectionResolver struct{ *Resolver } +type sessionResolver struct{ *Resolver } type sessionConnectionResolver struct{ *Resolver } diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 958123bcb..815237a45 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -2167,14 +2167,21 @@ func (r *mutationResolver) ExportFramework(ctx context.Context, input types.Expo prb := r.ProboService(ctx, input.FrameworkID.TenantID()) identity := connect_v1.IdentityFromContext(ctx) - err, exportJobID := prb.Frameworks.RequestExport( + // Load default profile to get the full name + recipientName := "" + profile, err := r.iam.AccountService.GetDefaultProfile(ctx, identity.ID) + if err == nil { + recipientName = profile.FullName + } + + exportErr, exportJobID := prb.Frameworks.RequestExport( ctx, input.FrameworkID, identity.EmailAddress, - identity.FullName, + recipientName, ) - if err != nil { - panic(fmt.Errorf("cannot export framework: %w", err)) + if exportErr != nil { + panic(fmt.Errorf("cannot export framework: %w", exportErr)) } return &types.ExportFrameworkPayload{ @@ -3345,15 +3352,22 @@ func (r *mutationResolver) BulkExportDocuments(ctx context.Context, input types. identity := connect_v1.IdentityFromContext(ctx) + // Load default profile to get the full name + recipientName := "" + profile, err := r.iam.AccountService.GetDefaultProfile(ctx, identity.ID) + if err == nil { + recipientName = profile.FullName + } + options := probo.ExportPDFOptions{ WithWatermark: input.WithWatermark, WithSignatures: input.WithSignatures, WatermarkEmail: input.WatermarkEmail, } - documentExport, err := prb.Documents.RequestExport(ctx, input.DocumentIds, identity.EmailAddress, identity.FullName, options) - if err != nil { - panic(fmt.Errorf("cannot request document export: %w", err)) + documentExport, exportErr := prb.Documents.RequestExport(ctx, input.DocumentIds, identity.EmailAddress, recipientName, options) + if exportErr != nil { + panic(fmt.Errorf("cannot request document export: %w", exportErr)) } return &types.BulkExportDocumentsPayload{