-
Notifications
You must be signed in to change notification settings - Fork 424
/
Copy pathpermissions_endpoint.py
91 lines (68 loc) · 3.79 KB
/
permissions_endpoint.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import logging
from tableauserverclient.server import RequestFactory
from tableauserverclient.models import TableauItem, PermissionsRule
from .endpoint import Endpoint
from .exceptions import MissingRequiredFieldError
from typing import Callable, TYPE_CHECKING, List, Optional, Union
from tableauserverclient.helpers.logging import logger
if TYPE_CHECKING:
from ..server import Server
from ..request_options import RequestOptions
class _PermissionsEndpoint(Endpoint):
"""Adds permission model to another endpoint
Tableau permissions model is identical between objects, but they are nested under
the parent object endpoint (i.e. permissions for workbooks are under
/workbooks/:id/permission). This class is meant to be instantiated inside a
parent endpoint which has these supported endpoints
"""
def __init__(self, parent_srv: "Server", owner_baseurl: Callable[[], str]) -> None:
super(_PermissionsEndpoint, self).__init__(parent_srv)
# owner_baseurl is the baseurl of the parent. The MUST be a lambda
# since we don't know the full site URL until we sign in. If
# populated without, we will get a sign-in error
self.owner_baseurl = owner_baseurl
def __str__(self):
return "<PermissionsEndpoint baseurl={}>".format(self.owner_baseurl)
def update(self, resource: TableauItem, permissions: List[PermissionsRule]) -> List[PermissionsRule]:
url = "{0}/{1}/permissions".format(self.owner_baseurl(), resource.id)
update_req = RequestFactory.Permission.add_req(permissions)
response = self.put_request(url, update_req)
permissions = PermissionsRule.from_response(response.content, self.parent_srv.namespace)
logger.info("Updated permissions for resource {0}: {1}".format(resource.id, permissions))
return permissions
def delete(self, resource: TableauItem, rules: Union[PermissionsRule, List[PermissionsRule]]):
# Delete is the only endpoint that doesn't take a list of rules
# so let's fake it to keep it consistent
# TODO that means we need error handling around the call
if isinstance(rules, PermissionsRule):
rules = [rules]
for rule in rules:
for capability, mode in rule.capabilities.items():
"/permissions/groups/group-id/capability-name/capability-mode"
url = "{0}/{1}/permissions/{2}/{3}/{4}/{5}".format(
self.owner_baseurl(),
resource.id,
rule.grantee.tag_name + "s",
rule.grantee.id,
capability,
mode,
)
logger.debug("Removing {0} permission for capability {1}".format(mode, capability))
self.delete_request(url)
logger.info(
"Deleted permission for {0} {1} item {2}".format(rule.grantee.tag_name, rule.grantee.id, resource.id)
)
def populate(self, item: TableauItem):
if not item.id:
error = "Server item is missing ID. Item must be retrieved from server first."
raise MissingRequiredFieldError(error)
def permission_fetcher():
return self._get_permissions(item)
item._set_permissions(permission_fetcher)
logger.info("Populated permissions for item (ID: {0})".format(item.id))
def _get_permissions(self, item: TableauItem, req_options: Optional["RequestOptions"] = None):
url = "{0}/{1}/permissions".format(self.owner_baseurl(), item.id)
server_response = self.get_request(url, req_options)
permissions = PermissionsRule.from_response(server_response.content, self.parent_srv.namespace)
logger.info("Permissions for resource {0}: {1}".format(item.id, permissions))
return permissions