Skip to content

Commit

Permalink
Working through metadata API methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryant Howell committed Nov 15, 2019
1 parent 8cd39cc commit 80850ab
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 9 deletions.
1 change: 1 addition & 0 deletions tableau_rest_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .sort import Sort
from .url_filter import UrlFilter, UrlFilter27, UrlFilter28
from .published_content import Project, Project28, Workbook, Datasource
from .permissions import *
29 changes: 22 additions & 7 deletions tableau_rest_api/methods/metadata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .rest_api_base import *
from ..permissions import DatabasePermissions35, TablePermissions35

# First Metadata Methods appear in API 3.5
class MetadataMethods35():
Expand All @@ -9,22 +10,22 @@ def __getattr__(self, attr):
return getattr(self.rest_api_base, attr)

def query_databases(self) -> ET.Element:
self.start_log_block
self.start_log_block()
response = self.query_resource("databases")
self.end_log_block
self.end_log_block()
return response

def query_database(self, database_name_or_luid: str) -> ET.Element:
self.start_log_block
self.start_log_block()
# Implement the search mechanism eventually using XPath similar to old workbooks / datasources lookup
response = self.query_single_element_from_endpoint("databases", name_or_luid=database_name_or_luid)
self.end_log_block
self.end_log_block()
return response

def update_database(self, database_name_or_luid: str, certification_status: Optional[bool] = None,
certification_note: Optional[str] = None, description: Optional[str] = None,
contact_username_or_luid: Optional[str] = None) -> ET.Element:
self.start_log_block
self.start_log_block()
tsr = ET.Element('tsRequest')
d = ET.Element('database')
if certification_status is not None:
Expand All @@ -42,6 +43,20 @@ def update_database(self, database_name_or_luid: str, certification_status: Opti
tsr.append(d)
database_luid = self.query_database_luid(database_name=database_name_or_luid)
url = self.build_api_url("databases/{}".format(database_luid))
response = self.send_update_request()
self.end_log_block
response = self.rest_api_base.send_update_request(url=url, request=tsr)
self.end_log_block()
return response

# UNFINISHED
def query_database_permissions(self, database_name_or_luid: str) -> DatabasePermissions35:
pass



# Described here https://help.tableau.com/current/api/metadata_api/en-us/index.html
# Uses json.loads() to build the JSON object to send
# Need to implement POST on the RestJsonRequest object to be able to do this
def graphql(self, graphql_query: str) -> str:
self.start_log_block()

self.end_log_block()
18 changes: 18 additions & 0 deletions tableau_rest_api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,4 +332,22 @@ def __init__(self, group_or_user: str, group_or_user_luid: str):
if cap != 'all':
self.capabilities[cap] = None
# Unclear that there are any defined roles for Prep Conductor flows
self.role_set = {}

class DatabasePermissions35(Permissions):
def __init__(self, group_or_user: str, group_or_user_luid: str):
Permissions.__init__(self, group_or_user, group_or_user_luid, 'database')
for cap in self.available_capabilities['3.5']['database']:
if cap != 'all':
self.capabilities[cap] = None
# No idea what roles might exist for 'databases' or 'tables'
self.role_set = {}

class TablePermissions35(Permissions):
def __init__(self, group_or_user: str, group_or_user_luid: str):
Permissions.__init__(self, group_or_user, group_or_user_luid, 'table')
for cap in self.available_capabilities['3.5']['table']:
if cap != 'all':
self.capabilities[cap] = None
# No idea what roles might exist for 'databases' or 'tables'
self.role_set = {}
6 changes: 5 additions & 1 deletion tableau_rest_api/rest_json_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,11 @@ def _handle_http_error(self, response, e):
self.log('Tableau REST API error code is: {}'.format(error_code))
# If you are not signed in
if error_code == '401000':
raise NotSignedInException('You must sign in first')
raise NotSignedInException('401000 error, no session token was provided. Please sign in again.')
if error_code == '401002':
raise NotSignedInException(
'401002 error, session token has timed out or otherwise been invalidated. Please sign in again.')

# Everything that is not 400 can potentially be recovered from
if status_code in [401, 402, 403, 404, 405, 409]:
# If 'not exists' for a delete, recover and log
Expand Down
5 changes: 4 additions & 1 deletion tableau_rest_api/rest_xml_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ def _handle_http_error(self, response, e):
self.log('Tableau REST API error code is: {}'.format(error_code))
# If you are not signed in
if error_code == '401000':
raise NotSignedInException('You must sign in first')
raise NotSignedInException('401000 error, no session token was provided. Please sign in again.')
if error_code == '401002':
raise NotSignedInException('401002 error, session token has timed out or otherwise been invalidated. Please sign in again.')

# Everything that is not 400 can potentially be recovered from
if status_code in [401, 402, 403, 404, 405, 409]:
# If 'not exists' for a delete, recover and log
Expand Down

0 comments on commit 80850ab

Please sign in to comment.