Repository: casbin/casbin
Pull request #910 (2021-10-28 04:58:28)

feat: keyMatch5 for ignoring params in url
Fix: https://github.com/casbin/casbin/issues/909

## What problem does this PR solve?
Add KeyMatch5 to ignoring params in URL when matching keys.

Related Issue: #909 

## What is changed and how it works?
Add a new operation `keyMatch5`

## Check List
### Tests

Unit test
### Code changes

Has exported function/method change



Patch:
diff --git a/Makefile b/Makefile
index 92563d5..6db2b92 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ export PATH := $(shell yarn global bin):$(PATH)
 default: lint test
 
 test:
-	go test -race -v .
+	go test -race -v ./...
 
 benchmark:
 	go test -bench=.
diff --git a/model/function.go b/model/function.go
index 2ac426f..4a50415 100644
--- a/model/function.go
+++ b/model/function.go
@@ -44,6 +44,7 @@ func LoadFunctionMap() FunctionMap {
 	fm.AddFunction("keyGet2", util.KeyGet2Func)
 	fm.AddFunction("keyMatch3", util.KeyMatch3Func)
 	fm.AddFunction("keyMatch4", util.KeyMatch4Func)
+	fm.AddFunction("keyMatch5", util.KeyMatch5Func)
 	fm.AddFunction("regexMatch", util.RegexMatchFunc)
 	fm.AddFunction("ipMatch", util.IPMatchFunc)
 	fm.AddFunction("globMatch", util.GlobMatchFunc)
diff --git a/util/builtin_operators.go b/util/builtin_operators.go
index 29cb9f5..3cf351b 100755
--- a/util/builtin_operators.go
+++ b/util/builtin_operators.go
@@ -235,6 +235,29 @@ func KeyMatch4Func(args ...interface{}) (interface{}, error) {
 	return bool(KeyMatch4(name1, name2)), nil
 }
 
+// KeyMatch determines whether key1 matches the pattern of key2 and ignores the parameters in key2.
+// For example, "/foo/bar?status=1&type=2" matches "/foo/bar"
+func KeyMatch5(key1 string, key2 string) bool {
+	i := strings.Index(key1, "?")
+	if i == -1 {
+		return key1 == key2
+	}
+
+	return key1[:i] == key2
+}
+
+// KeyMatch5Func is the wrapper for KeyMatch5.
+func KeyMatch5Func(args ...interface{}) (interface{}, error) {
+	if err := validateVariadicArgs(2, args...); err != nil {
+		return false, fmt.Errorf("%s: %s", "keyMatch5", err)
+	}
+
+	name1 := args[0].(string)
+	name2 := args[1].(string)
+
+	return bool(KeyMatch5(name1, name2)), nil
+}
+
 // RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
 func RegexMatch(key1 string, key2 string) bool {
 	res, err := regexp.MatchString(key2, key1)


Test patch:
diff --git a/util/builtin_operators_test.go b/util/builtin_operators_test.go
index fdc2d7f..1ac786b 100644
--- a/util/builtin_operators_test.go
+++ b/util/builtin_operators_test.go
@@ -333,6 +333,20 @@ func testKeyMatch4Func(t *testing.T, res bool, err string, args ...interface{})
 	}
 }
 
+func testKeyMatch5Func(t *testing.T, res bool, err string, args ...interface{}) {
+	t.Helper()
+	myRes, myErr := KeyMatch5Func(args...)
+	myErrStr := ""
+
+	if myErr != nil {
+		myErrStr = myErr.Error()
+	}
+
+	if myRes != res || err != myErrStr {
+		t.Errorf("%v returns %v %v, supposed to be %v %v", args, myRes, myErr, res, err)
+	}
+}
+
 func testIPMatchFunc(t *testing.T, res bool, err string, args ...interface{}) {
 	t.Helper()
 	myRes, myErr := IPMatchFunc(args...)
@@ -417,6 +431,20 @@ func TestKeyMatch4Func(t *testing.T) {
 
 }
 
+func TestKeyMatch5Func(t *testing.T) {
+	testKeyMatch5Func(t, false, "keyMatch5: Expected 2 arguments, but got 1", "/foo")
+	testKeyMatch5Func(t, false, "keyMatch5: Expected 2 arguments, but got 3", "/foo/create/123", "/foo/*", "/foo/update/123")
+	testKeyMatch5Func(t, false, "keyMatch5: Argument must be a string", "/parent/123", true)
+
+	testKeyMatch5Func(t, true, "", "/parent/child?status=1&type=2", "/parent/child")
+	testKeyMatch5Func(t, false, "", "/parent?status=1&type=2", "/parent/child")
+
+	testKeyMatch5Func(t, true, "", "/parent/child/?status=1&type=2", "/parent/child/")
+	testKeyMatch5Func(t, false, "", "/parent/child/?status=1&type=2", "/parent/child")
+	testKeyMatch5Func(t, false, "", "/parent/child?status=1&type=2", "/parent/child/")
+
+}
+
 func TestIPMatchFunc(t *testing.T) {
 	testIPMatchFunc(t, false, "ipMatch: Expected 2 arguments, but got 1", "192.168.2.123")
 	testIPMatchFunc(t, false, "ipMatch: Argument must be a string", "192.168.2.123", 128)