def test_filter_sort_legacy(self): self.server.version = "3.6" with requests_mock.mock() as m: m.get(requests_mock.ANY) url = self.baseurl + "/views?queryParamExists=true" opts = TSC.RequestOptions() opts.filter.add( TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.RequestOptions.Operator.In, ['stocks', 'market'])) opts.sort.add( TSC.Sort(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Direction.Asc)) resp = self.server.workbooks.get_request(url, request_object=opts) self.assertTrue( re.search('queryparamexists=true', resp.request.query)) self.assertTrue( re.search('filter=tags:in:%5bstocks,market%5d', resp.request.query)) self.assertTrue(re.search('sort=name:asc', resp.request.query))
def test_filter_in(self): with requests_mock.mock() as m: m.get(requests_mock.ANY) url = "http://test/api/2.3/sites/dad65087-b08b-4603-af4e-2887b8aafc67/workbooks" opts = TSC.RequestOptions(pagesize=13, pagenumber=13) opts.filter.add( TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.RequestOptions.Operator.In, ['stocks', 'market'])) resp = self.server.workbooks._make_request( requests.get, url, content=None, request_object=opts, auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM', content_type='text/xml') self.assertEqual( resp.request.query, 'pagenumber=13&pagesize=13&filter=tags:in:[stocks,market]')
def test_multiple_filter_options(self): with open(FILTER_MULTIPLE, 'rb') as f: response_xml = f.read().decode('utf-8') # To ensure that this is deterministic, run this a few times with requests_mock.mock() as m: # Sometimes pep8 requires you to do things you might not otherwise do url = ''.join( (self.baseurl, '/workbooks?pageNumber=1&pageSize=100&', 'filter=name:eq:foo,tags:in:[sample,safari,weather]')) m.get(url, text=response_xml) req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.RequestOptions.Operator.In, ['sample', 'safari', 'weather'])) req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, 'foo')) for _ in range(100): matching_workbooks, pagination_item = self.server.workbooks.get( req_option) self.assertEqual(3, pagination_item.total_available)
def test_double_query_params(self): with requests_mock.mock() as m: m.get(requests_mock.ANY) url = "http://test/api/2.3/sites/12345/views?queryParamExists=true" opts = TSC.RequestOptions() opts.filter.add( TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.RequestOptions.Operator.In, ['stocks', 'market'])) resp = self.server.workbooks._make_request( requests.get, url, content=None, request_object=opts, auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM', content_type='text/xml') self.assertTrue( re.search('queryparamexists=true', resp.request.query)) self.assertTrue( re.search('filter=tags%3ain%3a%5bstocks%2cmarket%5d', resp.request.query))
def test_filter_combo(self): with requests_mock.mock() as m: m.get(requests_mock.ANY) url = "http://test/api/2.3/sites/dad65087-b08b-4603-af4e-2887b8aafc67/users" opts = TSC.RequestOptions(pagesize=13, pagenumber=13) opts.filter.add(TSC.Filter(TSC.RequestOptions.Field.LastLogin, TSC.RequestOptions.Operator.GreaterThanOrEqual, '2017-01-15T00:00:00:00Z')) opts.filter.add(TSC.Filter(TSC.RequestOptions.Field.SiteRole, TSC.RequestOptions.Operator.Equals, 'Publisher')) resp = self.server.workbooks._make_request(requests.get, url, content=None, request_object=opts, auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM', content_type='text/xml') expected = 'pagenumber=13&pagesize=13&filter=lastlogin:gte:2017-01-15t00:00:00:00z,siterole:eq:publisher' self.assertEqual(resp.request.query, expected)
def update_workbooks_by_paths(all_projects, materialized_views_config, server, workbook_path_mapping): for workbook_name, workbook_paths in workbook_path_mapping.items(): req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, workbook_name)) workbooks = list(TSC.Pager(server.workbooks, req_option)) all_paths = set(workbook_paths[:]) for workbook in workbooks: path = find_project_path(all_projects[workbook.project_id], all_projects, "") if path in workbook_paths: all_paths.remove(path) workbook.materialized_views_config = materialized_views_config server.workbooks.update(workbook) print("Updated materialized views settings for workbook: {}". format(path + '/' + workbook.name)) for path in all_paths: print( "Cannot find workbook path: {}, each line should only contain one workbook path" .format(path + '/' + workbook_name)) print('\n')
import logging import json import time import datetime import tableauserverclient as TSC from DownloadConfiguration import * start_time = time.time() tableau_auth = TSC.TableauAuth(USER, PASSWORD, site_id=SITENAME) server = TSC.Server(SERVER) starttimestamp = datetime.datetime.now() start_time = time.time() fldrmonth = starttimestamp.strftime("%m") fldryear = starttimestamp.strftime("%Y") paging_options = TSC.RequestOptions(pagesize=1000) def create_folders(parentfoldername, subfolder1=None, subfolder2=None): osparentfolder = "\\" + parentfoldername + "\\" if subfolder1 is None: ossubfolder1 = "" else: ossubfolder1 = "\\" + subfolder1 + "\\" if subfolder2 is None: ossubfolder2 = "" else: ossubfolder2 = "\\" + subfolder2 + "\\" if not os.path.exists(MAINFOLDER + osparentfolder + ossubfolder1 + ossubfolder2): os.makedirs(MAINFOLDER + osparentfolder + ossubfolder1 + ossubfolder2)
def main(): parser = argparse.ArgumentParser( description="Move one workbook from the" "default project of the default site to" "the default project of another site." ) # Common options; please keep those in sync across all samples parser.add_argument("--server", "-s", required=True, help="server address") parser.add_argument("--site", "-S", help="site name") parser.add_argument( "--token-name", "-p", required=True, help="name of the personal access token used to sign into the server" ) parser.add_argument( "--token-value", "-v", required=True, help="value of the personal access token used to sign into the server" ) parser.add_argument( "--logging-level", "-l", choices=["debug", "info", "error"], default="error", help="desired logging level (set to error by default)", ) # Options specific to this sample parser.add_argument("--workbook-name", "-w", required=True, help="name of workbook to move") parser.add_argument("--destination-site", "-d", required=True, help="name of site to move workbook into") args = parser.parse_args() # Set logging level based on user input, or error by default logging_level = getattr(logging, args.logging_level.upper()) logging.basicConfig(level=logging_level) # Step 1: Sign in to both sites on server tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site) source_server = TSC.Server(args.server) dest_server = TSC.Server(args.server) with source_server.auth.sign_in(tableau_auth): # Step 2: Query workbook to move req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, args.workbook_name) ) all_workbooks, pagination_item = source_server.workbooks.get(req_option) # Step 3: Download workbook to a temp directory if len(all_workbooks) == 0: print("No workbook named {} found.".format(args.workbook_name)) else: tmpdir = tempfile.mkdtemp() try: workbook_path = source_server.workbooks.download(all_workbooks[0].id, tmpdir) # Step 4: Check if destination site exists, then sign in to the site all_sites, pagination_info = source_server.sites.get() found_destination_site = any( (True for site in all_sites if args.destination_site.lower() == site.content_url.lower()) ) if not found_destination_site: error = "No site named {} found.".format(args.destination_site) raise LookupError(error) tableau_auth.site_id = args.destination_site # Signing into another site requires another server object # because of the different auth token and site ID. with dest_server.auth.sign_in(tableau_auth): # Step 5: Create a new workbook item and publish workbook. Note that # an empty project_id will publish to the 'Default' project. new_workbook = TSC.WorkbookItem(name=args.workbook_name, project_id="") new_workbook = dest_server.workbooks.publish( new_workbook, workbook_path, mode=TSC.Server.PublishMode.Overwrite ) print("Successfully moved {0} ({1})".format(new_workbook.name, new_workbook.id)) # Step 6: Delete workbook from source site and delete temp directory source_server.workbooks.delete(all_workbooks[0].id) finally: shutil.rmtree(tmpdir)
def main(): try: tableauPassword = getCreds() logger.info('Preparing Backup') #setting up tableau login credentials tableau_auth = TSC.TableauAuth(cfg['tableauServer']['user'], tableauPassword) server = TSC.Server(cfg['tableauServer']['url']) server.add_http_options({'verify': False}) server.use_server_version() firstTime = False #check if there is git repo, if not clone the repository oPath = cfg['git']['projectName'] if os.path.isdir(oPath) is False: Repo.clone_from(cfg['git']['url'], oPath) firstTime = True repo = git.Repo(oPath) #logging into tableau server server.auth.sign_in(tableau_auth) #setting time stamp for one hour previous from when this script is run utc_value = int(cfg['tableauServer']['utc_value']) currentTime = datetime.now() if firstTime is True or args.full_load == True: downloadChangesSince = '2000-01-01T00:00:00Z' else: downloadChangesSince = (datetime.fromtimestamp( (currentTime.timestamp() - (utc_value + args.incremental) * 3600)).replace( microsecond=0)).isoformat() + 'Z' logger.info("downloadChangesSince: {0}".format(downloadChangesSince)) req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.UpdatedAt, TSC.RequestOptions.Operator.GreaterThanOrEqual, downloadChangesSince)) remove_punctuation_and_turkish_map = dict( (ord(char), None) for char in '\/*?:"<>|') turkish_character_set = { ('ı', 'i'), ('İ', 'I'), ('ü', 'u'), ('Ü', 'U'), ('ö', 'o'), ('Ö', 'O'), ('ç', 'c'), ('Ç', 'C'), ('ş', 's'), ('Ş', 'S'), ('ğ', 'g'), ('Ğ', 'G') } for map_item in turkish_character_set: remove_punctuation_and_turkish_map.update( {ord(map_item[0]): map_item[1]}) #iterating through each site on tableau for site in TSC.Pager(server.sites): logger.info( 'Backing up workbooks and datasources under the {} site changed after {}' .format(site.name, downloadChangesSince)) #logging into the specific site tableau_auth1 = TSC.TableauAuth(cfg['tableauServer']['user'], tableauPassword, site_id=site.content_url) server.auth.sign_in(tableau_auth1) sPath = os.path.join( oPath, site.name.translate(remove_punctuation_and_turkish_map)) if os.path.isdir(sPath) is False: os.makedirs(sPath) #iterating through each workbook in the specified site to download and extract for workbook in TSC.Pager(server.workbooks, req_option): projectName = workbook.project_name.translate( remove_punctuation_and_turkish_map) xPath = os.path.join(sPath, projectName) workbookFileName = os.path.join( xPath, workbook.name.translate( remove_punctuation_and_turkish_map)) + '.twb' if os.path.isdir(xPath) is False: os.makedirs(xPath) file_path = server.workbooks.download( workbook.id, filepath=workbookFileName) #extractWorkbook(file_path, site.name, projectName, workbook.project_id, workbook.id, os.path.basename(file_path), xPath) #iterating through each datasource in the specified site to downlad and extract for datasources in TSC.Pager(server.datasources, req_option): projectName = datasources.project_name.translate( remove_punctuation_and_turkish_map) dPath = os.path.join(sPath, projectName) datasourceFileName = os.path.join( dPath, datasources.name.translate( remove_punctuation_and_turkish_map)) + ".tdsx" if os.path.isdir(dPath) is False: os.makedirs(dPath) file_path = server.datasources.download( datasources.id, filepath=datasourceFileName, include_extract=False) extractDatasource(file_path, site.name, projectName, datasources.project_id, datasources.id, os.path.basename(file_path), dPath) #pushing changes to git and timestamping when this script was run if "nothing to commit" not in repo.git.status(): repo.git.add('.') repo.git.commit(m="last backup: " + currentTime.strftime('%Y-%m-%d %H-%M-%S')) repo.git.push('origin') logger.info('Backup Complete') server.auth.sign_out() except: logging.exception('error') pass
class TableauServerCommunicator: req_opts = tsc.RequestOptions(pagesize=1000) tableau_server = None locale = None def __init__(self, in_language): file_parts = os.path.normpath(os.path.abspath(__file__)).replace('\\', os.path.altsep)\ .split(os.path.altsep) locale_domain = file_parts[(len(file_parts) - 1)].replace('.py', '') locale_folder = os.path.normpath( os.path.join( os.path.join(os.path.altsep.join(file_parts[:-2]), 'project_locale'), locale_domain)) self.locale = gettext.translation(locale_domain, localedir=locale_folder, languages=[in_language], fallback=True) def connect_to_tableau_server(self, local_logger, timer, in_connection): timer.start() local_logger.debug( self.locale.gettext( 'About to connect to the Tableau Server with URL: {tableau_server}, ' + 'Site {tableau_site} with Username = {user_name}').replace( '{tableau_server}', in_connection['Tableau Server']).replace( '{tableau_site}', in_connection['Tableau Site']).replace( '{user_name}', in_connection['Username'])) self.tableau_server = tsc.Server(in_connection['Tableau Server'], True) tableau_auth = tsc.TableauAuth(in_connection['Username'], in_connection['Password'], in_connection['Tableau Site']) self.tableau_server.auth.sign_in(tableau_auth) local_logger.debug( self.locale.gettext( 'Connection to the Tableau Server has been established successfully!' )) timer.stop() def disconnect_from_tableau_server(self, local_logger, timer): timer.start() self.tableau_server.auth.sign_out() local_logger.debug( self.locale.gettext( 'Connection to the Tableau Server has been terminated!')) timer.stop() @staticmethod def get_project_relevancy(relevant_projects_to_filter, filtering_type, current_project): relevant = 0 if filtering_type == 'JustOnesMentioned': if current_project.name.replace( chr(8211), chr(45)) in relevant_projects_to_filter: relevant = 1 elif filtering_type == 'OnesMentionedMarked': relevant = 2 elif filtering_type == 'All': relevant = 99 return relevant def is_publishing_possible(self, local_logger, relevant_project_name, relevant_project_ids): publish_possible = False int_found_projects = len(relevant_project_ids) if int_found_projects == 0: local_logger.error( self.locale.gettext( 'No project with provided name "{project_name}" has been found' ).replace('{project_name}', relevant_project_name)) self.no_publishing_feedback() elif int_found_projects > 1: local_logger.error( f'There are {str(int_found_projects)} projects with provided name "' + relevant_project_name + ' but a unique identifier is expected') self.no_publishing_feedback() else: publish_possible = True local_logger.info( self.locale.gettext( 'A single project identifier was found "{project_guid}", ' + 'so I will proceed with publishing provided file there'). replace('{project_guid}', relevant_project_ids[0])) local_logger.info( self.locale.gettext('Stay tuned for the confirmation')) return publish_possible def load_tableau_project_ids(self, local_logger, timer, in_projects_to_filter, in_filter_type): timer.start() project_items, pagination_item = self.tableau_server.projects.get( req_options=self.req_opts) local_logger.info( self.locale.gettext( 'Reading list of all projects available has been completed')) local_logger.info( self.locale.gettext( 'A number of {projects_counted} projects have been identified' ).replace('{projects_counted}', str(len(project_items)))) timer.stop() timer.start() dictionary_project_ids = [] project_counter = 0 for project_current in project_items: relevant = self.get_project_relevancy(in_projects_to_filter, in_filter_type, project_current) if relevant >= 1: dictionary_project_ids.append(project_counter) dictionary_project_ids[project_counter] = project_current.id project_counter = project_counter + 1 local_logger.info( self.locale.gettext( 'Retaining the projects according to filtering type provided ({filter_type}) ' + 'has been completed').replace('{filter_type}', in_filter_type)) local_logger.info( self.locale.gettext( 'A number of {projects_counted} projects have been identified' ).replace('{projects_counted}', str(len(dictionary_project_ids)))) timer.stop() return dictionary_project_ids def no_publishing_feedback(self, local_logger): local_logger.debug( self.locale.gettext('No publishing action will take place!')) local_logger.debug( self.locale.gettext( 'Check your input parameter values for accuracy and try again!' )) def publish_data_source_to_tableau_server(self, local_logger, timer, publish_details): timer.start() local_logger.info(self.locale.gettext('About to start publishing')) data_source_name = Path(publish_details['Tableau Extract File'])\ .name.replace('.hyper', '') + " Extract" project_data_source = tsc.DatasourceItem(publish_details['Project ID'], data_source_name) self.tableau_server.datasources.publish( project_data_source, publish_details['Tableau Extract File'], publish_details['Publishing Mode']) local_logger.info( self.locale.gettext('Publishing completed successfully!')) timer.stop()
def main(): parser = argparse.ArgumentParser(description='Filter on groups') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') parser.add_argument('-p', default=None) args = parser.parse_args() if args.p is None: password = getpass.getpass("Password: "******"SALES NORTHWEST" create_example_group(group_name, server) group_name = 'SALES ROMANIA' # Try to create a group named "SALES ROMANIA" create_example_group(group_name, server) # URL Encode the name of the group that we want to filter on # i.e. turn spaces into plus signs filter_group_name = 'SALES+ROMANIA' options = TSC.RequestOptions() options.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, filter_group_name)) filtered_groups, _ = server.groups.get(req_options=options) # Result can either be a matching group or an empty list if filtered_groups: group_name = filtered_groups.pop().name print(group_name) else: error = "No project named '{}' found".format(filter_group_name) print(error) options = TSC.RequestOptions() options.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.In, ['SALES+NORTHWEST', 'SALES+ROMANIA', 'this_group'])) options.sort.add( TSC.Sort(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Direction.Desc)) matching_groups, pagination_item = server.groups.get( req_options=options) print('Filtered groups are:') for group in matching_groups: print(group.name)
def main(): parser = argparse.ArgumentParser( description= "Demonstrate pagination on the list of workbooks on the server.") # Common options; please keep those in sync across all samples parser.add_argument("--server", "-s", required=True, help="server address") parser.add_argument("--site", "-S", help="site name") parser.add_argument( "--token-name", "-n", required=True, help="name of the personal access token used to sign into the server") parser.add_argument( "--token-value", "-v", required=True, help="value of the personal access token used to sign into the server") parser.add_argument( "--logging-level", "-l", choices=["debug", "info", "error"], default="error", help="desired logging level (set to error by default)", ) # Options specific to this sample: # No additional options, yet. If you add some, please add them here args = parser.parse_args() # Set logging level based on user input, or error by default logging_level = getattr(logging, args.logging_level.upper()) logging.basicConfig(level=logging_level) # Sign in to server 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): you = server.users.get_by_id(server.user_id) print(you.name, you.id) # 1. Pager: Pager takes a server Endpoint as its first parameter, and a RequestOptions # object as the second parameter. The Endpoint defines which type of objects it returns, and # RequestOptions defines any restrictions on the objects: filter by name, sort, or select a page print("Your server contains the following workbooks:\n") count = 0 # Using a small number here so that you can see it work. Default is 100 and mostly doesn't need to change page_options = TSC.RequestOptions(1, 5) print("Fetching workbooks in pages of 5") for wb in TSC.Pager(server.workbooks, page_options): print(wb.name) count = count + 1 print("Total: {}\n".format(count)) count = 0 page_options = TSC.RequestOptions(2, 3) print( "Paging: start at the second page of workbooks, using pagesize = 3" ) for wb in TSC.Pager(server.workbooks, page_options): print(wb.name) count = count + 1 print("Truncated Total: {}\n".format(count)) print("Your id: ", you.name, you.id, "\n") count = 0 filtered_page_options = TSC.RequestOptions(1, 3) filter_owner = TSC.Filter("ownerEmail", TSC.RequestOptions.Operator.Equals, "*****@*****.**") filtered_page_options.filter.add(filter_owner) print("Fetching workbooks again, filtering by owner") for wb in TSC.Pager(server.workbooks, filtered_page_options): print(wb.name, " -- ", wb.owner_id) count = count + 1 print("Filtered Total: {}\n".format(count)) # 2. QuerySet offers a fluent interface on top of the RequestOptions object print("Fetching workbooks again - this time filtered with QuerySet") count = 0 page = 1 more = True while more: queryset = server.workbooks.filter( ownerEmail="*****@*****.**") for wb in queryset.paginate(page_number=page, page_size=3): print(wb.name, " -- ", wb.owner_id) count = count + 1 more = queryset.total_available > count page = page + 1 print("QuerySet Total: {}".format(count)) # 3. QuerySet also allows you to iterate over all objects without explicitly paging. print("Fetching again - this time without manually paging") for i, wb in enumerate( server.workbooks.filter(owner_email="*****@*****.**"), start=1): print(wb.name, "--", wb.owner_id) print(f"QuerySet Total, implicit paging: {i}")
def main(): parser = argparse.ArgumentParser( description='Download pdf file of snapshot(s) of a tableau dashboard.') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--token-name', '-tn', required=True, help='user token name') parser.add_argument('--token-secret', '-ts', required=True, help='user token secret') parser.add_argument('--view-name', '-v', required=True, help='name of dashboard view') parser.add_argument('--csv', '-csv', required=False, help='csv dataframe of filters/parameters') parser.add_argument('--filepath', '-f', required=True, help='filepath to save the pdf file returned') args = parser.parse_args() #signs user into server using token access tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_secret, '') server = TSC.Server(args.server, use_server_version=True) server.auth.sign_in(tableau_auth) #query for the view that we want an image of with server.auth.sign_in(tableau_auth): req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, args.view_name)) all_views, pagination_item = server.views.get(req_option) if not all_views: raise LookupError("View with the specified name was not found.") view_item = all_views[0] #adds filter/parameters to the view if .csv included in argument if args.csv is not None: filters = pd.read_csv(args.csv) path_names = [0] * filters.shape[0] for i, j in filters.iterrows(): image_req_option = TSC.ImageRequestOptions( imageresolution=TSC.ImageRequestOptions.Resolution.High) for col in filters.columns: image_req_option.vf(col, str(j[col]).replace(', ', ',')) server.views.populate_image(view_item, image_req_option) #temporarily saves each view as separate .png files with open('py_img_%i.png' % i, "wb") as image_file: image_file.write(view_item.image) path_names[i] = ('py_img_%i.png' % i) #takes a snapshot of the default view, when .csv not included else: image_req_option = TSC.ImageRequestOptions( imageresolution=TSC.ImageRequestOptions.Resolution.High) server.views.populate_image(view_item, image_req_option) #temporarily saves view as .png with open('py_img_0.png', "wb") as image_file: image_file.write(view_item.image) path_names = ['py_img_0.png'] #converts mode to remove alpha channel to allow .pdf conversion for path in path_names: img = Image.open(path) if img.mode == 'RGBA': img.convert('RGB').save(path) #save images as single .pdf with open(args.filepath, "wb") as f: f.write(img2pdf.convert(path_names)) #removes temporary .png file(s) from folder for path in path_names: os.remove(path)
def make_filter(**kwargs): options = TSC.RequestOptions() for item, value in kwargs.items(): name = getattr(TSC.RequestOptions.Field, item) options.filter.add(TSC.Filter(name, TSC.RequestOptions.Operator.Equals, value)) return options
import tableauserverclient as TSC from config import password, username import pandas as pd from db_connection import importer, run_query_non_results, query_text #sign in to tableau sever tableau_auth = TSC.TableauAuth(username, password, site_id='PeopleAnalytics') request_options = TSC.RequestOptions(pagesize=1000) #Set page size options server = TSC.Server('https://tableau.we.co/') with server.auth.sign_in(tableau_auth): #creating table of usernames and workbook permission #creates a list of all workbook on the server list_workbooks = [] #creates a list of all users on server list_users = [] #getting all users all_users, pagination_item = server.users.get() x = 0 #iterating through users and populating workbooks for each user for x in range(len(all_users)): page_n = server.users.populate_workbooks(all_users[x]) for workbook in all_users[x].workbooks: list_users.append(all_users[x].name) list_workbooks.append(workbook.name) x + 1 #creating a dataframe for all users and workbooks data1 = pd.DataFrame({
def getViews(servername): # return a list of views found on a given server, site, project, and with a particular name views = [] return_list = [] sites = getSites(servername) for site in sites: if args.si: # if filtered to a site, skip all but the one we want if site.name != args.si: continue tableau_auth = TSC.TableauAuth(args.u, password, site_id=site.content_url) server = TSC.Server(servername) server.add_http_options({'verify': False}) server.version = APIVERSION with server.auth.sign_in(tableau_auth): log.logger.info( f"signed in to {servername}, {site.name}, {site.content_url}, {site.state}" ) req_option = TSC.RequestOptions() # get the server information server_info = server.server_info.get() # if workbook name passed, filter on it if args.wi: req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, args.wi)) # if filtering by project, add that criteria if args.pi: req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.ProjectName, TSC.RequestOptions.Operator.Equals, args.pi)) if args.wi or args.pi: # get the filtered workbooks, then derive the views from them filtered_workbooks = list( TSC.Pager(server.workbooks, req_option)) filtered_views = [] for workbook in filtered_workbooks: server.workbooks.populate_views(workbook) filtered_views.extend(workbook.views) log.logger.debug(f'Found {len(filtered_views)} views') else: # no filtering, so just grab all the views on the site filtered_views = list(TSC.Pager(server.views)) # if filtering by file, remove any non-matches if args.vi: log.logger.debug( f'filtering views to those provided in {args.vi}') view_list = [] with open(args.vi, newline='') as view_list_file: view_list_reader = csv.reader(view_list_file) log.logger.debug('iterating over the views found') for line in view_list_reader: view_list.append(line[0]) file_filtered_views = [] for view in filtered_views: for luid in view_list: if view.id == luid: file_filtered_views.append(view) log.logger.debug( f'will run over {len(file_filtered_views)} views') time.sleep(5) filtered_views = file_filtered_views log.logger.debug(f'Final count is {len(filtered_views)} views') # now package up the return list views with their contextual information for view in filtered_views: return_list.append(SiteView(view, site, server, server_info)) # views.append({"site_content_url": site.content_url, "views": filtered_views}) return return_list
def CSV_ImageRequest(server, tableau_auth, csv_filename, end_file_directory, WorkbookName, DashboardName, UserEmail): with server.auth.sign_in(tableau_auth): folderExplore.TableauFolderViews(server) req_option1 = TSC.RequestOptions() req_option1.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, DashboardName)) req_option2 = TSC.RequestOptions() req_option2.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, WorkbookName)) all_views_filtered, views_items1 = server.views.get(req_option1) all_workbooks_filtered, workbooks_items1 = server.workbooks.get( req_option2) view_i, workbook_i = folderExplore.checkMatch(all_views_filtered, views_items1, all_workbooks_filtered, workbooks_items1) with open(csv_filename) as csv_file: csv_reader = csv.reader(csv_file, delimiter=',') line_count = 0 for row in csv_reader: if line_count == 0: num_col = len(row) column_header = row print("\n {}".format(column_header)) line_count += 1 else: if (row[1] == "PNG" or row[1] == "JPG"): # view item is the dashboard view. view_item = all_views_filtered[view_i] image_req_option = TSC.ImageRequestOptions( imageresolution=TSC.ImageRequestOptions.Resolution. High) # Assumes col 0,1,2 are imageName, FileType, and Email respectively for iter_ in range(3, num_col): # column_header[iter_] takes the nth item across in column header, # row header [iter_] takes the same nth item acrpss in the row # pases it to like this: # image_req_option.vf( Color By , 2) # image_req_option.vf( Bubble Color, 1) # image_req_option.vf( Sales Channel, Channel1) if (row[iter_] == "All"): image_req_option.view_filters.clear() break else: image_req_option.vf(column_header[iter_], row[iter_]) server.views.populate_image(view_item, image_req_option) image_filepath = view_item.name with open( end_file_directory + "/" + image_filepath + row[0] + "." + row[1], "wb") as image_file: image_file.write(view_item.image) elif (row[1] == "PDF"): view_item = all_views_filtered[view_i] pdf_req_option = TSC.PDFRequestOptions( page_type=TSC.PDFRequestOptions.PageType.A4, orientation=TSC.PDFRequestOptions.Orientation. Portrait) # Assumes col 0,1,2 are imageName, FileType, and Email respectively for iter_ in range(3, num_col): if (row[iter_] == "All"): pdf_req_option.view_filters.clear() break else: pdf_req_option.vf(column_header[iter_], row[iter_]) server.views.populate_pdf(view_item, pdf_req_option) pdf_name = view_item.name with open( end_file_directory + "/" + pdf_name + row[0] + "." + row[1], "wb") as pdf_file: pdf_file.write(view_item.pdf) # full_path = end_file_directory + "/" + pdf_name + row[0] + "." + row[1] # emailScript.email_singlePDF(row[2], full_path, row[0], UserEmail) print(row) line_count += 1 print(f'Processed {line_count} lines.') server.auth.sign_out()
def handler(event, context): logger.info(event) session = boto3.Session(region_name='us-east-1') ssm = session.client('ssm') user = ssm.get_parameter(Name='/tableau/user', WithDecryption=True)['Parameter']['Value'] password = ssm.get_parameter(Name='/tableau/password', WithDecryption=True)['Parameter']['Value'] body = json.loads(event['body']) extract_responses = [] for item in body['payload']: server_name = item['server'] host = ssm.get_parameter( Name=f"/tableau/{server_name}/host")['Parameter']['Value'] logger.info(f"Connecting to {server_name} server") server = TSC.Server(host, use_server_version=True) auth = TSC.TableauAuth(user, password) with server.auth.sign_in(auth): for extract in item['extracts']: extract_name = extract ro = TSC.RequestOptions() filter = TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, extract_name) ro.filter.add(filter) resource, pagination = server.datasources.get(ro) resource = resource[0] logger.info(f'Refreshing datasource - {resource.name}') tableau_response = server.datasources.refresh(resource) extract_response = { 'server': server_name, 'name': resource.name, 'queued_at': None, 'errors': [] } try: created_at = tableau_response.created_at message = f'{resource.name} extract queued at {created_at}' logger.info(message) extract_response['queued_at'] = str(created_at) except AttributeError: message = f'There was an error starting {resource.name}' logger.info(message) logger.error(tableau_response) extract_response['errors'].append(message) extract_responses.append(extract_response) return { 'headers': { 'content-type': 'application/json' }, 'statusCode': 200, 'body': json.dumps({ 'message': 'Success', 'extracts': extract_responses }) }
def main(): parser = argparse.ArgumentParser( description='List project details available on a server') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--site', '-S', default=None) parser.add_argument('-p', default=None) parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') parser.add_argument('project', help='one or more projects to list', nargs='+') args = parser.parse_args() if args.p is None: password = getpass.getpass("password: "******"no project named '{}' found".format( filter_project_name) print(error) server.projects.populate_permissions(project) print("{0}: {1}".format(project.name, project.content_permissions)) print("==================================================") userOptions = TSC.UserRequestOptions( details=TSC.UserRequestOptions.Details.All) users_site, _ = server.users.get(userOptions) users = dict([(u.id, u) for u in users_site]) groups, _ = server.groups.get() for g in groups: print("group: {0}".format(g.name)) server.groups.populate_users(g) for user in g.users: print("{0} ({1}): {2}, {3}".format( users[user.id].name, users[user.id].site_role, users[user.id].fullname, users[user.id].email)) print("--------------------------------------------------") print("==================================================") for c in project.permissions.grantee_capabilities: #print("{0}: {1}, {2}".format(c.grantee_id, c.grantee_type, c.capabilities)) if c.grantee_type == 'group': group = [g for g in groups if g.id == c.grantee_id].pop() print("{0}: {1}".format(group.name, c.capabilities)) if c.grantee_type == 'user': print("{0}: {1}".format(users[c.grantee_id].name, c.capabilities)) print("==================================================")
def main(): '''主函数 ''' # 连接tableau server request_options = TSC.RequestOptions(pagesize=200) tableau_auth = TSC.TableauAuth('20040201', 'GT2020!qaz', site_id='') # tableau_auth = TSC.TableauAuth('GT_Account', 'GT2020123456', site_id='') # server = TSC.Server('https://fas-gt.com:8000', use_server_version=True) server = TSC.Server('https://tab.sucgm.com:10000', use_server_version=True) nowTime = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') # 现在 content = fwapi() infos = content['data'] # print("输出本次全部数据:",infos) connect = sqlcon() workgroup = [] cursor = connect.cursor() # 创建一个游标对象,python里的sql语句都要通过cursor来执行 # 1. 创建文件对象 f = open('user&pwd-' + nowTime + '.csv', 'w', encoding='utf-8', newline='' "") # 2. 基于文件对象构建 csv写入对象 csv_writer = csv.writer(f) # 3. 构建列表头 csv_writer.writerow(["Workcode", "Password"]) tbgroup = tabgroup(server, tableau_auth, request_options) tbuser = tabuser(server, tableau_auth, request_options) # 本次新加入用户计数器 addCount = 0 addRecord = [] # 本次离职人数计数器 quitCount = 0 # 系统账户(不可删除) SystemUser = ['SHCJTS_Admin', '20040201', 'RPA_Account'] for info in infos: # 遍历获取员工信息号和群组名称 workcode = info['workcode'] # workcode = 'A0716' groupidnew = info['rolesmark'] status = info['status'] if status == '1': groupidnew = groupidnew[:-5] # 将群组名称后的 -致同群组 字段删除 workgroup.append([workcode, groupidnew]) print(workcode) # 查询FW_Users库内对应workcoode 人员状态信息 sql = "select * from OFW_USER_TAB_ALLOWED where IsDelete = 0 and MemberCode = %s" # sql = "select * from OFW_USER_TAB_ALLOWED where MemberCode = %s" # sql = "select * from OFW_USER_TAB_ALLOWED_TEST where IsDelete = 0 and MemberCode = %s" cursor.execute(sql, workcode) # 执行sql语句 row = cursor.fetchall() # 读取查询结果, rowCount = len(row) print(row) # for n in row: # print(n[1]) print(workcode, "该员工当前在Tableau Server对应群组记录数", rowCount) # time.sleep(5) # 查询用户是否已存在 若不存在 创建新用户并加入相应群组 if rowCount == 0: # 查询该用户是否之前曾有过群组的记录 sql = "select * from OFW_USER_TAB_ALLOWED where IsDelete = 1 and MemberCode = %s and GroupID= %s" # sql = "select * from OFW_USER_TAB_ALLOWED_TEST where IsDelete = 0 and MemberCode = %s and GroupID= %s" value = (workcode, groupidnew) cursor.execute(sql, value) # 执行sql语句 row = cursor.fetchall() # 读取查询结果, rowCount = len(row) if rowCount != 0: sql = "UPDATE OFW_USER_TAB_ALLOWED SET IsDelete =0 WHERE MemberCode = %s and GroupID= %s" # sql = "UPDATE OFW_USER_TAB_ALLOWED_TEST SET IsDelete =0 WHERE MemberCode = %s and GroupID= %s" cursor.execute(sql, value) connect.commit() addCount = addCount + 1 with server.auth.sign_in(tableau_auth): # 将用户加入群组 # index = getTwoDimensionListIndex(tbgroup, groupidnew) user = getTwoDimensionListIndex(tbuser, workcode) # print(user) all_groups, pagination_item = server.groups.get( request_options) for group in all_groups: if group.name == groupidnew: server.groups.add_user(group, tbuser[user][0]) break else: with server.auth.sign_in(tableau_auth): # 先查询用户是否存在 # 将新用户添加至user表 newU = TSC.UserItem(workcode, 'Viewer') # add the new user to the site newU = server.users.add(newU) # 将用户的id,name加入tbuser tbuser.append([newU.id, newU.name]) # 更新详细信息 newU.fullname = workcode # index = getTwoDimensionListIndex(tbgroup, groupidnew) # 加入群组 # if index !="不存在该值": all_groups, pagination_item = server.groups.get( request_options) for group in all_groups: if group.name == groupidnew: server.groups.add_user(group, newU.id) break # else: # print(index) pwd = pwdcreate() csv_writer.writerow([workcode, pwd]) user1 = server.users.update(newU, password=pwd) sql2 = "insert into OFW_USER_TAB_ALLOWED (MemberCode,GroupID) VALUES (%s,%s)" # sql2 = "insert into OFW_USER_TAB_ALLOWED_TEST (MemberCode,GroupID) VALUES (%s,%s)" value = (workcode, groupidnew) cursor.execute(sql2, value) connect.commit() print('完成账号 ' + workcode + ' 在群组 ' + groupidnew + ' 的添加') addCount = addCount + 1 addRecord.append([workcode, groupidnew]) # 用户已存在的情况 else: # 查询该用户是否之前曾有过群组的记录 sql = "select * from OFW_USER_TAB_ALLOWED where IsDelete = 1 and MemberCode = %s and GroupID= %s" # sql = "select * from OFW_USER_TAB_ALLOWED_TEST where IsDelete = 1 and MemberCode = %s and GroupID= %s" value = (workcode, groupidnew) cursor.execute(sql, value) # 执行sql语句 rowold = cursor.fetchall() # 读取查询结果, rowCount = len(rowold) # 无群组记录 if rowCount != 0: # rowCount不为0 说明该用户在该群组之前有记录被删除,将isdel置0# sql = "UPDATE OFW_USER_TAB_ALLOWED SET IsDelete =0 WHERE MemberCode = %s and GroupID= %s" # sql = "UPDATE OFW_USER_TAB_ALLOWED_TEST SET IsDelete =0 WHERE MemberCode = %s and GroupID= %s" cursor.execute(sql, value) connect.commit() with server.auth.sign_in(tableau_auth): # 将用户加入群组 # index = getTwoDimensionListIndex(tbgroup, groupidnew) user = getTwoDimensionListIndex(tbuser, workcode) # print(user) all_groups, pagination_item = server.groups.get( request_options) for group in all_groups: if group.name == groupidnew: server.groups.add_user(group, tbuser[user][0]) print('完成账号 ' + workcode + ' 在群组 ' + groupidnew + ' 的添加') addCount = addCount + 1 addRecord.append([workcode, groupidnew]) break else: oldgroup = [] # 该员工原有的群组 for n in row: oldgroup.append(n[1]) # api传递的数据是一一对应的情况 print(workcode, "该员工对应原有群组", oldgroup) if groupidnew not in oldgroup: with server.auth.sign_in(tableau_auth): # 将用户加入群组 # index = getTwoDimensionListIndex(tbgroup, groupidnew) user = getTwoDimensionListIndex(tbuser, workcode) print(user) all_groups, pagination_item = server.groups.get( request_options) for group in all_groups: if group.name == groupidnew: server.groups.add_user( group, tbuser[user][0]) break # 更新详细信息 # newU.name = 'test' # newU.fullname = workcode sql2 = "insert into OFW_USER_TAB_ALLOWED (MemberCode,GroupID) VALUES (%s,%s)" # sql2 = "insert into OFW_USER_TAB_ALLOWED_TEST (MemberCode,GroupID) VALUES (%s,%s)" value = (workcode, groupidnew) cursor.execute(sql2, value) connect.commit() print('完成账号 ' + workcode + ' 在群组 ' + groupidnew + ' 的添加') addCount = addCount + 1 addRecord.append([workcode, groupidnew]) f.close() cursor = connect.cursor() # 创建一个游标对象,python里的sql语句都要通过cursor来执行 # 查询群组表内的群组信息 sql = "select GroupName from OFW_GROUP_TAB_ALLOWED" # sql = "select GroupName from OFW_GROUP_TAB_ALLOWED_TEST" cursor.execute(sql) # 执行sql语句 rowgroup = cursor.fetchall() # 读取查询结果, # rowCount = len(row) for groupid in rowgroup: # print(groupid) groupid = groupid[0] # 查询表内对应该群组的workcode sqls = "select MemberCode from OFW_USER_TAB_ALLOWED where GroupID= %s and IsDelete =0" # sqls = "select MemberCode from OFW_USER_TAB_ALLOWED_TEST where GroupID= %s" cursor.execute(sqls, groupid) # 执行sql语句 rowidingroups = cursor.fetchall() # 读取查询结果, # print(rowidingroups) for rowidingroup in rowidingroups: rawdata = rowidingroup[0] # 此处注意判断是否有另外开的账号 需要加在指定群组中 但不在泛微数据中 if [rawdata, groupid] not in workgroup: # 通过tsc 获取id 在group中删除 # indexgroup=getTwoDimensionListIndex(tbgroup,groupid) indexuser = getTwoDimensionListIndex(tbuser, rawdata) with server.auth.sign_in(tableau_auth): # mygroup = tbgroup[indexgroup][0] userdel = tbuser[indexuser][0] all_groups, pagination_item = server.groups.get( request_options) for group in all_groups: if group.name == groupid: server.groups.remove_user(group, userdel) # 若该群组不存在 进行逻辑删除 sql = "UPDATE OFW_USER_TAB_ALLOWED SET IsDelete =1 WHERE MemberCode = %s and GroupID= %s" # sql = "UPDATE OFW_USER_TAB_ALLOWED_TEST SET IsDelete =1 WHERE MemberCode = %s and GroupID= %s" value = (rawdata, groupid) cursor.execute(sql, value) # 提交到数据库执行 connect.commit() break print('完成对 ' + rawdata + " 在群组 " + groupid + " 的删除操作") for userid in tbuser: # 判断是否为非城建用户 if userid[1] not in SystemUser: sql = "select * from DW_HR_MEMBER where MemberMsgCode = %s AND snapdate = CONVERT(DATE,GETDATE(),110)" cursor.execute(sql, userid[1]) # 执行sql语句 row = cursor.fetchall() # 读取查询结果, rowCount = len(row) # 为0代表用户已离职 从tableau server端删除 计数器+1 if rowCount == 0: with server.auth.sign_in(tableau_auth): server.users.remove(userid[0]) print('员工' + userid[1] + '已离职,从Tableau Server端删除成功') quitCount = quitCount + 1 print('本次共删除用户' + str(quitCount) + '人') # 统计各群组新增用户 if addRecord: for record in addRecord: print('本次已完成对用户 ' + record[0] + ' 在群组 ' + record[1] + '中的添加') print('本次完成群组新增' + str(addCount) + '人')
def main(): logger.debug('Loading config...') config = configparser.ConfigParser() config_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'tableausync.conf') config.read_file(open(config_path)) config_sections = config.sections() do_something = config.get('Common', 'do_something') if do_something in ['True']: do_something = True logger.info('This is the real deal, updating data in the system') else: do_something = False logger.info('It is TEST RUN') ad_server = config.get('AD', 'server') ad_user = config.get('AD', 'user') ad_password = config.get('AD', 'password') tableau_root_ou = config.get('AD', 'tableau_root_ou') users_root_ou = config.get('AD', 'users_root_ou') tableau_server = config.get('Tableau', 'server') tableau_admin = config.get('Tableau', 'username') tableau_password = config.get('Tableau', 'password') ad = AD(ad_server, ad_user, ad_password, tableau_root_ou, users_root_ou) tableau_auth = TSC.TableauAuth(tableau_admin, tableau_password) tableau_server = TSC.Server(tableau_server) with tableau_server.auth.sign_in(tableau_auth): opts = TSC.RequestOptions(pagesize=1000) tableau_all_site_users = [user for user in TSC.Pager(tableau_server.users) if user.site_role != 'Unlicensed'] tableau_unlicensed_users = [user for user in TSC.Pager(tableau_server.users) if user.site_role == 'Unlicensed'] for group in TSC.Pager(tableau_server.groups): # get ad_members_set for this group if(not group.name == 'All Users'): logger.info("Getting AD Group Members for: {}".format(group.name)) ad_members = ad.get_members_by_groupname(group.name) ad_members_set = set([user.sAMAccountName.value for user in ad_members]) logger.info("AD Members #: {}".format(len(ad_members_set))) # get tab_members_set for this group logger.info("Getting Tableau Group Members for: {}".format(group.name)) tableau_server.groups.populate_users(group, opts) tableau_members_set = set([user.name for user in group.users]) logger.info("Tableau Members #: {}".format(len(tableau_members_set))) add_members = ad_members_set - tableau_members_set remove_members = tableau_members_set - ad_members_set logger.info("Group {} - Adding Users: {}".format(group.name, add_members)) logger.info("Group {} - Removing Users: {}".format(group.name, remove_members)) if do_something: for new_member in add_members: logger.debug("Adding user:{0}".format(new_member)) user_id = [user.id for user in tableau_all_site_users if user.name == new_member].pop() tableau_server.groups.add_user(user_id=user_id, group_item=group) if do_something: for old_member in remove_members: logger.debug("Removing user:{0}".format(old_member)) user_id = [user.id for user in tableau_all_site_users if user.name == old_member][0] tableau_server.groups.remove_user(user_id=user_id, group_item=group)
def setPagination(): return TSC.RequestOptions(pagesize=1000)
def main(): parser = argparse.ArgumentParser(description='Filter and sort projects.') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--site', '-S', default=None) parser.add_argument('-p', default=None) parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') args = parser.parse_args() if args.p is None: password = getpass.getpass("Password: "******"No project named '{}' found".format(filter_project_name) print(error) create_example_project(name='Example 1', server=server) create_example_project(name='Example 2', server=server) create_example_project(name='Example 3', server=server) create_example_project(name='Proiect ca Exemplu', server=server) options = TSC.RequestOptions() # don't forget to URL encode the query names options.filter.add(TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.In, ['Example+1', 'Example+2', 'Example+3'])) options.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Direction.Desc)) matching_projects, pagination_item = server.projects.get(req_options=options) print('Filtered projects are:') for project in matching_projects: print(project.name, project.id)
def main(): try: tableauPassword, gitPassword, environment, env_site_id = getCreds() logger.info('Preparing Backup') #setting up tableau login credentials tableau_auth = TSC.TableauAuth(cfg['tableauServer']['user'], tableauPassword, site_id=env_site_id) server = TSC.Server(cfg['tableauServer']['url'], use_server_version=True) firstTime = False #check if there is git repo, if not clone the repository oPath = cfg['git']['projectName'] #if os.path.isdir(oPath) is False: # Repo.clone_from('http://'+cfg['git']['login']+':'+gitPassword+'@'+cfg['git']['url'].split('://', 1)[1], oPath) # firstTime = True if os.path.isdir(oPath) is False: git_ssh_identity_file = os.path.expanduser('/home/.ssh/id_rsa') git_ssh_cmd = 'ssh -i %s' % git_ssh_identity_file with Git().custom_environment(GIT_SSH_COMMAND=git_ssh_cmd): Repo.clone_from('git@git_url/repository.git', oPath, branch='develop') firstTime = True repo = git.Repo(oPath) oPath = oPath + "/" + environment #logging into tableau server server.auth.sign_in(tableau_auth) #setting time stamp for one hour previous from when this script is run currentTime = datetime.now() downloadChangesSince = (datetime.fromtimestamp( (currentTime.timestamp() - args.incremental * 3600)).replace( microsecond=0)).isoformat() + 'Z' if firstTime is True or args.full_load == True: downloadChangesSince = '2000-01-01T00:00:00Z' req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.UpdatedAt, TSC.RequestOptions.Operator.GreaterThanOrEqual, downloadChangesSince)) remove_punctuation_map = dict( (ord(char), None) for char in '\/*?:"<>|') #iterating through each site on tableau for site in TSC.Pager(server.sites): logger.info( 'Backing up workbooks and datasources under the {} site changed after {}' .format(site.name, downloadChangesSince)) #logging into the specific site tableau_auth1 = TSC.TableauAuth(cfg['tableauServer']['user'], tableauPassword, site_id=site.content_url) server.auth.sign_in(tableau_auth1) sPath = os.path.join(oPath, site.name.translate(remove_punctuation_map)) if os.path.isdir(sPath) is False: os.makedirs(sPath) #iterating through each workbook in the specified site to download and extract for workbook in TSC.Pager(server.workbooks, req_option): workbookName = workbook.project_name.translate( remove_punctuation_map) xPath = os.path.join(sPath, workbookName) if os.path.isdir(xPath) is False: os.makedirs(xPath) file_path = server.workbooks.download(workbook.id, filepath=xPath, no_extract=True) print('---- path ----------') print('---- ' + file_path) print('---- ' + site.name) print('---- ' + workbookName) print('---- ' + workbook.project_id) print('---- ' + workbook.id) print('--- /path-----------') extractWorkbook(file_path, site.name, workbookName, workbook.project_id, workbook.id, os.path.basename(file_path), xPath) #iterating through each datasource in the specified site to downlad and extract for datasources in TSC.Pager(server.datasources, req_option): datasourcesName = datasources.project_name.translate( remove_punctuation_map) dPath = os.path.join(sPath, datasourcesName) if os.path.isdir(dPath) is False: os.makedirs(dPath) file_path = server.datasources.download(datasources.id, filepath=dPath, include_extract=False) extractDatasource(file_path, site.name, datasourcesName, datasources.project_id, datasources.id, os.path.basename(file_path), dPath) #pushing changes to git and timestamping when this script was run print(repo.git.status()) if "nothing to commit" not in repo.git.status(): repo.git.add('.') repo.git.commit(m="backup of" + environment + ": " + currentTime.strftime('%Y-%m-%d %H-%M-%S')) repo.git.push('origin') print("backed up to git") logger.info('Backup Complete') server.auth.sign_out() except: logging.exception('error') pass
def main(): parser = argparse.ArgumentParser(description="Move one workbook from the" "default project of the default site to" "the default project of another site.") parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--workbook-name', '-w', required=True, help='name of workbook to move') parser.add_argument('--destination-site', '-d', required=True, help='name of site to move workbook into') parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') args = parser.parse_args() password = getpass.getpass("Password: "******"No site named {} found.".format( args.destination_site) raise LookupError(error) tableau_auth.site_id = args.destination_site # Signing into another site requires another server object # because of the different auth token and site ID. with dest_server.auth.sign_in(tableau_auth): # Step 5: Create a new workbook item and publish workbook. Note that # an empty project_id will publish to the 'Default' project. new_workbook = TSC.WorkbookItem(name=args.workbook_name, project_id="") new_workbook = dest_server.workbooks.publish( new_workbook, workbook_path, mode=TSC.Server.PublishMode.Overwrite) print("Successfully moved {0} ({1})".format( new_workbook.name, new_workbook.id)) # Step 6: Delete workbook from source site and delete temp directory source_server.workbooks.delete(all_workbooks[0].id) finally: shutil.rmtree(tmpdir)
def main(): parser = argparse.ArgumentParser(description="Creates sample schedules for each type of frequency.") # Common options; please keep those in sync across all samples parser.add_argument("--server", "-s", required=True, help="server address") parser.add_argument("--site", "-S", help="site name") parser.add_argument( "--token-name", "-p", required=True, help="name of the personal access token used to sign into the server" ) parser.add_argument( "--token-value", "-v", required=True, help="value of the personal access token used to sign into the server" ) parser.add_argument( "--logging-level", "-l", choices=["debug", "info", "error"], default="error", help="desired logging level (set to error by default)", ) # Options specific to this sample: # This sample has no additional options, yet. If you add some, please add them here args = parser.parse_args() # Set logging level based on user input, or error by default 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=False) server.add_http_options({"verify": False}) server.use_server_version() with server.auth.sign_in(tableau_auth): # Hourly Schedule # This schedule will run every 2 hours between 2:30AM and 11:00PM hourly_interval = TSC.HourlyInterval(start_time=time(2, 30), end_time=time(23, 0), interval_value=2) hourly_schedule = TSC.ScheduleItem( "Hourly-Schedule", 50, TSC.ScheduleItem.Type.Extract, TSC.ScheduleItem.ExecutionOrder.Parallel, hourly_interval, ) try: hourly_schedule = server.schedules.create(hourly_schedule) print("Hourly schedule created (ID: {}).".format(hourly_schedule.id)) except Exception as e: print(e) # Daily Schedule # This schedule will run every day at 5AM daily_interval = TSC.DailyInterval(start_time=time(5)) daily_schedule = TSC.ScheduleItem( "Daily-Schedule", 60, TSC.ScheduleItem.Type.Subscription, TSC.ScheduleItem.ExecutionOrder.Serial, daily_interval, ) try: daily_schedule = server.schedules.create(daily_schedule) print("Daily schedule created (ID: {}).".format(daily_schedule.id)) except Exception as e: print(e) # Weekly Schedule # This schedule will wun every Monday, Wednesday, and Friday at 7:15PM weekly_interval = TSC.WeeklyInterval( time(19, 15), TSC.IntervalItem.Day.Monday, TSC.IntervalItem.Day.Wednesday, TSC.IntervalItem.Day.Friday ) weekly_schedule = TSC.ScheduleItem( "Weekly-Schedule", 70, TSC.ScheduleItem.Type.Extract, TSC.ScheduleItem.ExecutionOrder.Serial, weekly_interval, ) try: weekly_schedule = server.schedules.create(weekly_schedule) print("Weekly schedule created (ID: {}).".format(weekly_schedule.id)) except Exception as e: print(e) options = TSC.RequestOptions() options.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, "Weekly Schedule") ) schedules, _ = server.schedules.get(req_options=options) weekly_schedule = schedules[0] print(weekly_schedule) # Monthly Schedule # This schedule will run on the 15th of every month at 11:30PM monthly_interval = TSC.MonthlyInterval(start_time=time(23, 30), interval_value=15) monthly_schedule = TSC.ScheduleItem( "Monthly-Schedule", 80, TSC.ScheduleItem.Type.Subscription, TSC.ScheduleItem.ExecutionOrder.Parallel, monthly_interval, ) try: monthly_schedule = server.schedules.create(monthly_schedule) print("Monthly schedule created (ID: {}).".format(monthly_schedule.id)) except Exception as e: print(e) # Now fetch the weekly schedule by id fetched_schedule = server.schedules.get_by_id(weekly_schedule.id) fetched_interval = fetched_schedule.interval_item print("Fetched back our weekly schedule, it shows interval ", fetched_interval)
print('\nGET THE WORKBOOK BY LUID and its VIEWS >>>') workbook = server.workbooks.get_by_id( '5fba2c81-76b3-4b29-b24b-0f69eca3703f') server.workbooks.populate_views( workbook) #get only the views of that particular workbook print('Views of the Workbook uder ID: ', workbook.id, ' (name : ', workbook.name, ')', ' are: ', [view.name for view in workbook.views]) # - 05 - get all usernames and LUIDs print('\nGET USERS NAMES AND LUIDs >>>') all_users, pagination_item = server.users.get() print('All the Users: ', [user.name for user in all_users]) print('IDs of the Users: ', [user.id for user in all_users]) # - 06 - get user by name print('\nGET USER BY NAME >>>') req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, 'User01')) matching_user, pagination_item = server.users.get(req_option) print('Username is: ', matching_user[0].name, 'and LUID of the user:'******'\nGET WORKBOOKS FOR THE SPECIFIC USER >>>') server.users.populate_workbooks(matching_user[0]) print("The workbooks for", matching_user[0].name, "are :") for workbook in matching_user[0].workbooks: print(workbook.name)
def main(): parser = argparse.ArgumentParser(description="Filter and sort projects.") # Common options; please keep those in sync across all samples parser.add_argument("--server", "-s", required=True, help="server address") parser.add_argument("--site", "-S", help="site name") parser.add_argument( "--token-name", "-p", required=True, help="name of the personal access token used to sign into the server") parser.add_argument( "--token-value", "-v", required=True, help="value of the personal access token used to sign into the server") parser.add_argument( "--logging-level", "-l", choices=["debug", "info", "error"], default="error", help="desired logging level (set to error by default)", ) # Options specific to this sample # This sample has no additional options, yet. If you add some, please add them here args = parser.parse_args() # Set logging level based on user input, or error by default 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): # Use highest Server REST API version available server.use_server_version() filter_project_name = "default" options = TSC.RequestOptions() options.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, filter_project_name)) filtered_projects, _ = server.projects.get(req_options=options) # Result can either be a matching project or an empty list if filtered_projects: project_name = filtered_projects.pop().name print(project_name) else: error = "No project named '{}' found".format(filter_project_name) print(error) create_example_project(name="Example 1", server=server) create_example_project(name="Example 2", server=server) create_example_project(name="Example 3", server=server) create_example_project(name="Proiect ca Exemplu", server=server) options = TSC.RequestOptions() # don't forget to URL encode the query names options.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.In, ["Example+1", "Example+2", "Example+3"])) options.sort.add( TSC.Sort(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Direction.Desc)) matching_projects, pagination_item = server.projects.get( req_options=options) print("Filtered projects are:") for project in matching_projects: print(project.name, project.id) # Or, try the django style filtering. projects = ["Example 1", "Example 2", "Example 3"] projects = [urllib.parse.quote_plus(p) for p in projects] for project in server.projects.filter(name__in=projects).sort("-name"): print(project.name, project.id)
def main(): parser = argparse.ArgumentParser( description='Query View Image From Server') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--site-id', '-si', required=False, help='content url for site the view is on') parser.add_argument('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--view-name', '-v', required=True, help='name of view to download an image of') parser.add_argument('--filepath', '-f', required=True, help='filepath to save the image returned') parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') args = parser.parse_args() password = getpass.getpass("Password: "******"" tableau_auth = TSC.TableauAuth(args.username, password, site_id=site_id) server = TSC.Server(args.server) # The new endpoint was introduced in Version 2.5 server.version = "2.5" with server.auth.sign_in(tableau_auth): # Step 2: Query for the view that we want an image of req_option = TSC.RequestOptions() req_option.filter.add( TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, args.view_name)) all_views, pagination_item = server.views.get(req_option) if not all_views: raise LookupError("View with the specified name was not found.") view_item = all_views[0] # Step 3: Query the image endpoint and save the image to the specified location image_req_option = TSC.ImageRequestOptions( imageresolution=TSC.ImageRequestOptions.Resolution.High) server.views.populate_image(view_item, image_req_option) with open(args.filepath, "wb") as image_file: image_file.write(view_item.image) print("View image saved to {0}".format(args.filepath))
def publish(self, creation_mode='CreateNew'): """Publishes a Hyper File to a Tableau Server""" # Ensure that the Hyper File exists if not os.path.isfile(self.hyper_file_path): error = "{0}: Hyper File not found".format(self.hyper_file_path) raise IOError(error) # Check the Hyper File size hyper_file_size = os.path.getsize(self.hyper_file_path) logging.info(f"The Hyper File size is (in bytes): {hyper_file_size}") username_pw_auth = TSC.TableauAuth(username=self.username, password=self.password, site_id=self.site_id) server = TSC.Server(self.tableau_server_url) server.use_server_version() with server.auth.sign_in(username_pw_auth): # Search for project on the Tableau server, filtering by project name req_options = TSC.RequestOptions() req_options.filter.add(TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, self.project_name)) projects, pagination = server.projects.get(req_options=req_options) for project in projects: if project.name == self.project_name: logging.info(f'Found project on Tableau server. Project ID: {project.id}') self.project_id = project.id # If project was not found on the Tableau Server, raise an error if self.project_id is None: raise ValueError(f'Invalid project name. Could not find project named "{self.project_name}" ' f'on the Tableau server.') # Next, check if the datasource already exists and needs to be overwritten create_mode = TSC.Server.PublishMode.CreateNew if creation_mode.upper() == 'CREATENEW': # Search for the datasource under project name req_options = TSC.RequestOptions() req_options.filter.add(TSC.Filter(TSC.RequestOptions.Field.ProjectName, TSC.RequestOptions.Operator.Equals, self.project_name)) req_options.filter.add(TSC.Filter(TSC.RequestOptions.Field.Name, TSC.RequestOptions.Operator.Equals, self.datasource_name)) datasources, pagination = server.datasources.get(req_options=req_options) for datasource in datasources: # the datasource already exists, overwrite if datasource.name == self.datasource_name: logging.info(f'Overwriting existing datasource named "{self.datasource_name}".') create_mode = TSC.Server.PublishMode.Overwrite break elif creation_mode.upper() == 'APPEND': create_mode = TSC.Server.PublishMode.Append else: raise ValueError(f'Invalid "creation_mode" : {creation_mode}') # Finally, publish the Hyper File to the Tableau server logging.info(f'Publishing Hyper File located at: "{self.hyper_file_path}"') logging.info(f'Create mode: {create_mode}') datasource_item = TSC.DatasourceItem(project_id=self.project_id, name=self.datasource_name) logging.info(f'Publishing datasource: \n{datasource_to_string(datasource_item)}') datasource_item = server.datasources.publish(datasource_item, self.hyper_file_path, create_mode) self.datasource_luid = datasource_item.id logging.info(f'Published datasource to Tableau server. Datasource LUID : {self.datasource_luid}') logging.info("Done.") return self.datasource_luid