Move source and state from membership to profile

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-02-13 21:21:11 +04:00
parent ec3d8fad40
commit 56ec0ab3c3
33 changed files with 1066 additions and 1220 deletions

View File

@@ -89,12 +89,12 @@ func (e ErrSAMLAutoSignupDisabled) Error() string {
return fmt.Sprintf("SAML auto-signup is disabled for configuration %q", e.ConfigID)
}
type ErrMembershipInactive struct{ MembershipID gid.GID }
type ErrUserInactive struct{ ProfileID gid.GID }
func NewMembershipInactiveError(membershipID gid.GID) error {
return &ErrMembershipInactive{MembershipID: membershipID}
func NewUserInactiveError(profileID gid.GID) error {
return &ErrUserInactive{ProfileID: profileID}
}
func (e ErrMembershipInactive) Error() string {
return fmt.Sprintf("membership %q is inactive", e.MembershipID)
func (e ErrUserInactive) Error() string {
return fmt.Sprintf("user %q is inactive", e.ProfileID)
}

View File

@@ -296,16 +296,23 @@ 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 err := profile.LoadByIdentityIDAndOrganizationID(
ctx,
tx,
scope,
identity.ID,
config.OrganizationID,
); err != nil {
if !errors.Is(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,
Source: coredata.ProfileSourceSAML,
State: coredata.ProfileStateActive,
FullName: fullname,
CreatedAt: now,
UpdatedAt: now,
@@ -315,25 +322,28 @@ func (s *Service) HandleAssertion(
if err != nil {
return fmt.Errorf("cannot insert membership profile: %w", err)
}
} else {
if profile.State == coredata.ProfileStateInactive {
return NewUserInactiveError(membership.ID)
}
}
err = membership.LoadByIdentityAndOrg(ctx, tx, scope, identity.ID, config.OrganizationID)
if err != nil && err != coredata.ErrResourceNotFound {
return fmt.Errorf("cannot load membership: %w", err)
}
if err := membership.LoadByIdentityAndOrg(
ctx,
tx,
scope,
identity.ID,
config.OrganizationID,
); err != nil {
if !errors.Is(err, coredata.ErrResourceNotFound) {
return fmt.Errorf("cannot load membership: %w", err)
}
if membership.ID != gid.Nil && membership.State == coredata.MembershipStateInactive {
return NewMembershipInactiveError(membership.ID)
}
if membership.ID == gid.Nil {
membership = &coredata.Membership{
ID: gid.New(config.ID.TenantID(), coredata.MembershipEntityType),
IdentityID: identity.ID,
OrganizationID: config.OrganizationID,
Role: coredata.MembershipRoleEmployee,
Source: coredata.MembershipSourceSAML,
State: coredata.MembershipStateActive,
CreatedAt: now,
UpdatedAt: now,
}
@@ -358,34 +368,26 @@ func (s *Service) HandleAssertion(
}
}
if membership.Source != coredata.MembershipSourceSCIM {
needsUpdate := false
if profile.Source != coredata.ProfileSourceSCIM {
profile.FullName = fullname
profile.UpdatedAt = now
if profile.Source == coredata.ProfileSourceManual {
profile.Source = coredata.ProfileSourceSAML
}
err = profile.Update(ctx, tx, scope)
if err != nil {
return fmt.Errorf("cannot update profile: %w", err)
}
if role != nil {
membership.Role = *role
membership.UpdatedAt = now
needsUpdate = true
}
if membership.Source == coredata.MembershipSourceManual {
membership.Source = coredata.MembershipSourceSAML
membership.UpdatedAt = now
needsUpdate = true
}
if needsUpdate {
err = membership.Update(ctx, tx, scope)
if err != nil {
return fmt.Errorf("cannot update membership: %w", err)
}
}
profile.FullName = fullname
profile.UpdatedAt = now
err = profile.Update(ctx, tx, scope)
if err != nil {
return fmt.Errorf("cannot update profile: %w", err)
}
}
return nil