feat: patch user scim v2 endpoint (#9219)

# Which Problems Are Solved
* Adds support for the patch user SCIM v2 endpoint

# How the Problems Are Solved
* Adds support for the patch user SCIM v2 endpoint under `PATCH
/scim/v2/{orgID}/Users/{id}`

# Additional Context
Part of #8140
This commit is contained in:
Lars
2025-01-27 13:36:07 +01:00
committed by GitHub
parent ec5f18c168
commit 189f9770c6
31 changed files with 3601 additions and 125 deletions

View File

@@ -14,12 +14,13 @@ import (
)
type ChangeHuman struct {
ID string
State *domain.UserState
Username *string
Profile *Profile
Email *Email
Phone *Phone
ID string
State *domain.UserState
Username *string
Profile *Profile
Email *Email
Phone *Phone
Metadata []*domain.Metadata
MetadataKeysToRemove []string
@@ -61,8 +62,8 @@ func (h *ChangeHuman) Validate(hasher *crypto.Hasher) (err error) {
}
}
if h.Phone != nil && h.Phone.Number != "" {
if h.Phone.Number, err = h.Phone.Number.Normalize(); err != nil {
if h.Phone != nil {
if err := h.Phone.Validate(); err != nil {
return err
}
}
@@ -263,7 +264,7 @@ func (c *Commands) ChangeUserHuman(ctx context.Context, human *ChangeHuman, alg
return err
}
existingHuman, err := c.userHumanWriteModel(
existingHuman, err := c.UserHumanWriteModel(
ctx,
human.ID,
human.Profile != nil,
@@ -272,13 +273,11 @@ func (c *Commands) ChangeUserHuman(ctx context.Context, human *ChangeHuman, alg
human.Password != nil,
false, // avatar not updateable
false, // IDPLinks not updateable
len(human.Metadata) > 0 || len(human.MetadataKeysToRemove) > 0,
)
if err != nil {
return err
}
if !isUserStateExists(existingHuman.UserState) {
return zerrors.ThrowNotFound(nil, "COMMAND-ugjs0upun6", "Errors.User.NotFound")
}
if human.Changed() {
if err := c.checkPermissionUpdateUser(ctx, existingHuman.ResourceOwner, existingHuman.AggregateID); err != nil {
@@ -415,6 +414,10 @@ func (c *Commands) changeUserPhone(ctx context.Context, cmds []eventstore.Comman
ctx, span := tracing.NewSpan(ctx)
defer func() { span.End() }()
if phone.Remove {
return append(cmds, user.NewHumanPhoneRemovedEvent(ctx, &wm.Aggregate().Aggregate)), nil, nil
}
if phone.Number != "" && phone.Number != wm.Phone {
cmds = append(cmds, user.NewHumanPhoneChangedEvent(ctx, &wm.Aggregate().Aggregate, phone.Number))
@@ -432,6 +435,7 @@ func (c *Commands) changeUserPhone(ctx context.Context, cmds []eventstore.Comman
return cmds, code, nil
}
}
// only create separate event of verified if email was not changed
if phone.Verified && wm.IsPhoneVerified != phone.Verified {
return append(cmds, user.NewHumanPhoneVerifiedEvent(ctx, &wm.Aggregate().Aggregate)), code, nil
@@ -499,14 +503,19 @@ func (c *Commands) userExistsWriteModel(ctx context.Context, userID string) (wri
return writeModel, nil
}
func (c *Commands) userHumanWriteModel(ctx context.Context, userID string, profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM bool) (writeModel *UserV2WriteModel, err error) {
func (c *Commands) UserHumanWriteModel(ctx context.Context, userID string, profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM, metadataWM bool) (writeModel *UserV2WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewUserHumanWriteModel(userID, "", profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM)
writeModel = NewUserHumanWriteModel(userID, "", profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM, metadataWM)
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
if !isUserStateExists(writeModel.UserState) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-ugjs0upun6", "Errors.User.NotFound")
}
return writeModel, nil
}