mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:37:34 +00:00
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:
111
internal/api/scim/resources/user_patch.go
Normal file
111
internal/api/scim/resources/user_patch.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/scim/metadata"
|
||||
"github.com/zitadel/zitadel/internal/api/scim/resources/filter"
|
||||
"github.com/zitadel/zitadel/internal/api/scim/resources/patch"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
type userPatcher struct {
|
||||
ctx context.Context
|
||||
user *ScimUser
|
||||
metadataChanges map[metadata.Key]*domain.Metadata
|
||||
metadataKeysToRemove map[metadata.Key]bool
|
||||
handler *UsersHandler
|
||||
}
|
||||
|
||||
func (h *UsersHandler) applyPatchesToChangeHuman(ctx context.Context, user *ScimUser, operations patch.OperationCollection) (*command.ChangeHuman, error) {
|
||||
patcher := &userPatcher{
|
||||
ctx: ctx,
|
||||
user: user,
|
||||
metadataChanges: make(map[metadata.Key]*domain.Metadata),
|
||||
metadataKeysToRemove: make(map[metadata.Key]bool),
|
||||
handler: h,
|
||||
}
|
||||
|
||||
if err := operations.Apply(patcher, user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we rely on the change detection of the write model to only execute commands that really change data
|
||||
changeCommand, err := h.mapToChangeHuman(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
patcher.applyMetadataChangesToCommand(changeCommand)
|
||||
return changeCommand, nil
|
||||
}
|
||||
|
||||
func (p *userPatcher) FilterEvaluator() *filter.Evaluator {
|
||||
return p.handler.filterEvaluator
|
||||
}
|
||||
|
||||
func (p *userPatcher) Added(attributePath []string) error {
|
||||
return p.updateMetadata(attributePath)
|
||||
}
|
||||
|
||||
func (p *userPatcher) Replaced(attributePath []string) error {
|
||||
return p.updateMetadata(attributePath)
|
||||
}
|
||||
|
||||
func (p *userPatcher) Removed(attributePath []string) error {
|
||||
return p.updateMetadata(attributePath)
|
||||
}
|
||||
|
||||
func (p *userPatcher) applyMetadataChangesToCommand(command *command.ChangeHuman) {
|
||||
command.MetadataKeysToRemove = make([]string, 0, len(p.metadataKeysToRemove))
|
||||
for key := range p.metadataKeysToRemove {
|
||||
command.MetadataKeysToRemove = append(command.MetadataKeysToRemove, string(key))
|
||||
}
|
||||
|
||||
command.Metadata = make([]*domain.Metadata, 0, len(p.metadataChanges))
|
||||
for _, update := range p.metadataChanges {
|
||||
command.Metadata = append(command.Metadata, update)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *userPatcher) updateMetadata(attributePath []string) error {
|
||||
if len(attributePath) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// try full path first (e.g. name.middleName)
|
||||
// try root only if full path did not match (e.g. for entitlements.value only entitlements is mapped)
|
||||
var ok bool
|
||||
var keys []metadata.Key
|
||||
if len(attributePath) > 1 {
|
||||
keys, ok = metadata.AttributePathToMetadataKeys[strings.Join(attributePath, ".")]
|
||||
}
|
||||
|
||||
if !ok {
|
||||
keys, ok = metadata.AttributePathToMetadataKeys[attributePath[0]]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
value, err := getValueForMetadataKey(p.user, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(value) > 0 {
|
||||
delete(p.metadataKeysToRemove, key)
|
||||
p.metadataChanges[key] = &domain.Metadata{
|
||||
Key: string(metadata.ScopeKey(p.ctx, key)),
|
||||
Value: value,
|
||||
}
|
||||
} else {
|
||||
p.metadataKeysToRemove[key] = true
|
||||
delete(p.metadataChanges, key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user