-
Notifications
You must be signed in to change notification settings - Fork 445
Added new apis to workbook and datasource #1637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c728b19
2d3901d
2886018
dcaf0f1
ddeab9e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| import argparse | ||
| import logging | ||
| import tableauserverclient as TSC | ||
|
|
||
|
|
||
| def main(): | ||
| parser = argparse.ArgumentParser(description="Update a single connection on a datasource or workbook to embed credentials") | ||
|
|
||
| # Common options | ||
| parser.add_argument("--server", "-s", help="Server address", required=True) | ||
| parser.add_argument("--site", "-S", help="Site name", required=True) | ||
| parser.add_argument("--token-name", "-p", help="Personal access token name", required=True) | ||
| parser.add_argument("--token-value", "-v", help="Personal access token value", required=True) | ||
| parser.add_argument( | ||
| "--logging-level", "-l", | ||
| choices=["debug", "info", "error"], | ||
| default="error", | ||
| help="Logging level (default: error)", | ||
| ) | ||
|
|
||
| # Resource and connection details | ||
| parser.add_argument("resource_type", choices=["workbook", "datasource"]) | ||
| parser.add_argument("resource_id", help="Workbook or datasource ID") | ||
| parser.add_argument("connection_id", help="Connection ID to update") | ||
| parser.add_argument("datasource_username", help="Username to set for the connection") | ||
| parser.add_argument("datasource_password", help="Password to set for the connection") | ||
| parser.add_argument("authentication_type", help="Authentication type") | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| # Logging setup | ||
| logging_level = getattr(logging, args.logging_level.upper()) | ||
| logging.basicConfig(level=logging_level) | ||
|
|
||
| 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): | ||
| endpoint = { | ||
| "workbook": server.workbooks, | ||
| "datasource": server.datasources | ||
| }.get(args.resource_type) | ||
|
|
||
| update_function = endpoint.update_connection | ||
| resource = endpoint.get_by_id(args.resource_id) | ||
| endpoint.populate_connections(resource) | ||
|
|
||
| connections = [conn for conn in resource.connections if conn.id == args.connection_id] | ||
| assert len(connections) == 1, f"Connection ID '{args.connection_id}' not found." | ||
|
|
||
| connection = connections[0] | ||
| connection.username = args.datasource_username | ||
| connection.password = args.datasource_password | ||
| connection.authentication_type = args.authentication_type | ||
| connection.embed_password = True | ||
|
|
||
| updated_connection = update_function(resource, connection) | ||
| print(f"Updated connection: {updated_connection.__dict__}") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import argparse | ||
| import logging | ||
| import tableauserverclient as TSC | ||
|
|
||
|
|
||
| def main(): | ||
| parser = argparse.ArgumentParser(description="Bulk update all workbook or datasource connections") | ||
|
|
||
| # Common options | ||
| parser.add_argument("--server", "-s", help="Server address", required=True) | ||
| parser.add_argument("--site", "-S", help="Site name", required=True) | ||
| parser.add_argument("--username", "-p", help="Personal access token name", required=True) | ||
| parser.add_argument("--password", "-v", help="Personal access token value", required=True) | ||
| parser.add_argument( | ||
| "--logging-level", | ||
| "-l", | ||
| choices=["debug", "info", "error"], | ||
| default="error", | ||
| help="Logging level (default: error)", | ||
| ) | ||
|
|
||
| # Resource-specific | ||
| parser.add_argument("resource_type", choices=["workbook", "datasource"]) | ||
| parser.add_argument("resource_id") | ||
| parser.add_argument("datasource_username") | ||
| parser.add_argument("authentication_type") | ||
| parser.add_argument("--datasource_password", default=None, help="Datasource password (optional)") | ||
| parser.add_argument("--embed_password", default="true", choices=["true", "false"], help="Embed password (default: true)") | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| # Set logging level | ||
| logging_level = getattr(logging, args.logging_level.upper()) | ||
| logging.basicConfig(level=logging_level) | ||
|
|
||
| tableau_auth = TSC.TableauAuth(args.username, args.password, site_id=args.site) | ||
| server = TSC.Server(args.server, use_server_version=True) | ||
|
|
||
| with server.auth.sign_in(tableau_auth): | ||
| endpoint = { | ||
| "workbook": server.workbooks, | ||
| "datasource": server.datasources | ||
| }.get(args.resource_type) | ||
|
|
||
| resource = endpoint.get_by_id(args.resource_id) | ||
| endpoint.populate_connections(resource) | ||
|
|
||
| connection_luids = [conn.id for conn in resource.connections] | ||
| embed_password = args.embed_password.lower() == "true" | ||
|
|
||
| # Call unified update_connections method | ||
| updated_ids = endpoint.update_connections( | ||
| resource, | ||
| connection_luids=connection_luids, | ||
| authentication_type=args.authentication_type, | ||
| username=args.datasource_username, | ||
| password=args.datasource_password, | ||
| embed_password=embed_password | ||
| ) | ||
|
|
||
| print(f"Updated connections on {args.resource_type} {args.resource_id}: {updated_ids}") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -319,6 +319,71 @@ def update_connection( | |
| logger.info(f"Updated datasource item (ID: {datasource_item.id} & connection item {connection_item.id}") | ||
| return connection | ||
|
|
||
| @api(version="3.26") | ||
| def update_connections( | ||
| self, datasource_item: DatasourceItem, connection_luids: list[str], authentication_type: str, username: Optional[str] = None, password: Optional[str] = None, embed_password: Optional[bool] = None | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should accept an |
||
| ) -> list[str]: | ||
| """ | ||
| Bulk updates one or more datasource connections by LUID. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| datasource_item : DatasourceItem | ||
| The datasource item containing the connections. | ||
|
|
||
| connection_luids : list of str | ||
| The connection LUIDs to update. | ||
|
|
||
| authentication_type : str | ||
| The authentication type to use (e.g., 'auth-keypair'). | ||
|
|
||
| username : str, optional | ||
| The username to set. | ||
|
|
||
| password : str, optional | ||
| The password or secret to set. | ||
|
|
||
| embed_password : bool, optional | ||
| Whether to embed the password. | ||
|
|
||
| Returns | ||
| ------- | ||
| list of str | ||
| The connection LUIDs that were updated. | ||
| """ | ||
| from xml.etree.ElementTree import Element, SubElement, tostring | ||
|
|
||
| url = f"{self.baseurl}/{datasource_item.id}/connections" | ||
|
|
||
| ts_request = Element("tsRequest") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating the XML payload belongs in the request_factory. |
||
|
|
||
| # <connectionLuids> | ||
| conn_luids_elem = SubElement(ts_request, "connectionLuids") | ||
| for luid in connection_luids: | ||
| SubElement(conn_luids_elem, "connectionLuid").text = luid | ||
|
|
||
| # <connection> | ||
| connection_elem = SubElement(ts_request, "connection") | ||
| connection_elem.set("authenticationType", authentication_type) | ||
|
|
||
| if username: | ||
| connection_elem.set("userName", username) | ||
|
|
||
| if password: | ||
| connection_elem.set("password", password) | ||
|
|
||
| if embed_password is not None: | ||
| connection_elem.set("embedPassword", str(embed_password).lower()) | ||
|
|
||
| request_body = tostring(ts_request) | ||
|
|
||
| response = self.put_request(url, request_body) | ||
|
|
||
| logger.info( | ||
| f"Updated connections for datasource {datasource_item.id}: {', '.join(connection_luids)}" | ||
| ) | ||
| return connection_luids | ||
|
|
||
| @api(version="2.8") | ||
| def refresh(self, datasource_item: DatasourceItem, incremental: bool = False) -> JobItem: | ||
| """ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -325,6 +325,72 @@ def update_connection(self, workbook_item: WorkbookItem, connection_item: Connec | |
| logger.info(f"Updated workbook item (ID: {workbook_item.id} & connection item {connection_item.id})") | ||
| return connection | ||
|
|
||
| # Update workbook_connections | ||
| @api(version="3.26") | ||
| def update_connections(self, workbook_item: WorkbookItem, connection_luids: list[str], authentication_type: str, username: Optional[str] = None, password: Optional[str] = None, embed_password: Optional[bool] = None | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as datasource method. |
||
| ) -> list[str]: | ||
| """ | ||
| Bulk updates one or more workbook connections by LUID, including authenticationType, username, password, and embedPassword. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| workbook_item : WorkbookItem | ||
| The workbook item containing the connections. | ||
|
|
||
| connection_luids : list of str | ||
| The connection LUIDs to update. | ||
|
|
||
| authentication_type : str | ||
| The authentication type to use (e.g., 'AD Service Principal'). | ||
|
|
||
| username : str, optional | ||
| The username to set (e.g., client ID for keypair auth). | ||
|
|
||
| password : str, optional | ||
| The password or secret to set. | ||
|
|
||
| embed_password : bool, optional | ||
| Whether to embed the password. | ||
|
|
||
| Returns | ||
| ------- | ||
| list of str | ||
| The connection LUIDs that were updated. | ||
| """ | ||
| from xml.etree.ElementTree import Element, SubElement, tostring | ||
|
|
||
| url = f"{self.baseurl}/{workbook_item.id}/connections" | ||
|
|
||
| ts_request = Element("tsRequest") | ||
|
|
||
| # <connectionLuids> | ||
| conn_luids_elem = SubElement(ts_request, "connectionLuids") | ||
| for luid in connection_luids: | ||
| SubElement(conn_luids_elem, "connectionLuid").text = luid | ||
|
|
||
| # <connection> | ||
| connection_elem = SubElement(ts_request, "connection") | ||
| connection_elem.set("authenticationType", authentication_type) | ||
|
|
||
| if username: | ||
| connection_elem.set("userName", username) | ||
|
|
||
| if password: | ||
| connection_elem.set("password", password) | ||
|
|
||
| if embed_password is not None: | ||
| connection_elem.set("embedPassword", str(embed_password).lower()) | ||
|
|
||
| request_body = tostring(ts_request) | ||
|
|
||
| # Send request | ||
| response = self.put_request(url, request_body) | ||
|
|
||
| logger.info( | ||
| f"Updated connections for workbook {workbook_item.id}: {', '.join(connection_luids)}" | ||
| ) | ||
| return connection_luids | ||
|
|
||
| # Download workbook contents with option of passing in filepath | ||
| @api(version="2.0") | ||
| @parameter_added_in(no_extract="2.5") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated change