Skip to content

Commit 2f8fd5d

Browse files
authored
Merge pull request #1381 from jorwoods/jorwoods/combining_permissionsrules
2 parents 48debe6 + d84fbc2 commit 2f8fd5d

File tree

4 files changed

+156
-1
lines changed

4 files changed

+156
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,4 @@ docs/_site/
156156
docs/.jekyll-metadata
157157
docs/Gemfile.lock
158158
samples/credentials
159+
.venv/

tableauserverclient/models/permissions_item.py

+46-1
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,59 @@ def __repr__(self):
4545
return "<Enum Capability: AddComment | ChangeHierarchy | ChangePermission ... (17 more) >"
4646

4747

48-
class PermissionsRule(object):
48+
class PermissionsRule:
4949
def __init__(self, grantee: ResourceReference, capabilities: Dict[str, str]) -> None:
5050
self.grantee = grantee
5151
self.capabilities = capabilities
5252

5353
def __repr__(self):
5454
return "<PermissionsRule grantee={}, capabilities={}>".format(self.grantee, self.capabilities)
5555

56+
def __eq__(self, other: object) -> bool:
57+
if not hasattr(other, "grantee") or not hasattr(other, "capabilities"):
58+
return False
59+
return self.grantee == other.grantee and self.capabilities == other.capabilities
60+
61+
def __and__(self, other: "PermissionsRule") -> "PermissionsRule":
62+
if self.grantee != other.grantee:
63+
raise ValueError("Cannot AND two permissions rules with different grantees")
64+
65+
if self.capabilities == other.capabilities:
66+
return self
67+
68+
capabilities = set((*self.capabilities.keys(), *other.capabilities.keys()))
69+
new_capabilities = {}
70+
for capability in capabilities:
71+
if (self.capabilities.get(capability), other.capabilities.get(capability)) == (
72+
Permission.Mode.Allow,
73+
Permission.Mode.Allow,
74+
):
75+
new_capabilities[capability] = Permission.Mode.Allow
76+
elif Permission.Mode.Deny in (self.capabilities.get(capability), other.capabilities.get(capability)):
77+
new_capabilities[capability] = Permission.Mode.Deny
78+
79+
return PermissionsRule(self.grantee, new_capabilities)
80+
81+
def __or__(self, other: "PermissionsRule") -> "PermissionsRule":
82+
if self.grantee != other.grantee:
83+
raise ValueError("Cannot OR two permissions rules with different grantees")
84+
85+
if self.capabilities == other.capabilities:
86+
return self
87+
88+
capabilities = set((*self.capabilities.keys(), *other.capabilities.keys()))
89+
new_capabilities = {}
90+
for capability in capabilities:
91+
if Permission.Mode.Allow in (self.capabilities.get(capability), other.capabilities.get(capability)):
92+
new_capabilities[capability] = Permission.Mode.Allow
93+
elif (self.capabilities.get(capability), other.capabilities.get(capability)) == (
94+
Permission.Mode.Deny,
95+
Permission.Mode.Deny,
96+
):
97+
new_capabilities[capability] = Permission.Mode.Deny
98+
99+
return PermissionsRule(self.grantee, new_capabilities)
100+
56101
@classmethod
57102
def from_response(cls, resp, ns=None) -> List["PermissionsRule"]:
58103
parsed_response = fromstring(resp)

tableauserverclient/models/reference_item.py

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ def __str__(self):
88

99
__repr__ = __str__
1010

11+
def __eq__(self, other: object) -> bool:
12+
if not hasattr(other, "id") or not hasattr(other, "tag_name"):
13+
return False
14+
return (self.id == other.id) and (self.tag_name == other.tag_name)
15+
1116
@property
1217
def id(self):
1318
return self._id

test/test_permissionsrule.py

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import unittest
2+
3+
import tableauserverclient as TSC
4+
from tableauserverclient.models.reference_item import ResourceReference
5+
6+
7+
class TestPermissionsRules(unittest.TestCase):
8+
def test_and(self):
9+
grantee = ResourceReference("a", "user")
10+
rule1 = TSC.PermissionsRule(
11+
grantee,
12+
{
13+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
14+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Deny,
15+
TSC.Permission.Capability.ViewComments: TSC.Permission.Mode.Allow,
16+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
17+
},
18+
)
19+
rule2 = TSC.PermissionsRule(
20+
grantee,
21+
{
22+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
23+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Allow,
24+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
25+
},
26+
)
27+
28+
composite = rule1 & rule2
29+
30+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.ExportData), TSC.Permission.Mode.Allow)
31+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.Delete), TSC.Permission.Mode.Deny)
32+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.ViewComments), None)
33+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.ExportXml), TSC.Permission.Mode.Deny)
34+
35+
def test_or(self):
36+
grantee = ResourceReference("a", "user")
37+
rule1 = TSC.PermissionsRule(
38+
grantee,
39+
{
40+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
41+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Deny,
42+
TSC.Permission.Capability.ViewComments: TSC.Permission.Mode.Allow,
43+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
44+
},
45+
)
46+
rule2 = TSC.PermissionsRule(
47+
grantee,
48+
{
49+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
50+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Allow,
51+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
52+
},
53+
)
54+
55+
composite = rule1 | rule2
56+
57+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.ExportData), TSC.Permission.Mode.Allow)
58+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.Delete), TSC.Permission.Mode.Allow)
59+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.ViewComments), TSC.Permission.Mode.Allow)
60+
self.assertEqual(composite.capabilities.get(TSC.Permission.Capability.ExportXml), TSC.Permission.Mode.Deny)
61+
62+
def test_eq_false(self):
63+
grantee = ResourceReference("a", "user")
64+
rule1 = TSC.PermissionsRule(
65+
grantee,
66+
{
67+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
68+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Deny,
69+
TSC.Permission.Capability.ViewComments: TSC.Permission.Mode.Allow,
70+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
71+
},
72+
)
73+
rule2 = TSC.PermissionsRule(
74+
grantee,
75+
{
76+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
77+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Allow,
78+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
79+
},
80+
)
81+
82+
self.assertNotEqual(rule1, rule2)
83+
84+
def test_eq_true(self):
85+
grantee = ResourceReference("a", "user")
86+
rule1 = TSC.PermissionsRule(
87+
grantee,
88+
{
89+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
90+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Deny,
91+
TSC.Permission.Capability.ViewComments: TSC.Permission.Mode.Allow,
92+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
93+
},
94+
)
95+
rule2 = TSC.PermissionsRule(
96+
grantee,
97+
{
98+
TSC.Permission.Capability.ExportData: TSC.Permission.Mode.Allow,
99+
TSC.Permission.Capability.Delete: TSC.Permission.Mode.Deny,
100+
TSC.Permission.Capability.ViewComments: TSC.Permission.Mode.Allow,
101+
TSC.Permission.Capability.ExportXml: TSC.Permission.Mode.Deny,
102+
},
103+
)
104+
self.assertEqual(rule1, rule2)

0 commit comments

Comments
 (0)