Skip to content

Commit

Permalink
Merge pull request #7 from ivixvi/feat-remove-complex-attributes
Browse files Browse the repository at this point in the history
feat: remove complex attributse
  • Loading branch information
ivixvi authored Jul 10, 2024
2 parents 2803587 + ada48c5 commit 740244c
Show file tree
Hide file tree
Showing 3 changed files with 263 additions and 37 deletions.
45 changes: 10 additions & 35 deletions scimpatch.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package scimpatch

import (
"fmt"
"strings"

"github.com/elimity-com/scim"
Expand Down Expand Up @@ -76,16 +75,19 @@ func (p *Patcher) remove(op scim.PatchOperation, data scim.ResourceAttributes) (
if cannotBePatched(op.Op, attr) {
return scim.ResourceAttributes{}, false, errors.ScimErrorMutability
}
scopedMap := p.getScopedMap(op, data)
switch {
case !attr.HasSubAttributes() && !attr.MultiValued():
fmt.Printf("%v, %s", scopedMap, attrName)
if _, ok := scopedMap[attrName]; ok {
delete(scopedMap, attrName)
switch attr.MultiValued() {
case true:
case false:
n := NewScopeNavigator(op, data, attr)
scopedMap, scopedAttr := n.GetScopedMap()
if _, ok := scopedMap[scopedAttr]; ok {
delete(scopedMap, scopedAttr)
changed = true
}
n.ApplyScopedMap(scopedMap)
data = n.GetMap()
}
data = p.setScopedMap(op, data, scopedMap)

return data, changed, nil
}

Expand All @@ -99,30 +101,3 @@ func (p *Patcher) containsAttribute(attrName string) (schema.CoreAttribute, bool
}
return schema.CoreAttribute{}, false
}

// getScopedMap は 処理対象であるmapまでのスコープをたどり該当のmapを返却します
func (p *Patcher) getScopedMap(op scim.PatchOperation, data scim.ResourceAttributes) scim.ResourceAttributes {
uriPrefix, containsURI := containsURIPrefix(op.Path)
if containsURI {
data, ok := data[uriPrefix].(map[string]interface{})
if !ok {
data = scim.ResourceAttributes{}
}
return data
}

return data
}

// setScopedMap は 処理対象であるmapまでのスコープをたどりscopedMapに置換したdataを返却します
func (p *Patcher) setScopedMap(op scim.PatchOperation, data scim.ResourceAttributes, scopedMap scim.ResourceAttributes) scim.ResourceAttributes {
uriPrefix, containsURI := containsURIPrefix(op.Path)
if containsURI {
if len(scopedMap) == 0 {
delete(data, uriPrefix)
} else {
data[uriPrefix] = scopedMap
}
}
return data
}
165 changes: 163 additions & 2 deletions scimpatch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func TestPatcher_Apply(t *testing.T) {
},
expectedChanged: false,
},
// Remove Singular Attribute
{
name: "Remove operation - Core Singular Attribute",
op: scim.PatchOperation{
Expand Down Expand Up @@ -142,6 +143,166 @@ func TestPatcher_Apply(t *testing.T) {
},
expectedChanged: false,
},
// Remove Complex Attributes
{
name: "Remove operation - Core Complex Attribute - SubAttributes Not Specified.",
op: scim.PatchOperation{
Op: "remove",
Path: path("name"),
},
data: scim.ResourceAttributes{
"name": map[string]interface{}{
"familyName": "Green",
},
},
expected: scim.ResourceAttributes{},
expectedChanged: true,
},
{
name: "Remove operation - Core Complex Attribute - SubAttributes Specified.",
op: scim.PatchOperation{
Op: "remove",
Path: path("name.familyName"),
},
data: scim.ResourceAttributes{
"name": map[string]interface{}{
"familyName": "Green",
"givenName": "Alice",
},
},
expected: scim.ResourceAttributes{
"name": map[string]interface{}{
"givenName": "Alice",
},
},
expectedChanged: true,
},
{
name: "Remove operation - Core Complex Attribute - SubAttributes Specified - Remove Attributes",
op: scim.PatchOperation{
Op: "remove",
Path: path("name.familyName"),
},
data: scim.ResourceAttributes{
"name": map[string]interface{}{
"familyName": "Green",
},
},
expected: scim.ResourceAttributes{},
expectedChanged: true,
},
{
name: "Remove operation - Core Complex Attribute Not Changed. - SubAttributes not Specified ",
op: scim.PatchOperation{
Op: "remove",
Path: path("name"),
},
data: scim.ResourceAttributes{},
expected: scim.ResourceAttributes{},
expectedChanged: false,
},
{
name: "Remove operation - Core Complex Attribute Not Changed. - SubAttributes Specified ",
op: scim.PatchOperation{
Op: "remove",
Path: path("name.familyName"),
},
data: scim.ResourceAttributes{},
expected: scim.ResourceAttributes{},
expectedChanged: false,
},
{
name: "Remove operation - Extention Complex Attribute - Attribute Removed.",
op: scim.PatchOperation{
Op: "remove",
Path: path("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager"),
},
data: scim.ResourceAttributes{
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{
"manager": interface{}(
map[string]interface{}{
"value": "0001",
"displayName": "Bob Green",
},
),
},
},
expected: scim.ResourceAttributes{},
expectedChanged: true,
},
{
name: "Remove operation - Extention Complex Attribute - All Removed.",
op: scim.PatchOperation{
Op: "remove",
Path: path("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value"),
},
data: scim.ResourceAttributes{
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{
"manager": interface{}(
map[string]interface{}{
"value": "0001",
},
),
},
},
expected: scim.ResourceAttributes{},
expectedChanged: true,
},
{
name: "Remove operation - Extention Complex Attribute - Partially Removed.",
op: scim.PatchOperation{
Op: "remove",
Path: path("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value"),
},
data: scim.ResourceAttributes{
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{
"manager": interface{}(
map[string]interface{}{
"value": "0001",
"displayName": "Bob Green",
},
),
},
},
expected: scim.ResourceAttributes{
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{
"manager": interface{}(
map[string]interface{}{
"displayName": "Bob Green",
},
),
},
},
expectedChanged: true,
},
{
name: "Remove operation - Extention Complex Attribute - URI Prefix not exists.",
op: scim.PatchOperation{
Op: "remove",
Path: path("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value"),
},
data: scim.ResourceAttributes{},
expected: scim.ResourceAttributes{},
expectedChanged: false,
},
{
name: "Remove operation - Extention Complex Attribute - URI Prefix exists.",
op: scim.PatchOperation{
Op: "remove",
Path: path("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value"),
},
data: scim.ResourceAttributes{
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{
"division": "Sales",
},
},
expected: scim.ResourceAttributes{
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{
"division": "Sales",
},
},
expectedChanged: false,
},
}

for _, tc := range testCases {
Expand All @@ -157,11 +318,11 @@ func TestPatcher_Apply(t *testing.T) {
}
// Check if the result matches the expected data
if changed != tc.expectedChanged {
t.Errorf("actual: %v, expected: %v", changed, tc.expectedChanged)
t.Errorf("changed:\n actual : %v\n expected: %v", changed, tc.expectedChanged)
}
// Check if the result matches the expected data
if !(fmt.Sprint(result) == fmt.Sprint(tc.expected)) {
t.Errorf("actual: %v, expected: %v", result, tc.expected)
t.Errorf("result:\n actual : %v\n expected: %v", result, tc.expected)
}
})
}
Expand Down
90 changes: 90 additions & 0 deletions scope.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package scimpatch

