From 108e9cb85d856712dce5bfafe9e7cabcf3a7ed79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Thu, 12 Feb 2026 14:17:39 +0400 Subject: [PATCH] Remove coredata.MembershipProfile MemerhipID field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Émile Ré --- pkg/coredata/membership_profile.go | 71 +------------------ pkg/iam/account_service.go | 40 ----------- pkg/iam/organization_service.go | 1 - pkg/iam/saml/service.go | 54 +++++++------- pkg/iam/scim/service.go | 3 +- pkg/server/api/connect/v1/schema.graphql | 2 +- pkg/server/api/connect/v1/schema/schema.go | 2 +- .../api/connect/v1/types/identity_profile.go | 1 - 8 files changed, 32 insertions(+), 142 deletions(-) diff --git a/pkg/coredata/membership_profile.go b/pkg/coredata/membership_profile.go index 6386e226b..ac7ebe812 100644 --- a/pkg/coredata/membership_profile.go +++ b/pkg/coredata/membership_profile.go @@ -33,7 +33,6 @@ type ( ID gid.GID `db:"id"` IdentityID gid.GID `db:"identity_id"` OrganizationID gid.GID `db:"organization_id"` - MembershipID gid.GID `db:"membership_id"` EmailAddress mail.Addr `db:"email_address"` FullName string `db:"full_name"` Kind MembershipProfileKind `db:"kind"` @@ -62,7 +61,7 @@ func (p MembershipProfile) CursorKey(orderBy MembershipProfileOrderField) page.C } func (p *MembershipProfile) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) { - q := `SELECT m.organization_id, mp.identity_id FROM iam_membership_profiles mp JOIN iam_memberships m ON mp.membership_id = m.id WHERE mp.id = $1 LIMIT 1;` + q := `SELECT organization_id, identity_id FROM iam_membership_profiles WHERE id = $1 LIMIT 1;` var organizationID gid.GID var identityID gid.GID @@ -70,7 +69,7 @@ func (p *MembershipProfile) AuthorizationAttributes(ctx context.Context, conn pg if errors.Is(err, pgx.ErrNoRows) { return nil, ErrResourceNotFound } - return nil, fmt.Errorf("cannot query membership profile authorization attributes: %w", err) + return nil, fmt.Errorf("cannot query profile authorization attributes: %w", err) } return map[string]string{ @@ -79,61 +78,6 @@ func (p *MembershipProfile) AuthorizationAttributes(ctx context.Context, conn pg }, nil } -func (p *MembershipProfile) LoadByMembershipID( - ctx context.Context, - conn pg.Conn, - scope Scoper, - membershipID gid.GID, -) error { - q := ` -SELECT - p.id, - p.identity_id, - p.organization_id, - p.membership_id, - i.email_address, - p.full_name, - p.kind, - p.additional_email_addresses, - p.position, - p.contract_start_date, - p.contract_end_date, - p.created_at, - p.updated_at -FROM - iam_membership_profiles p -INNER JOIN identities i - ON i.id = p.identity_id -WHERE - p.%s - AND p.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 profile: %w", err) - } - - profile, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[MembershipProfile]) - if err != nil { - if errors.Is(err, pgx.ErrNoRows) { - return ErrResourceNotFound - } - - return fmt.Errorf("cannot collect profile: %w", err) - } - - *p = profile - - return nil -} - func (p *MembershipProfile) LoadByID( ctx context.Context, conn pg.Conn, @@ -145,7 +89,6 @@ SELECT p.id, p.identity_id, p.organization_id, - p.membership_id, i.email_address, p.full_name, p.kind, @@ -201,7 +144,6 @@ SELECT p.id, p.identity_id, p.organization_id, - p.membership_id, i.email_address, p.full_name, p.kind, @@ -260,7 +202,6 @@ SELECT p.id, p.identity_id, p.organization_id, - p.membership_id, i.email_address, p.full_name, p.kind, @@ -313,7 +254,6 @@ WITH profiles AS ( id, identity_id, organization_id, - membership_id, full_name, kind, additional_email_addresses, @@ -334,7 +274,6 @@ SELECT p.id, p.identity_id, p.organization_id, - p.membership_id, i.email_address, p.full_name, p.kind, @@ -587,7 +526,6 @@ WITH attendees AS ( p.tenant_id, p.identity_id, p.organization_id, - p.membership_id, i.email_address, p.full_name, p.kind, @@ -611,7 +549,6 @@ SELECT id, identity_id, organization_id, - membership_id, kind, email_address, full_name, @@ -670,7 +607,6 @@ SELECT p.id, p.identity_id, p.organization_id, - p.membership_id, p.kind, p.full_name, i.email_address, @@ -753,7 +689,6 @@ INSERT INTO id, identity_id, organization_id, - membership_id, full_name, kind, additional_email_addresses, @@ -768,7 +703,6 @@ VALUES ( @id, @identity_id, @organization_id, - @membership_id, @full_name, @kind, COALESCE(@additional_email_addresses, '{}'::CITEXT[]), @@ -785,7 +719,6 @@ VALUES ( "id": p.ID, "identity_id": p.IdentityID, "organization_id": p.OrganizationID, - "membership_id": p.MembershipID, "full_name": p.FullName, "kind": p.Kind, "additional_email_addresses": p.AdditionalEmailAddresses, diff --git a/pkg/iam/account_service.go b/pkg/iam/account_service.go index c1c8e46f7..49ec8534d 100644 --- a/pkg/iam/account_service.go +++ b/pkg/iam/account_service.go @@ -269,7 +269,6 @@ func (s *AccountService) AcceptInvitation( ID: gid.New(tenantID, coredata.MembershipProfileEntityType), IdentityID: identity.ID, OrganizationID: invitation.OrganizationID, - MembershipID: membership.ID, FullName: identity.FullName, CreatedAt: now, UpdatedAt: now, @@ -820,45 +819,6 @@ func (s AccountService) GetMembershipForOrganization( return membership, nil } -func (s AccountService) GetProfileForMembership(ctx context.Context, membershipID gid.GID) (*coredata.MembershipProfile, error) { - var ( - scope = coredata.NewScopeFromObjectID(membershipID) - profile = &coredata.MembershipProfile{} - ) - - err := s.pg.WithConn( - ctx, - func(conn pg.Conn) error { - membership := &coredata.Membership{} - err := membership.LoadByID(ctx, conn, scope, membershipID) - if err != nil { - if errors.Is(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 errors.Is(err, coredata.ErrResourceNotFound) { - return NewProfileNotFoundError(membershipID) - } - - return fmt.Errorf("cannot load membership profile: %w", err) - } - - return nil - }, - ) - - if err != nil { - return nil, err - } - - return profile, nil -} - func (s AccountService) ListSAMLConfigurationsForEmail( ctx context.Context, email mail.Addr, diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index b0e2a5351..03b343cdc 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -697,7 +697,6 @@ func (s *OrganizationService) CreateOrganization( ID: gid.New(tenantID, coredata.MembershipProfileEntityType), IdentityID: identity.ID, OrganizationID: organization.ID, - MembershipID: membership.ID, FullName: identity.FullName, CreatedAt: now, UpdatedAt: now, diff --git a/pkg/iam/saml/service.go b/pkg/iam/saml/service.go index d2601aaca..c5cd39526 100644 --- a/pkg/iam/saml/service.go +++ b/pkg/iam/saml/service.go @@ -178,6 +178,7 @@ func (s *Service) HandleAssertion( var ( now = time.Now() identity = &coredata.Identity{} + profile = &coredata.MembershipProfile{} membership = &coredata.Membership{} ) @@ -295,6 +296,27 @@ func (s *Service) HandleAssertion( scope := coredata.NewScopeFromObjectID(config.OrganizationID) + err = profile.LoadByIdentityIDAndOrganizationID(ctx, tx, scope, identity.ID, config.OrganizationID) + if err != nil && err != coredata.ErrResourceNotFound { + return fmt.Errorf("cannot load profile: %w", err) + } + + if profile.ID == gid.Nil { + profile = &coredata.MembershipProfile{ + ID: gid.New(membership.ID.TenantID(), coredata.MembershipProfileEntityType), + IdentityID: identity.ID, + OrganizationID: config.OrganizationID, + FullName: fullname, + CreatedAt: now, + UpdatedAt: now, + } + + err = profile.Insert(ctx, tx) + if err != nil { + return fmt.Errorf("cannot insert membership profile: %w", err) + } + } + err = membership.LoadByIdentityAndOrg(ctx, tx, scope, identity.ID, config.OrganizationID) if err != nil && err != coredata.ErrResourceNotFound { return fmt.Errorf("cannot load membership: %w", err) @@ -304,8 +326,7 @@ func (s *Service) HandleAssertion( return NewMembershipInactiveError(membership.ID) } - isMember := membership.ID != gid.Nil - if !isMember { + if membership.ID == gid.Nil { membership = &coredata.Membership{ ID: gid.New(config.ID.TenantID(), coredata.MembershipEntityType), IdentityID: identity.ID, @@ -322,21 +343,6 @@ func (s *Service) HandleAssertion( return fmt.Errorf("cannot insert membership: %w", err) } - membershipProfile := &coredata.MembershipProfile{ - ID: gid.New(membership.ID.TenantID(), coredata.MembershipProfileEntityType), - IdentityID: identity.ID, - OrganizationID: config.OrganizationID, - 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) - } - // Expire all pending invitations for email in organization invitations := &coredata.Invitations{} onlyPending := coredata.NewInvitationFilter([]coredata.InvitationStatus{coredata.InvitationStatusPending}) @@ -374,17 +380,11 @@ func (s *Service) HandleAssertion( } } - memberProfile := &coredata.MembershipProfile{} - err = memberProfile.LoadByMembershipID(ctx, tx, scope, membership.ID) + profile.FullName = fullname + profile.UpdatedAt = now + err = profile.Update(ctx, tx, scope) if err != nil { - return fmt.Errorf("cannot load membership profile: %w", err) - } - - memberProfile.FullName = fullname - memberProfile.UpdatedAt = now - err = memberProfile.Update(ctx, tx, scope) - if err != nil { - return fmt.Errorf("cannot update membership profile: %w", err) + return fmt.Errorf("cannot update profile: %w", err) } } diff --git a/pkg/iam/scim/service.go b/pkg/iam/scim/service.go index 66d2ef8b0..6f7a0cea7 100644 --- a/pkg/iam/scim/service.go +++ b/pkg/iam/scim/service.go @@ -199,7 +199,6 @@ func (s *Service) CreateUser( ID: gid.New(membership.ID.TenantID(), coredata.MembershipProfileEntityType), IdentityID: identity.ID, OrganizationID: config.OrganizationID, - MembershipID: membership.ID, FullName: fullName, CreatedAt: now, UpdatedAt: now, @@ -461,7 +460,7 @@ func (s *Service) updateUser( } profile := &coredata.MembershipProfile{} - if err := profile.LoadByMembershipID(ctx, tx, scope, membershipID); err == nil { + if err := profile.LoadByIdentityIDAndOrganizationID(ctx, tx, scope, membership.IdentityID, membership.OrganizationID); err == nil { if fullName != "" { profile.FullName = fullName profile.UpdatedAt = now diff --git a/pkg/server/api/connect/v1/schema.graphql b/pkg/server/api/connect/v1/schema.graphql index 46f9935a6..d151a6f53 100644 --- a/pkg/server/api/connect/v1/schema.graphql +++ b/pkg/server/api/connect/v1/schema.graphql @@ -192,7 +192,7 @@ type MembershipProfile implements Node { identity: Identity @goField(forceResolver: true) organization: Organization @goField(forceResolver: true) - # TODO: remove when memberships are under profile + # FIXME: remove when memberships are under profile membershipId: ID! permission(action: String!): Boolean! diff --git a/pkg/server/api/connect/v1/schema/schema.go b/pkg/server/api/connect/v1/schema/schema.go index f875f96ef..249c4a311 100644 --- a/pkg/server/api/connect/v1/schema/schema.go +++ b/pkg/server/api/connect/v1/schema/schema.go @@ -2719,7 +2719,7 @@ type MembershipProfile implements Node { identity: Identity @goField(forceResolver: true) organization: Organization @goField(forceResolver: true) - # TODO: remove when memberships are under profile + # FIXME: remove when memberships are under profile membershipId: ID! permission(action: String!): Boolean! diff --git a/pkg/server/api/connect/v1/types/identity_profile.go b/pkg/server/api/connect/v1/types/identity_profile.go index b861ee842..bf0973c02 100644 --- a/pkg/server/api/connect/v1/types/identity_profile.go +++ b/pkg/server/api/connect/v1/types/identity_profile.go @@ -27,7 +27,6 @@ func NewMembershipProfile(profile *coredata.MembershipProfile) *MembershipProfil ContractEndDate: profile.ContractEndDate, CreatedAt: profile.CreatedAt, UpdatedAt: profile.UpdatedAt, - MembershipID: profile.MembershipID, Identity: &Identity{ ID: profile.IdentityID, },