From 5b556a666168059ac1873961a6432ab2382925d1 Mon Sep 17 00:00:00 2001 From: Amar Yadav Date: Thu, 26 May 2022 19:24:24 +0530 Subject: [PATCH 1/7] added new permission populate methods --- tableauserverclient/models/permissions_item.py | 4 ++++ tableauserverclient/models/project_item.py | 8 ++++++++ .../server/endpoint/projects_endpoint.py | 12 ++++++++++++ 3 files changed, 24 insertions(+) diff --git a/tableauserverclient/models/permissions_item.py b/tableauserverclient/models/permissions_item.py index 71ca56248..100f55f26 100644 --- a/tableauserverclient/models/permissions_item.py +++ b/tableauserverclient/models/permissions_item.py @@ -37,6 +37,9 @@ class Capability: ViewUnderlyingData = "ViewUnderlyingData" WebAuthoring = "WebAuthoring" Write = "Write" + RunExplainData='RunExplainData' + CreateRefreshMetrics='CreateRefreshMetrics' + SaveAs='SaveAs' class Resource: Workbook = "workbook" @@ -45,6 +48,7 @@ class Resource: Table = "table" Database = "database" View = "view" + Lense = 'lense' class PermissionsRule(object): diff --git a/tableauserverclient/models/project_item.py b/tableauserverclient/models/project_item.py index 2d3aa2eb4..4aab792c1 100644 --- a/tableauserverclient/models/project_item.py +++ b/tableauserverclient/models/project_item.py @@ -34,6 +34,7 @@ def __init__( self._default_workbook_permissions = None self._default_datasource_permissions = None self._default_flow_permissions = None + self._default_lense_permissions = None @property def content_permissions(self): @@ -72,6 +73,13 @@ def default_flow_permissions(self): raise UnpopulatedPropertyError(error) return self._default_flow_permissions() + @property + def default_lense_permissions(self): + if self._default_lense_permissions is None: + error = "Project item must be populated with permissions first." + raise UnpopulatedPropertyError(error) + return self._default_lense_permissions() + @property def id(self) -> Optional[str]: return self._id diff --git a/tableauserverclient/server/endpoint/projects_endpoint.py b/tableauserverclient/server/endpoint/projects_endpoint.py index b21ba3682..eca4c0d03 100644 --- a/tableauserverclient/server/endpoint/projects_endpoint.py +++ b/tableauserverclient/server/endpoint/projects_endpoint.py @@ -103,6 +103,10 @@ def populate_datasource_default_permissions(self, item): def populate_flow_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Flow) + @api(version='3.4') + def populate_lense_default_permissions(self, item): + self._default_permissions.populate_default_permissions(item, Permission.Resource.Lense) + @api(version="2.1") def update_workbook_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Workbook) @@ -115,6 +119,10 @@ def update_datasource_default_permissions(self, item, rules): def update_flow_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Flow) + @api(version='3.4') + def update_lense_default_permissions(self, item, rules): + return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Lense) + @api(version="2.1") def delete_workbook_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Workbook) @@ -126,3 +134,7 @@ def delete_datasource_default_permissions(self, item, rule): @api(version="3.4") def delete_flow_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Flow) + + @api(version='3.4') + def delete_lense_default_permissions(self, item, rule): + self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Lense) From a7c3c29fce21f348c09a4aa9a1dfab4b9d970a0a Mon Sep 17 00:00:00 2001 From: Amar Yadav Date: Wed, 1 Jun 2022 16:37:22 +0530 Subject: [PATCH 2/7] changed lense to lens --- tableauserverclient/models/permissions_item.py | 2 +- tableauserverclient/models/project_item.py | 8 ++++---- .../server/endpoint/projects_endpoint.py | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tableauserverclient/models/permissions_item.py b/tableauserverclient/models/permissions_item.py index 100f55f26..2ec2b76f1 100644 --- a/tableauserverclient/models/permissions_item.py +++ b/tableauserverclient/models/permissions_item.py @@ -48,7 +48,7 @@ class Resource: Table = "table" Database = "database" View = "view" - Lense = 'lense' + Lens = 'lense' class PermissionsRule(object): diff --git a/tableauserverclient/models/project_item.py b/tableauserverclient/models/project_item.py index 4aab792c1..bd382dfc6 100644 --- a/tableauserverclient/models/project_item.py +++ b/tableauserverclient/models/project_item.py @@ -34,7 +34,7 @@ def __init__( self._default_workbook_permissions = None self._default_datasource_permissions = None self._default_flow_permissions = None - self._default_lense_permissions = None + self._default_lens_permissions = None @property def content_permissions(self): @@ -74,11 +74,11 @@ def default_flow_permissions(self): return self._default_flow_permissions() @property - def default_lense_permissions(self): - if self._default_lense_permissions is None: + def default_lens_permissions(self): + if self._default_lens_permissions is None: error = "Project item must be populated with permissions first." raise UnpopulatedPropertyError(error) - return self._default_lense_permissions() + return self._default_lens_permissions() @property def id(self) -> Optional[str]: diff --git a/tableauserverclient/server/endpoint/projects_endpoint.py b/tableauserverclient/server/endpoint/projects_endpoint.py index eca4c0d03..e0f27dcff 100644 --- a/tableauserverclient/server/endpoint/projects_endpoint.py +++ b/tableauserverclient/server/endpoint/projects_endpoint.py @@ -104,8 +104,8 @@ def populate_flow_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Flow) @api(version='3.4') - def populate_lense_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item, Permission.Resource.Lense) + def populate_lens_default_permissions(self, item): + self._default_permissions.populate_default_permissions(item, Permission.Resource.Lens) @api(version="2.1") def update_workbook_default_permissions(self, item, rules): @@ -120,8 +120,8 @@ def update_flow_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Flow) @api(version='3.4') - def update_lense_default_permissions(self, item, rules): - return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Lense) + def update_lens_default_permissions(self, item, rules): + return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Lens) @api(version="2.1") def delete_workbook_default_permissions(self, item, rule): @@ -136,5 +136,5 @@ def delete_flow_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Flow) @api(version='3.4') - def delete_lense_default_permissions(self, item, rule): - self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Lense) + def delete_lens_default_permissions(self, item, rule): + self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Lens) From f15d3716ce5a0395ff9ee7fefe379dd679fb7ad9 Mon Sep 17 00:00:00 2001 From: Amar Yadav Date: Thu, 2 Jun 2022 14:11:55 +0530 Subject: [PATCH 3/7] reformatted with black --- tableauserverclient/models/permissions_item.py | 8 ++++---- tableauserverclient/server/endpoint/projects_endpoint.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tableauserverclient/models/permissions_item.py b/tableauserverclient/models/permissions_item.py index 2ec2b76f1..35afb248d 100644 --- a/tableauserverclient/models/permissions_item.py +++ b/tableauserverclient/models/permissions_item.py @@ -37,9 +37,9 @@ class Capability: ViewUnderlyingData = "ViewUnderlyingData" WebAuthoring = "WebAuthoring" Write = "Write" - RunExplainData='RunExplainData' - CreateRefreshMetrics='CreateRefreshMetrics' - SaveAs='SaveAs' + RunExplainData = "RunExplainData" + CreateRefreshMetrics = "CreateRefreshMetrics" + SaveAs = "SaveAs" class Resource: Workbook = "workbook" @@ -48,7 +48,7 @@ class Resource: Table = "table" Database = "database" View = "view" - Lens = 'lense' + Lens = "lense" class PermissionsRule(object): diff --git a/tableauserverclient/server/endpoint/projects_endpoint.py b/tableauserverclient/server/endpoint/projects_endpoint.py index e0f27dcff..8edf66f39 100644 --- a/tableauserverclient/server/endpoint/projects_endpoint.py +++ b/tableauserverclient/server/endpoint/projects_endpoint.py @@ -103,7 +103,7 @@ def populate_datasource_default_permissions(self, item): def populate_flow_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Flow) - @api(version='3.4') + @api(version="3.4") def populate_lens_default_permissions(self, item): self._default_permissions.populate_default_permissions(item, Permission.Resource.Lens) @@ -119,7 +119,7 @@ def update_datasource_default_permissions(self, item, rules): def update_flow_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Flow) - @api(version='3.4') + @api(version="3.4") def update_lens_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Lens) @@ -135,6 +135,6 @@ def delete_datasource_default_permissions(self, item, rule): def delete_flow_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Flow) - @api(version='3.4') + @api(version="3.4") def delete_lens_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Lens) From dc2876001ef28b13ae74b3fc51ca60f9d15787c0 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Thu, 2 Jun 2022 16:11:43 -0700 Subject: [PATCH 4/7] edit resource name to "Lens" --- tableauserverclient/models/permissions_item.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tableauserverclient/models/permissions_item.py b/tableauserverclient/models/permissions_item.py index 35afb248d..fcb758279 100644 --- a/tableauserverclient/models/permissions_item.py +++ b/tableauserverclient/models/permissions_item.py @@ -48,7 +48,7 @@ class Resource: Table = "table" Database = "database" View = "view" - Lens = "lense" + Lens = "lens" class PermissionsRule(object): From e954cdcaa9a3e1475d3abefaeb1db09851e35fe8 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Fri, 3 Jun 2022 16:55:30 -0700 Subject: [PATCH 5/7] refactor Resource Types and add sample code accessing default permissions --- samples/create_project.py | 20 ++++++- tableauserverclient/__init__.py | 3 + tableauserverclient/models/__init__.py | 3 +- tableauserverclient/models/database_item.py | 6 +- .../models/permissions_item.py | 14 ++--- tableauserverclient/models/project_item.py | 10 +++- tableauserverclient/models/reference_item.py | 5 ++ tableauserverclient/models/tableau_types.py | 31 ++++++++++ tableauserverclient/server/__init__.py | 3 + .../server/endpoint/databases_endpoint.py | 10 ++-- .../endpoint/default_permissions_endpoint.py | 59 +++++++++---------- .../server/endpoint/permissions_endpoint.py | 12 ++-- .../server/endpoint/projects_endpoint.py | 34 ++++++----- 13 files changed, 139 insertions(+), 71 deletions(-) create mode 100644 tableauserverclient/models/tableau_types.py diff --git a/samples/create_project.py b/samples/create_project.py index 1fa563fca..6c9c9b3e0 100644 --- a/samples/create_project.py +++ b/samples/create_project.py @@ -21,7 +21,8 @@ def create_project(server, project_item, samples=False): return project_item except TSC.ServerResponseError: print("We have already created this project: %s" % project_item.name) - sys.exit(1) + project_items = server.projects.filter(name=project_item.name) + return project_items[0] def main(): @@ -52,7 +53,8 @@ def main(): logging.basicConfig(level=logging_level) tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site) - server = TSC.Server(args.server) + server = TSC.Server(args.server, http_options={'verify': False}) + server.use_server_version() with server.auth.sign_in(tableau_auth): # Use highest Server REST API version available @@ -73,6 +75,20 @@ def main(): # Projects can be updated changed_project = server.projects.update(grand_child_project, samples=True) + server.projects.populate_workbook_default_permissions(changed_project), + server.projects.populate_flow_default_permissions(changed_project), + server.projects.populate_lens_default_permissions(changed_project), # uses same as workbook + server.projects.populate_datasource_default_permissions(changed_project), + server.projects.populate_permissions(changed_project) + # Projects have default permissions set for the object types they contain + print("Permissions from project {}:".format(changed_project.id)) + print(changed_project.permissions) + print( + changed_project.default_workbook_permissions, + changed_project.default_datasource_permissions, + changed_project.default_lens_permissions, + changed_project.default_flow_permissions, + ) if __name__ == "__main__": main() diff --git a/tableauserverclient/__init__.py b/tableauserverclient/__init__.py index 2ca56b6a5..4eda978cd 100644 --- a/tableauserverclient/__init__.py +++ b/tableauserverclient/__init__.py @@ -37,6 +37,9 @@ FlowRunItem, RevisionItem, MetricItem, + TableauItem, + Resource, + plural_type ) from .namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE from .server import ( diff --git a/tableauserverclient/models/__init__.py b/tableauserverclient/models/__init__.py index 20bbeb751..451502a9c 100644 --- a/tableauserverclient/models/__init__.py +++ b/tableauserverclient/models/__init__.py @@ -29,7 +29,8 @@ from .site_item import SiteItem from .subscription_item import SubscriptionItem from .table_item import TableItem -from .tableau_auth import Credentials, TableauAuth, PersonalAccessTokenAuth +from .tableau_auth import TableauAuth +from .tableau_types import Resource, TableauItem, plural_type from .target import Target from .task_item import TaskItem from .user_item import UserItem diff --git a/tableauserverclient/models/database_item.py b/tableauserverclient/models/database_item.py index 862a51a11..3d5a00a1a 100644 --- a/tableauserverclient/models/database_item.py +++ b/tableauserverclient/models/database_item.py @@ -1,3 +1,5 @@ +import logging + from defusedxml.ElementTree import fromstring from .exceptions import UnpopulatedPropertyError @@ -242,11 +244,13 @@ def _set_tables(self, tables): self._tables = tables def _set_default_permissions(self, permissions, content_type): + attr = "_default_{content}_permissions".format(content=content_type) setattr( self, - "_default_{content}_permissions".format(content=content_type), + attr, permissions, ) + logging.getLogger().debug({"type": attr, "value": getattr(self, attr)}) def _set_data_quality_warnings(self, dqw): self._data_quality_warnings = dqw diff --git a/tableauserverclient/models/permissions_item.py b/tableauserverclient/models/permissions_item.py index fcb758279..1c1e9db4d 100644 --- a/tableauserverclient/models/permissions_item.py +++ b/tableauserverclient/models/permissions_item.py @@ -41,21 +41,17 @@ class Capability: CreateRefreshMetrics = "CreateRefreshMetrics" SaveAs = "SaveAs" - class Resource: - Workbook = "workbook" - Datasource = "datasource" - Flow = "flow" - Table = "table" - Database = "database" - View = "view" - Lens = "lens" - class PermissionsRule(object): def __init__(self, grantee: "ResourceReference", capabilities: Dict[str, str]) -> None: self.grantee = grantee self.capabilities = capabilities + def __str__(self): + return "".format(self.grantee, self.capabilities) + + __repr__ = __str__ + @classmethod def from_response(cls, resp, ns=None) -> List["PermissionsRule"]: parsed_response = fromstring(resp) diff --git a/tableauserverclient/models/project_item.py b/tableauserverclient/models/project_item.py index bd382dfc6..891af554b 100644 --- a/tableauserverclient/models/project_item.py +++ b/tableauserverclient/models/project_item.py @@ -1,11 +1,13 @@ +import logging import xml.etree.ElementTree as ET -from typing import List, Optional from defusedxml.ElementTree import fromstring from .exceptions import UnpopulatedPropertyError from .property_decorators import property_is_enum, property_not_empty +from typing import List, Optional + from typing import List, Optional, TYPE_CHECKING @@ -137,11 +139,15 @@ def _set_permissions(self, permissions): self._permissions = permissions def _set_default_permissions(self, permissions, content_type): + attr = "_default_{content}_permissions".format(content=content_type) setattr( self, - "_default_{content}_permissions".format(content=content_type), + attr, permissions, ) + fetch_call = getattr(self, attr) + logging.getLogger().info({"type" :attr, "value": fetch_call()}) + return fetch_call() @classmethod def from_response(cls, resp, ns) -> List["ProjectItem"]: diff --git a/tableauserverclient/models/reference_item.py b/tableauserverclient/models/reference_item.py index 48d2ab56a..6fc6b0c22 100644 --- a/tableauserverclient/models/reference_item.py +++ b/tableauserverclient/models/reference_item.py @@ -3,6 +3,11 @@ def __init__(self, id_, tag_name): self.id = id_ self.tag_name = tag_name + def __str__(self): + return "".format(self._id, self._tag_name) + + __repr__ = __str__ + @property def id(self): return self._id diff --git a/tableauserverclient/models/tableau_types.py b/tableauserverclient/models/tableau_types.py new file mode 100644 index 000000000..0c5c00159 --- /dev/null +++ b/tableauserverclient/models/tableau_types.py @@ -0,0 +1,31 @@ +from tableauserverclient.models.database_item import DatabaseItem +from tableauserverclient.models.datasource_item import DatasourceItem +from tableauserverclient.models.flow_item import FlowItem +from tableauserverclient.models.project_item import ProjectItem +from tableauserverclient.models.table_item import TableItem +from tableauserverclient.models.view_item import ViewItem +from tableauserverclient.models.workbook_item import WorkbookItem + +from typing import Union + + +class Resource: + Database = "database" + Datasource = "datasource" + Flow = "flow" + Lens = "lens" + Project = "project" + Table = "table" + View = "view" + Workbook = "workbook" + + +# resource types that have permissions, can be renamed, etc +TableauItem = Union[DatasourceItem, FlowItem, ProjectItem, ViewItem, WorkbookItem] + + +def plural_type(type: Resource) -> str: + if type == Resource.Lens: + return "lenses" + else: + return type + "s" diff --git a/tableauserverclient/server/__init__.py b/tableauserverclient/server/__init__.py index 335306db8..95f508189 100644 --- a/tableauserverclient/server/__init__.py +++ b/tableauserverclient/server/__init__.py @@ -36,6 +36,9 @@ ViewItem, WebhookItem, WorkbookItem, + TableauItem, + Resource, + plural_type ) from .endpoint import ( Auth, diff --git a/tableauserverclient/server/endpoint/databases_endpoint.py b/tableauserverclient/server/endpoint/databases_endpoint.py index 255b7b7a3..66d064a1f 100644 --- a/tableauserverclient/server/endpoint/databases_endpoint.py +++ b/tableauserverclient/server/endpoint/databases_endpoint.py @@ -5,7 +5,7 @@ from .endpoint import api, Endpoint from .exceptions import MissingRequiredFieldError from .permissions_endpoint import _PermissionsEndpoint -from .. import RequestFactory, DatabaseItem, TableItem, PaginationItem, Permission +from .. import RequestFactory, DatabaseItem, TableItem, PaginationItem, Resource logger = logging.getLogger("tableau.endpoint.databases") @@ -16,7 +16,7 @@ def __init__(self, parent_srv): self._permissions = _PermissionsEndpoint(parent_srv, lambda: self.baseurl) self._default_permissions = _DefaultPermissionsEndpoint(parent_srv, lambda: self.baseurl) - self._data_quality_warnings = _DataQualityWarningEndpoint(parent_srv, "database") + self._data_quality_warnings = _DataQualityWarningEndpoint(parent_srv, Resource.Database) @property def baseurl(self): @@ -108,15 +108,15 @@ def delete_permission(self, item, rules): @api(version="3.5") def populate_table_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item, Permission.Resource.Table) + self._default_permissions.populate_default_permissions(item,Resource.Table) @api(version="3.5") def update_table_default_permissions(self, item): - return self._default_permissions.update_default_permissions(item, Permission.Resource.Table) + return self._default_permissions.update_default_permissions(item,Resource.Table) @api(version="3.5") def delete_table_default_permissions(self, item): - self._default_permissions.delete_default_permissions(item, Permission.Resource.Table) + self._default_permissions.delete_default_permissions(item,Resource.Table) @api(version="3.5") def populate_dqw(self, item): diff --git a/tableauserverclient/server/endpoint/default_permissions_endpoint.py b/tableauserverclient/server/endpoint/default_permissions_endpoint.py index 6e54d02c7..4a81d67ef 100644 --- a/tableauserverclient/server/endpoint/default_permissions_endpoint.py +++ b/tableauserverclient/server/endpoint/default_permissions_endpoint.py @@ -3,56 +3,53 @@ from .endpoint import Endpoint from .exceptions import MissingRequiredFieldError from .. import RequestFactory -from ...models import PermissionsRule - -logger = logging.getLogger(__name__) - +from ...models import DatabaseItem, PermissionsRule, ProjectItem, plural_type, Resource from typing import TYPE_CHECKING, Callable, List, Optional, Sequence, Union if TYPE_CHECKING: - from ...models import ( - DatasourceItem, - FlowItem, - ProjectItem, - ViewItem, - WorkbookItem, - ) - from ..server import Server from ..request_options import RequestOptions - TableauItem = Union[DatasourceItem, FlowItem, ProjectItem, ViewItem, WorkbookItem] +logger = logging.getLogger(__name__) + +# these are the only two items that can hold default permissions for another type +BaseItem = Union[DatabaseItem, ProjectItem] class _DefaultPermissionsEndpoint(Endpoint): - """Adds default-permission model to another endpoint + """Adds default-permission model to an existing database or project - Tableau default-permissions model applies only to databases and projects - and then takes an object type in the uri to set the defaults. - This class is meant to be instantated inside a parent endpoint which + Tableau default-permissions model takes an object type in the uri to set the defaults. + 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(_DefaultPermissionsEndpoint, 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 + # owner_baseurl is the baseurl of the parent, a project or database. + # It 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 "".format(self.owner_baseurl()) + + __repr__ = __str__ + def update_default_permissions( - self, resource: "TableauItem", permissions: Sequence[PermissionsRule], content_type: str + self, resource: BaseItem, permissions: Sequence[PermissionsRule], content_type: Resource ) -> List[PermissionsRule]: - url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), resource.id, content_type + "s") + url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), resource.id, plural_type(content_type)) 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}".format(resource.id)) + logger.info("Updated default {} permissions for resource {}".format(content_type, resource.id)) + logger.info(permissions) return permissions - def delete_default_permission(self, resource: "TableauItem", rule: PermissionsRule, content_type: str) -> None: + def delete_default_permission(self, resource: BaseItem, rule: PermissionsRule, content_type: Resource) -> None: for capability, mode in rule.capabilities.items(): # Made readability better but line is too long, will make this look better url = ( @@ -60,7 +57,7 @@ def delete_default_permission(self, resource: "TableauItem", rule: PermissionsRu "{content_type}/{grantee_type}/{grantee_id}/{cap}/{mode}".format( baseurl=self.owner_baseurl(), content_id=resource.id, - content_type=content_type + "s", + content_type=plural_type(content_type), grantee_type=rule.grantee.tag_name + "s", grantee_id=rule.grantee.id, cap=capability, @@ -68,7 +65,7 @@ def delete_default_permission(self, resource: "TableauItem", rule: PermissionsRu ) ) - logger.debug("Removing {0} permission for capabilty {1}".format(mode, capability)) + logger.debug("Removing {0} permission for capability {1}".format(mode, capability)) self.delete_request(url) @@ -76,7 +73,7 @@ def delete_default_permission(self, resource: "TableauItem", rule: PermissionsRu "Deleted permission for {0} {1} item {2}".format(rule.grantee.tag_name, rule.grantee.id, resource.id) ) - def populate_default_permissions(self, item: "ProjectItem", content_type: str) -> None: + def populate_default_permissions(self, item: BaseItem, content_type: Resource) -> None: if not item.id: error = "Server item is missing ID. Item must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -85,13 +82,13 @@ def permission_fetcher() -> List[PermissionsRule]: return self._get_default_permissions(item, content_type) item._set_default_permissions(permission_fetcher, content_type) - logger.info("Populated {0} permissions for item (ID: {1})".format(item.id, content_type)) + logger.info("Populated default {0} permissions for item (ID: {1})".format(content_type, item.id)) def _get_default_permissions( - self, item: "TableauItem", content_type: str, req_options: Optional["RequestOptions"] = None + self, item: BaseItem, content_type: Resource, req_options: Optional["RequestOptions"] = None ) -> List[PermissionsRule]: - url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), item.id, content_type + "s") + url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), item.id, plural_type(content_type)) server_response = self.get_request(url, req_options) permissions = PermissionsRule.from_response(server_response.content, self.parent_srv.namespace) - + logger.info({"content_type": content_type, "permissions":permissions}) return permissions diff --git a/tableauserverclient/server/endpoint/permissions_endpoint.py b/tableauserverclient/server/endpoint/permissions_endpoint.py index 10a1d9fac..f7c2f9f13 100644 --- a/tableauserverclient/server/endpoint/permissions_endpoint.py +++ b/tableauserverclient/server/endpoint/permissions_endpoint.py @@ -5,17 +5,15 @@ from .endpoint import Endpoint from .exceptions import MissingRequiredFieldError +from ...models import TableauItem from typing import Callable, TYPE_CHECKING, List, Union logger = logging.getLogger(__name__) if TYPE_CHECKING: - from ...models import DatasourceItem, ProjectItem, WorkbookItem, ViewItem from ..server import Server from ..request_options import RequestOptions -TableauItem = Union["DatasourceItem", "ProjectItem", "WorkbookItem", "ViewItem"] - class _PermissionsEndpoint(Endpoint): """Adds permission model to another endpoint @@ -34,12 +32,15 @@ def __init__(self, parent_srv: "Server", owner_baseurl: Callable[[], str]) -> No # populated without, we will get a sign-in error self.owner_baseurl = owner_baseurl + def __str__(self): + return "".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}".format(resource.id)) + logger.info("Updated permissions for resource {0}: {1}".format(resource.id, permissions)) return permissions @@ -62,7 +63,7 @@ def delete(self, resource: TableauItem, rules: Union[PermissionsRule, List[Permi mode, ) - logger.debug("Removing {0} permission for capabilty {1}".format(mode, capability)) + logger.debug("Removing {0} permission for capability {1}".format(mode, capability)) self.delete_request(url) @@ -85,5 +86,6 @@ def _get_permissions(self, item: TableauItem, req_options: "RequestOptions" = No 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 diff --git a/tableauserverclient/server/endpoint/projects_endpoint.py b/tableauserverclient/server/endpoint/projects_endpoint.py index 8edf66f39..7ae07b4c9 100644 --- a/tableauserverclient/server/endpoint/projects_endpoint.py +++ b/tableauserverclient/server/endpoint/projects_endpoint.py @@ -4,9 +4,7 @@ from .endpoint import QuerysetEndpoint, api, XML_CONTENT_TYPE from .exceptions import MissingRequiredFieldError from .permissions_endpoint import _PermissionsEndpoint -from .. import RequestFactory, RequestOptions, ProjectItem, PaginationItem, Permission - -logger = logging.getLogger("tableau.endpoint.projects") +from .. import RequestFactory, RequestOptions, ProjectItem, PaginationItem, Resource from typing import List, Optional, Tuple, TYPE_CHECKING @@ -14,6 +12,8 @@ from ..server import Server from ..request_options import RequestOptions +logger = logging.getLogger("tableau.endpoint.projects") + class Projects(QuerysetEndpoint): def __init__(self, parent_srv: "Server") -> None: @@ -93,48 +93,52 @@ def delete_permission(self, item, rules): @api(version="2.1") def populate_workbook_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item, Permission.Resource.Workbook) + self._default_permissions.populate_default_permissions(item, Resource.Workbook) @api(version="2.1") def populate_datasource_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item, Permission.Resource.Datasource) + self._default_permissions.populate_default_permissions(item, Resource.Datasource) @api(version="3.4") def populate_flow_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item, Permission.Resource.Flow) + self._default_permissions.populate_default_permissions(item, Resource.Flow) @api(version="3.4") def populate_lens_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item, Permission.Resource.Lens) + self._default_permissions.populate_default_permissions(item, Resource.Lens) @api(version="2.1") def update_workbook_default_permissions(self, item, rules): - return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Workbook) + return self._default_permissions.update_default_permissions(item, rules, Resource.Workbook) @api(version="2.1") def update_datasource_default_permissions(self, item, rules): - return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Datasource) + return self._default_permissions.update_default_permissions(item, rules, Resource.Datasource) @api(version="3.4") def update_flow_default_permissions(self, item, rules): - return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Flow) + return self._default_permissions.update_default_permissions(item, rules, Resource.Flow) + + @api(version="3.4") + def update_lens_default_permissions(self, item, rules): + return self._default_permissions.update_default_permissions(item, rules, Resource.Lens) @api(version="3.4") def update_lens_default_permissions(self, item, rules): - return self._default_permissions.update_default_permissions(item, rules, Permission.Resource.Lens) + return self._default_permissions.update_default_permissions(item, rules, Resource.Lens) @api(version="2.1") def delete_workbook_default_permissions(self, item, rule): - self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Workbook) + self._default_permissions.delete_default_permission(item, rule, Resource.Workbook) @api(version="2.1") def delete_datasource_default_permissions(self, item, rule): - self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Datasource) + self._default_permissions.delete_default_permission(item, rule, Resource.Datasource) @api(version="3.4") def delete_flow_default_permissions(self, item, rule): - self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Flow) + self._default_permissions.delete_default_permission(item, rule, Resource.Flow) @api(version="3.4") def delete_lens_default_permissions(self, item, rule): - self._default_permissions.delete_default_permission(item, rule, Permission.Resource.Lens) + self._default_permissions.delete_default_permission(item, rule, Resource.Lens) From c6c9e9ccc0754815db9bfe2e01413bb43167106d Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Fri, 3 Jun 2022 17:00:33 -0700 Subject: [PATCH 6/7] fixup: black and mypy --- samples/create_project.py | 5 +++-- tableauserverclient/__init__.py | 2 +- tableauserverclient/models/__init__.py | 2 ++ tableauserverclient/models/project_item.py | 2 +- tableauserverclient/models/tableau_types.py | 6 +++--- tableauserverclient/server/__init__.py | 2 +- tableauserverclient/server/endpoint/databases_endpoint.py | 6 +++--- .../server/endpoint/default_permissions_endpoint.py | 2 +- tableauserverclient/server/endpoint/projects_endpoint.py | 4 ---- 9 files changed, 15 insertions(+), 16 deletions(-) diff --git a/samples/create_project.py b/samples/create_project.py index 6c9c9b3e0..8b2ec3354 100644 --- a/samples/create_project.py +++ b/samples/create_project.py @@ -53,7 +53,7 @@ def main(): logging.basicConfig(level=logging_level) tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site) - server = TSC.Server(args.server, http_options={'verify': False}) + server = TSC.Server(args.server, http_options={"verify": False}) server.use_server_version() with server.auth.sign_in(tableau_auth): @@ -88,7 +88,8 @@ def main(): changed_project.default_datasource_permissions, changed_project.default_lens_permissions, changed_project.default_flow_permissions, - ) + ) + if __name__ == "__main__": main() diff --git a/tableauserverclient/__init__.py b/tableauserverclient/__init__.py index 4eda978cd..592551b4e 100644 --- a/tableauserverclient/__init__.py +++ b/tableauserverclient/__init__.py @@ -39,7 +39,7 @@ MetricItem, TableauItem, Resource, - plural_type + plural_type, ) from .namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE from .server import ( diff --git a/tableauserverclient/models/__init__.py b/tableauserverclient/models/__init__.py index 451502a9c..577a946d9 100644 --- a/tableauserverclient/models/__init__.py +++ b/tableauserverclient/models/__init__.py @@ -22,6 +22,8 @@ from .metric_item import MetricItem from .pagination_item import PaginationItem from .permissions_item import PermissionsRule, Permission +from .personal_access_token_auth import PersonalAccessTokenAuth +from .personal_access_token_auth import PersonalAccessTokenAuth from .project_item import ProjectItem from .revision_item import RevisionItem from .schedule_item import ScheduleItem diff --git a/tableauserverclient/models/project_item.py b/tableauserverclient/models/project_item.py index 891af554b..9237d134e 100644 --- a/tableauserverclient/models/project_item.py +++ b/tableauserverclient/models/project_item.py @@ -146,7 +146,7 @@ def _set_default_permissions(self, permissions, content_type): permissions, ) fetch_call = getattr(self, attr) - logging.getLogger().info({"type" :attr, "value": fetch_call()}) + logging.getLogger().info({"type": attr, "value": fetch_call()}) return fetch_call() @classmethod diff --git a/tableauserverclient/models/tableau_types.py b/tableauserverclient/models/tableau_types.py index 0c5c00159..feaf02873 100644 --- a/tableauserverclient/models/tableau_types.py +++ b/tableauserverclient/models/tableau_types.py @@ -24,8 +24,8 @@ class Resource: TableauItem = Union[DatasourceItem, FlowItem, ProjectItem, ViewItem, WorkbookItem] -def plural_type(type: Resource) -> str: - if type == Resource.Lens: +def plural_type(content_type: Resource) -> str: + if content_type == Resource.Lens: return "lenses" else: - return type + "s" + return "{}s".format(content_type) diff --git a/tableauserverclient/server/__init__.py b/tableauserverclient/server/__init__.py index 95f508189..cb680d914 100644 --- a/tableauserverclient/server/__init__.py +++ b/tableauserverclient/server/__init__.py @@ -38,7 +38,7 @@ WorkbookItem, TableauItem, Resource, - plural_type + plural_type, ) from .endpoint import ( Auth, diff --git a/tableauserverclient/server/endpoint/databases_endpoint.py b/tableauserverclient/server/endpoint/databases_endpoint.py index 66d064a1f..1fab7ac4b 100644 --- a/tableauserverclient/server/endpoint/databases_endpoint.py +++ b/tableauserverclient/server/endpoint/databases_endpoint.py @@ -108,15 +108,15 @@ def delete_permission(self, item, rules): @api(version="3.5") def populate_table_default_permissions(self, item): - self._default_permissions.populate_default_permissions(item,Resource.Table) + self._default_permissions.populate_default_permissions(item, Resource.Table) @api(version="3.5") def update_table_default_permissions(self, item): - return self._default_permissions.update_default_permissions(item,Resource.Table) + return self._default_permissions.update_default_permissions(item, Resource.Table) @api(version="3.5") def delete_table_default_permissions(self, item): - self._default_permissions.delete_default_permissions(item,Resource.Table) + self._default_permissions.delete_default_permissions(item, Resource.Table) @api(version="3.5") def populate_dqw(self, item): diff --git a/tableauserverclient/server/endpoint/default_permissions_endpoint.py b/tableauserverclient/server/endpoint/default_permissions_endpoint.py index 4a81d67ef..66fc23d49 100644 --- a/tableauserverclient/server/endpoint/default_permissions_endpoint.py +++ b/tableauserverclient/server/endpoint/default_permissions_endpoint.py @@ -90,5 +90,5 @@ def _get_default_permissions( url = "{0}/{1}/default-permissions/{2}".format(self.owner_baseurl(), item.id, plural_type(content_type)) server_response = self.get_request(url, req_options) permissions = PermissionsRule.from_response(server_response.content, self.parent_srv.namespace) - logger.info({"content_type": content_type, "permissions":permissions}) + logger.info({"content_type": content_type, "permissions": permissions}) return permissions diff --git a/tableauserverclient/server/endpoint/projects_endpoint.py b/tableauserverclient/server/endpoint/projects_endpoint.py index 7ae07b4c9..e268d2011 100644 --- a/tableauserverclient/server/endpoint/projects_endpoint.py +++ b/tableauserverclient/server/endpoint/projects_endpoint.py @@ -123,10 +123,6 @@ def update_flow_default_permissions(self, item, rules): def update_lens_default_permissions(self, item, rules): return self._default_permissions.update_default_permissions(item, rules, Resource.Lens) - @api(version="3.4") - def update_lens_default_permissions(self, item, rules): - return self._default_permissions.update_default_permissions(item, rules, Resource.Lens) - @api(version="2.1") def delete_workbook_default_permissions(self, item, rule): self._default_permissions.delete_default_permission(item, rule, Resource.Workbook) From b56ec3bfb6b8130d5526a7d8e7b005466a2923dd Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Fri, 3 Jun 2022 20:06:33 -0700 Subject: [PATCH 7/7] fix imports --- tableauserverclient/models/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tableauserverclient/models/__init__.py b/tableauserverclient/models/__init__.py index 577a946d9..58e5ed6d1 100644 --- a/tableauserverclient/models/__init__.py +++ b/tableauserverclient/models/__init__.py @@ -22,8 +22,6 @@ from .metric_item import MetricItem from .pagination_item import PaginationItem from .permissions_item import PermissionsRule, Permission -from .personal_access_token_auth import PersonalAccessTokenAuth -from .personal_access_token_auth import PersonalAccessTokenAuth from .project_item import ProjectItem from .revision_item import RevisionItem from .schedule_item import ScheduleItem @@ -31,7 +29,7 @@ from .site_item import SiteItem from .subscription_item import SubscriptionItem from .table_item import TableItem -from .tableau_auth import TableauAuth +from .tableau_auth import Credentials, TableauAuth, PersonalAccessTokenAuth from .tableau_types import Resource, TableauItem, plural_type from .target import Target from .task_item import TaskItem