import (
"fmt"

"github.com/elimity-com/scim"
"github.com/elimity-com/scim/schema"
)

type ScopeNavigator struct {
op scim.PatchOperation
data scim.ResourceAttributes
attr schema.CoreAttribute
}

func NewScopeNavigator(op scim.PatchOperation, data scim.ResourceAttributes, attr schema.CoreAttribute) *ScopeNavigator {
return &ScopeNavigator{
op: op,
data: data,
attr: attr,
}
}

// GetMap は 処理対象であるmapまでのスコープをたどり該当のmapを返却します
func (n *ScopeNavigator) GetMap() scim.ResourceAttributes {
return n.data
}

// GetScopedMap は 処理対象であるmapまでのスコープをたどり該当のmapを返却します
func (n *ScopeNavigator) GetScopedMap() (scim.ResourceAttributes, string) {
return n.getAttributeScopedMap()
}

// ApplyScopedMap は 処理対象であるmapまでのスコープをたどりscopedMapに置換します
func (n *ScopeNavigator) ApplyScopedMap(scopedMap scim.ResourceAttributes) {
uriScoped := n.getURIScopedMap()
if n.attr.HasSubAttributes() && n.op.Path != nil && n.op.Path.AttributePath.SubAttribute != nil {
if len(scopedMap) == 0 {
delete(uriScoped, n.op.Path.AttributePath.AttributeName)
} else {
uriScoped[n.op.Path.AttributePath.AttributeName] = scopedMap
}
}

data := n.data
uriPrefix, containsURI := containsURIPrefix(n.op.Path)
if containsURI {
if len(uriScoped) == 0 {
delete(data, uriPrefix)
} else {
data[uriPrefix] = uriScoped
}
}
fmt.Printf("%v\n", data)
n.data = data
}

// getURIScopedMap は URIに応じて、処理対象のMapを返却します
func (n *ScopeNavigator) getURIScopedMap() scim.ResourceAttributes {
uriScoped := n.data
uriPrefix, containsURI := containsURIPrefix(n.op.Path)
if containsURI {
data_, ok := n.data[uriPrefix].(map[string]interface{})
switch ok {
case true:
uriScoped = data_
case false:
uriScoped = scim.ResourceAttributes{}
}
}
return uriScoped
}

// getAttributeScopedMap は 属性に応じて、処理対象のMapを返却します
func (n *ScopeNavigator) getAttributeScopedMap() (scim.ResourceAttributes, string) {
// initialize returns
attrName := n.attr.Name()
data := n.getURIScopedMap()
if n.attr.HasSubAttributes() && n.op.Path != nil && n.op.Path.AttributePath.SubAttribute != nil {
data_, ok := data[n.op.Path.AttributePath.AttributeName].(map[string]interface{})
switch ok {
case true:
data = data_
attrName = *n.op.Path.AttributePath.SubAttribute
case false:
data = scim.ResourceAttributes{}
}
}
return data, attrName
}

0 comments on commit 740244c

Please sign in to comment.