diff --git a/samples/publish_workbook.py b/samples/publish_workbook.py index d31978c0..052eee1f 100644 --- a/samples/publish_workbook.py +++ b/samples/publish_workbook.py @@ -36,9 +36,16 @@ def main(): help="desired logging level (set to error by default)", ) # Options specific to this sample + group = parser.add_mutually_exclusive_group(required=False) + group.add_argument("--thumbnails-user-id", "-u", help="User ID to use for thumbnails") + group.add_argument("--thumbnails-group-id", "-g", help="Group ID to use for thumbnails") + + parser.add_argument("--workbook-name", "-n", help="Name with which to publish the workbook") parser.add_argument("--file", "-f", help="local filepath of the workbook to publish") parser.add_argument("--as-job", "-a", help="Publishing asynchronously", action="store_true") parser.add_argument("--skip-connection-check", "-c", help="Skip live connection check", action="store_true") + parser.add_argument("--project", help="Project within which to publish the workbook") + parser.add_argument("--show-tabs", help="Publish workbooks with tabs displayed", action="store_true") args = parser.parse_args() @@ -50,9 +57,20 @@ def main(): tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site) server = TSC.Server(args.server, use_server_version=True) with server.auth.sign_in(tableau_auth): - # Step 2: Get all the projects on server, then look for the default one. - all_projects, pagination_item = server.projects.get() - default_project = next((project for project in all_projects if project.is_default()), None) + # Step2: Retrieve the project id, if a project name was passed + if args.project is not None: + req_options = TSC.RequestOptions() + req_options.filter.add( + TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, args.project) + ) + projects = list(TSC.Pager(server.projects, req_options)) + if len(projects) > 1: + raise ValueError("The project name is not unique") + project_id = projects[0].id + else: + # Get all the projects on server, then look for the default one. + all_projects, pagination_item = server.projects.get() + project_id = next((project for project in all_projects if project.is_default()), None).id connection1 = ConnectionItem() connection1.server_address = "mssql.test.com" @@ -67,10 +85,16 @@ def main(): all_connections.append(connection1) all_connections.append(connection2) - # Step 3: If default project is found, form a new workbook item and publish. + # Step 3: Form a new workbook item and publish. overwrite_true = TSC.Server.PublishMode.Overwrite - if default_project is not None: - new_workbook = TSC.WorkbookItem(default_project.id) + if project_id is not None: + new_workbook = TSC.WorkbookItem( + project_id=project_id, + name=args.workbook_name, + show_tabs=args.show_tabs, + thumbnails_user_id=args.thumbnails_user_id, + thumbnails_group_id=args.thumbnails_group_id, + ) if args.as_job: new_job = server.workbooks.publish( new_workbook, @@ -92,7 +116,7 @@ def main(): ) print(f"Workbook published. ID: {new_workbook.id}") else: - error = "The default project could not be found." + error = "The destination project could not be found." raise LookupError(error) diff --git a/tableauserverclient/models/workbook_item.py b/tableauserverclient/models/workbook_item.py index 776d041e..32ab413a 100644 --- a/tableauserverclient/models/workbook_item.py +++ b/tableauserverclient/models/workbook_item.py @@ -99,7 +99,14 @@ class as arguments. The workbook item specifies the project. >>> new_workbook = TSC.WorkbookItem('3a8b6148-493c-11e6-a621-6f3499394a39') """ - def __init__(self, project_id: Optional[str] = None, name: Optional[str] = None, show_tabs: bool = False) -> None: + def __init__( + self, + project_id: Optional[str] = None, + name: Optional[str] = None, + show_tabs: bool = False, + thumbnails_user_id: Optional[str] = None, + thumbnails_group_id: Optional[str] = None, + ) -> None: self._connections = None self._content_url = None self._webpage_url = None @@ -130,6 +137,8 @@ def __init__(self, project_id: Optional[str] = None, name: Optional[str] = None, } self.data_freshness_policy = None self._permissions = None + self.thumbnails_user_id = thumbnails_user_id + self.thumbnails_group_id = thumbnails_group_id return None @@ -275,6 +284,22 @@ def revisions(self) -> list[RevisionItem]: raise UnpopulatedPropertyError(error) return self._revisions() + @property + def thumbnails_user_id(self) -> Optional[str]: + return self._thumbnails_user_id + + @thumbnails_user_id.setter + def thumbnails_user_id(self, value: str): + self._thumbnails_user_id = value + + @property + def thumbnails_group_id(self) -> Optional[str]: + return self._thumbnails_group_id + + @thumbnails_group_id.setter + def thumbnails_group_id(self, value: str): + self._thumbnails_group_id = value + def _set_connections(self, connections): self._connections = connections diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py index 5849a8da..f0b2d184 100644 --- a/tableauserverclient/server/request_factory.py +++ b/tableauserverclient/server/request_factory.py @@ -958,6 +958,12 @@ def _generate_xml( views_element = ET.SubElement(workbook_element, "views") for view_name in workbook_item.hidden_views: _add_hiddenview_element(views_element, view_name) + + if workbook_item.thumbnails_user_id is not None: + workbook_element.attrib["thumbnailsUserId"] = workbook_item.thumbnails_user_id + elif workbook_item.thumbnails_group_id is not None: + workbook_element.attrib["thumbnailsGroupId"] = workbook_item.thumbnails_group_id + return ET.tostring(xml_request) def update_req(self, workbook_item, parent_srv: Optional["Server"] = None): diff --git a/test/test_workbook.py b/test/test_workbook.py index 1a6b3192..0aa52f50 100644 --- a/test/test_workbook.py +++ b/test/test_workbook.py @@ -624,6 +624,45 @@ def test_publish_with_hidden_views_on_workbook(self) -> None: self.assertTrue(re.search(rb"<\/views>", request_body)) self.assertTrue(re.search(rb"<\/views>", request_body)) + def test_publish_with_thumbnails_user_id(self) -> None: + with open(PUBLISH_XML, "rb") as f: + response_xml = f.read().decode("utf-8") + with requests_mock.mock() as m: + m.post(self.baseurl, text=response_xml) + + new_workbook = TSC.WorkbookItem( + name="Sample", + show_tabs=False, + project_id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20760", + thumbnails_user_id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20761", + ) + + sample_workbook = os.path.join(TEST_ASSET_DIR, "SampleWB.twbx") + publish_mode = self.server.PublishMode.CreateNew + new_workbook = self.server.workbooks.publish(new_workbook, sample_workbook, publish_mode) + request_body = m._adapter.request_history[0]._request.body + # order of attributes in xml is unspecified + self.assertTrue(re.search(rb"thumbnailsUserId=\"ee8c6e70-43b6-11e6-af4f-f7b0d8e20761\"", request_body)) + + def test_publish_with_thumbnails_group_id(self) -> None: + with open(PUBLISH_XML, "rb") as f: + response_xml = f.read().decode("utf-8") + with requests_mock.mock() as m: + m.post(self.baseurl, text=response_xml) + + new_workbook = TSC.WorkbookItem( + name="Sample", + show_tabs=False, + project_id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20760", + thumbnails_group_id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20762", + ) + + sample_workbook = os.path.join(TEST_ASSET_DIR, "SampleWB.twbx") + publish_mode = self.server.PublishMode.CreateNew + new_workbook = self.server.workbooks.publish(new_workbook, sample_workbook, publish_mode) + request_body = m._adapter.request_history[0]._request.body + self.assertTrue(re.search(rb"thumbnailsGroupId=\"ee8c6e70-43b6-11e6-af4f-f7b0d8e20762\"", request_body)) + @pytest.mark.filterwarnings("ignore:'as_job' not available") def test_publish_with_query_params(self) -> None: with open(PUBLISH_ASYNC_XML, "rb") as f: