Split inactive profile state
Replace the binary profile ACTIVE/INACTIVE model with PENDING, ACTIVE, and DEACTIVATED so invited-but-not-yet-activated members remain assignable to assets, data, and risks instead of being treated like deactivated users. Add activated_at/deactivated_at timestamps and Mark* lifecycle helpers, and update every transition (create, invite/re-invite, activation, archive, SCIM, SAML, sessions, compliance-portal grant) to the new states. Expose a multi-state states[] filter across coredata, GraphQL, MCP, and the console owner pickers, which now request ACTIVE and PENDING members. A migration renames the membership_state enum, classifies existing inactive profiles as PENDING from recent invitation activity, and backfills the new timestamp columns. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -150,7 +150,7 @@ func (s *Service) CreateUser(
|
||||
|
||||
profileState := coredata.ProfileStateActive
|
||||
if !attrs.Active {
|
||||
profileState = coredata.ProfileStateInactive
|
||||
profileState = coredata.ProfileStateDeactivated
|
||||
}
|
||||
|
||||
var externalIdPtr *string
|
||||
@@ -536,8 +536,8 @@ func (s *Service) updateUser(
|
||||
previousMembership := *membership
|
||||
previousUser := webhooktypes.NewUser(&previousProfile, &previousMembership)
|
||||
|
||||
shouldReactivate := attrs.Active != nil && *attrs.Active && profile.State == coredata.ProfileStateInactive
|
||||
shouldDeactivate := attrs.Active != nil && !*attrs.Active && profile.State == coredata.ProfileStateActive
|
||||
shouldReactivate := attrs.Active != nil && *attrs.Active && profile.State == coredata.ProfileStateDeactivated
|
||||
shouldDeactivate := attrs.Active != nil && !*attrs.Active && profile.State != coredata.ProfileStateDeactivated
|
||||
|
||||
if attrs.FullName != "" {
|
||||
profile.FullName = attrs.FullName
|
||||
@@ -748,11 +748,9 @@ func (s *Service) updateUser(
|
||||
}
|
||||
|
||||
if shouldReactivate {
|
||||
profile.State = coredata.ProfileStateActive
|
||||
profile.UpdatedAt = now
|
||||
profile.MarkActive(now)
|
||||
} else if shouldDeactivate {
|
||||
profile.State = coredata.ProfileStateInactive
|
||||
profile.UpdatedAt = now
|
||||
profile.MarkDeactivated(now)
|
||||
}
|
||||
|
||||
if profile.Source != coredata.ProfileSourceSCIM {
|
||||
@@ -826,7 +824,15 @@ func applyUserAttributes(
|
||||
now time.Time,
|
||||
) {
|
||||
profile.Source = coredata.ProfileSourceSCIM
|
||||
profile.State = state
|
||||
switch {
|
||||
case state == coredata.ProfileStateActive && profile.State != coredata.ProfileStateActive:
|
||||
profile.MarkActive(now)
|
||||
case state == coredata.ProfileStateDeactivated && profile.State != coredata.ProfileStateDeactivated:
|
||||
profile.MarkDeactivated(now)
|
||||
default:
|
||||
profile.State = state
|
||||
}
|
||||
|
||||
profile.FullName = attrs.FullName
|
||||
profile.Position = &attrs.Title
|
||||
profile.UserName = &attrs.UserName
|
||||
@@ -956,15 +962,14 @@ func (s *Service) deactivateProfileInTx(
|
||||
profile *coredata.MembershipProfile,
|
||||
membership *coredata.Membership,
|
||||
) error {
|
||||
if profile.State == coredata.ProfileStateInactive {
|
||||
if profile.State == coredata.ProfileStateDeactivated {
|
||||
return nil
|
||||
}
|
||||
|
||||
previousUser := webhooktypes.NewUser(profile, membership)
|
||||
|
||||
now := time.Now()
|
||||
profile.State = coredata.ProfileStateInactive
|
||||
profile.UpdatedAt = now
|
||||
profile.MarkDeactivated(now)
|
||||
|
||||
if err := profile.Update(ctx, tx, scope); err != nil {
|
||||
return fmt.Errorf("cannot deactivate profile: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user