コード例 #1
0
ファイル: Workbooks.py プロジェクト: Sam-Holmes/tableau-rest
    def download(self,
                 authentication,
                 export_type,
                 path,
                 filename,
                 filters=""):
        filter_string = ""
        if export_type == "image":
            filename += ".png"
        if export_type == "data":
            filename += ".csv"
        if export_type == "PDF":
            # export_type = "image"
            filename += ".pdf"
        if not filters == "":
            filter_string = "?vf_" + filters
        url = authentication.server + "/api/{0}/sites/{1}/views/{2}/{3}{4}".format(
            Tools.VERSION, authentication.site_id, self.view_id, export_type,
            filter_string)

        server_response = authentication.session.get(
            url, headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)
        # Header format: Content-Disposition: name="tableau_workbook"; filename="workbook-filename"
        # filename = re.findall(r'filename="(.*)"', server_response.headers['Content-Disposition'])[0]
        output = path + filename.replace('/', '-')
        with open(output, 'wb') as f:
            f.write(server_response.content)
コード例 #2
0
def create(authentication, name, description, log):
    """
    Creates the Project on the server. However to store this project into a project obj you will need to query the
    server.
    :param authentication: authentication: <authentication obj> :class Auth:
    :param name: Project Name
    :param description: Project Description
    :param log: log: <logging obj>
    """
    logger = log
    url = authentication.server + "/api/{0}/sites/{1}/projects".format(
        Tools.VERSION, authentication.site_id)

    # xml_response = ET.fromstring(Tools.encode_for_display(server_response.text))
    xml_request = ET.Element('tsRequest')
    project_element = ET.SubElement(xml_request,
                                    'project',
                                    parentProjectId="",
                                    name=name,
                                    description=description,
                                    contentPermissions="LockedToProject")
    xml_request = ET.tostring(xml_request)
    server_response = authentication.session.post(
        url,
        data=xml_request,
        headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 201)
コード例 #3
0
def add_datasource(authentication, capability, datasource_id, group_user,
                   group_id):
    '''
    Function to add default permissions at a datasources level
    :param authentication: The authentication object holding all information for the signed in session
    :param capability: Key value pair, consisting of below permissions followed by "Allow"/"Deny"
    AddComment, ChangeHierarchy, ChangePermissions, Delete, ExportData, ExportImage, ExportXml,
    Filter, Read, ShareView, ViewComments, ViewUnderlyingData, WebAuthoring, and Write.
    :param project_id: id for the project that you are assigning the permissions
    :param group_user: String to specify group or user
    :param group_id: id of the group receiving the permissions, interchangable with user id
    :return:
    '''
    url = authentication.server + "/api/{0}/sites/{1}/datasources/{2}/permissions".format(
        Tools.VERSION, authentication.site_id, datasource_id)
    xml_request = ET.Element('tsRequest')
    project_element = ET.SubElement(xml_request, 'permissions')
    ET.SubElement(xml_request, "datasource", id=datasource_id)
    capability_element = ET.SubElement(project_element, "granteeCapabilities")
    group_element = ET.SubElement(capability_element, group_user, id=group_id)
    capabilities = ET.SubElement(capability_element, "capabilities")
    for key, value in capability.items():
        ET.SubElement(capabilities, "capability", name=key, mode=value)
    xml_request = ET.tostring(xml_request)

    server_response = authentication.session.put(
        url,
        data=xml_request,
        headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 200)
コード例 #4
0
    def delete(self, authentication):
        url = authentication.server + "/api/{0}/sites/{1}/projects/{2}".format(
            Tools.VERSION, authentication.site_id, self.project_id)

        server_response = authentication.session.delete(
            url, headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 204)
コード例 #5
0
    def delete(self):
        url = self.authentication.server + "/api/{0}/schedules/{1}".format(
            Tools.VERSION, self.schedule_id)

        server_response = requests.delete(
            url, headers={'x-tableau-auth': self.authentication.get_token()})
        Tools.check_status(server_response, 204)
コード例 #6
0
    def get_workgroup_id(self, session, repos_url=""):
        if repos_url:
            url = repos_url + "/vizportal/api/web/v1/getSchedules"
        else:
            url = self.authentication.server + "/vizportal/api/web/v1/getSchedules"

        payload = "{\"method\":\"getSchedules\",\"params\":{\"filter\":{\"operator\":\"and\",\"clauses\":[{\"operator\":\"eq\", \"field\":\"siteId\", \"value\":\"4\"}]},\"order\":[{\"field\":\"name\",\"ascending\":true}],\"page\":{\"startIndex\":0,\"maxItems\":1000}}}"
        xsrf_token = self.authentication.get_viz_token()
        # Make the request to server
        server_response = session.post(url,
                                       headers={
                                           'content-type':
                                           "application/json;charset=UTF-8",
                                           'accept':
                                           "application/json, text/plain, */*",
                                           'cache-control': "no-cache",
                                           'X-XSRF-TOKEN': xsrf_token
                                       },
                                       data=payload)
        response_json = json.loads(server_response.text)
        returned_schedules = response_json["result"]["schedules"]
        for s in returned_schedules:
            if s['name'] == self.name:
                self.set_workgroup_id(s['id'])
        Tools.check_status(server_response, 200)
        # ASCII encode server response to enable displaying to console
        server_response = Tools.encode_for_display(server_response.text)
コード例 #7
0
    def get_workgroup_id(self, session, repos_url=""):
        """
        for use with the vizportal API the repository(workgroup) id is required, this function gets said id.
        :param session:
        :param repos_url:
        :return:
        """
        if repos_url:
            url = repos_url + "/vizportal/api/web/v1/setExtractTasksSchedule"
        else:
            url = self.authentication.server + "/vizportal/api/web/v1/setExtractTasksSchedule"

        payload = "{\"method\":\"getExtractTasks\",\"params\":{\"filter\":{\"operator\":\"and\",\"clauses\":[{\"operator\":\"eq\",\"field\":\"siteId\",\"value\":\"4\"}]},\"order\":[{\"field\":\"targetName\",\"ascending\":true}],\"page\":{\"startIndex\":0,\"maxItems\":1000}}}"
        xsrf_token = self.authentication.get_viz_token()
        # Make the request to server
        server_response = session.post(url,
                                       headers={
                                           'content-type':
                                           "application/json;charset=UTF-8",
                                           'accept':
                                           "application/json, text/plain, */*",
                                           'cache-control': "no-cache",
                                           'X-XSRF-TOKEN': xsrf_token
                                       },
                                       data=payload)
        response_json = json.loads(server_response.text)
        returned_task = response_json["result"]["tasks"]
        for s in returned_tasks:
            if s['name'] == self.name:
                # Todo not sure any frame of validation here, task id is the only consistent which this is identifying.
                self.workgroup_id = (s['id'])
        print(server_response)
        Tools.check_status(server_response, 200)
        # ASCII encode server response to enable displaying to console
        server_response = Tools.encode_for_display(server_response.text)
コード例 #8
0
    def set_task_schedule(self, task_id, schedule_id, session, repos_url=""):
        """
        Again built using the vizportal API which is not recommended.
        :param task_id:
        :param schedule_id:
        :param session:
        :param repos_url:
        :return:
        """
        if repos_url:
            url = repos_url + "/vizportal/api/web/v1/setExtractTasksSchedule"
        else:
            url = self.authentication.server + "/vizportal/api/web/v1/setExtractTasksSchedule"

        payload = "{\"method\":\"setExtractTasksSchedule\",\"params\":{\"ids\":[\"%s\"], \"scheduleId\":\"%s\"}}" % (
            task_id, schedule_id)
        xsrf_token = self.authentication.get_viz_token()
        # Make the request to server
        server_response = session.post(url,
                                       headers={
                                           'content-type':
                                           "application/json;charset=UTF-8",
                                           'accept':
                                           "application/json, text/plain, */*",
                                           'cache-control': "no-cache",
                                           'X-XSRF-TOKEN': xsrf_token
                                       },
                                       data=payload)
        Tools.check_status(server_response, 200)

        # ASCII encode server response to enable displaying to console
        server_response = Tools.encode_for_display(server_response.text)
コード例 #9
0
ファイル: Workbooks.py プロジェクト: Sam-Holmes/tableau-rest
def query_view(authentication, name, workbook_id):
    """
    Gets the workbook info and stores it
    :param authentication: authentication object that grants user access to API calls and holds any signin info
    :param name: the name of the workbook
    :return:
    """
    url = authentication.server + "/api/{0}/sites/{1}/workbooks/{2}/views?includeUsageStatistics=true".format(
        Tools.VERSION, authentication.site_id, workbook_id)

    server_response = authentication.session.get(
        url, headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 200)
    xml_response = ET.fromstring(Tools.encode_for_display(
        server_response.text))

    views = xml_response.findall('.//t:view', namespaces=Tools.XMLNS)

    for v in views:
        if v.get('name') == name:
            # source_workbook_id = v.find('.//t:workbook', namespaces=Tools.XMLNS).get('id')
            # source_owner_id = v.find('.//t:owner', namespaces=Tools.XMLNS).get('id')
            # source_view_count = v.find('.//t:usage', namespaces=Tools.XMLNS).get('totalViewCount')

            view = View(v.get('name'), v.get('id'), v.get('contentUrl'),
                        workbook_id)
            # source_owner_id, source_view_count)
            return view
    error = "View named '{0}' not found.".format(name)
    raise LookupError(error)
コード例 #10
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
def remove_from_site(authentication, user_id, logger):
    url = authentication.server + "/api/{0}/sites/{1}/users/{2}".format(
        Tools.VERSION, authentication.site_id, user_id)

    server_response = authentication.session.delete(
        url, headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 204)
    pass
コード例 #11
0
def query(authentication, log, name=""):
    """
    Returns Project(s) from Tableau Server.
    :param authentication: <authentication obj> :class Auth:
    :param log: <logging obj>
    :param name: if not stated will return all projects on specified server.
    :return:
    """
    logger = log
    done = False
    page_size = 100
    page_number = 1
    total_returned = 0

    output_projects = []

    if name == "":
        logger.debug("No name specified, pulling all projects")

    while not (done):
        url = authentication.server + "/api/{0}/sites/{1}/projects".format(
            Tools.VERSION, authentication.site_id)
        url += "?pageSize={0}&pageNumber={1}".format(page_size, page_number)

        server_response = authentication.session.get(
            url, headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)
        xml_response = ET.fromstring(
            Tools.encode_for_display(server_response.text))
        # Get total number of records from the <pagination> element
        total_available = xml_response.find('.//t:pagination',
                                            namespaces={
                                                't': "http://tableau.com/api"
                                            }).attrib['totalAvailable']
        # Note! Need to convert "total_available" to integer
        total_available = int(total_available)

        page_number += 1
        total_returned += page_size
        projects = xml_response.findall('.//t:project', namespaces=Tools.XMLNS)

        for p in projects:
            if name == "":
                project = Project(p.get('id'), p.get('name'),
                                  p.get('description'),
                                  p.get('contentPermission'))
                output_projects.append(project)
            elif p.get('name') == name:
                project = Project(p.get('id'), p.get('name'),
                                  p.get('description'),
                                  p.get('contentPermission'))
                return project
        if total_returned >= total_available:
            done = True
            if name == "":
                return output_projects
    error = "Project named '{0}' not found.".format(name)
    raise LookupError(error)
コード例 #12
0
ファイル: Auth.py プロジェクト: Sam-Holmes/tableau-rest
 def sign_out(self):
     """Sign out of tableau Server, destroying the Authentication Token"""
     url = self.server + "/api/{0}/auth/signout".format(Tools.VERSION)
     server_response = self.session.post(
         url, headers={'x-tableau-auth': self.token})
     Tools.check_status(server_response, 204)
     self.set_token("")
     del self
     return
コード例 #13
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
def query_group(authentication, log, name=''):
    """
    Returns group(s) from Tableau Server.
    :param authentication: <authentication obj> :class Auth:
    :param log: <logging obj>
    :param name: if not stated will return all groups on specified server.
    :return: <Group Obj> or list<Group Obj>
    """

    logger = log
    done = False
    page_size = 100
    page_number = 1
    total_returned = 0
    returned_groups = []
    while not (done):
        url = authentication.server + "/api/{0}/sites/{1}/groups".format(
            Tools.VERSION, authentication.site_id)
        url += "?pageSize={0}&pageNumber={1}".format(page_size, page_number)

        server_response = authentication.session.get(
            url, headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)
        xml_response = ET.fromstring(
            Tools.encode_for_display(server_response.text))
        # Get total number of records from the <pagination> element
        total_available = xml_response.find('.//t:pagination',
                                            namespaces={
                                                't': "http://tableau.com/api"
                                            }).attrib['totalAvailable']
        # Note! Need to convert "total_available" to integer
        total_available = int(total_available)

        page_number += 1
        total_returned += page_size
        groups = xml_response.findall('.//t:group', namespaces=Tools.XMLNS)
        for g in groups:
            if name == '':
                domain_name = g.find('.//t:domain',
                                     namespaces=Tools.XMLNS).get('name')
                group = Group(g.get('id'), g.get('name'), domain_name, logger)
                returned_groups.append(group)
            elif g.get('name') == name:
                domain_name = g.find('.//t:domain',
                                     namespaces=Tools.XMLNS).get('name')
                group = Group(g.get('id'), g.get('name'), domain_name, logger)
                return group
        if total_returned >= total_available:
            done = True

    if name == "":
        return returned_groups
    error = "Group named '{0}' not found.".format(name)
    raise LookupError(error)
コード例 #14
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
def query_user(authentication, log, name=""):
    """
    Returns users(s) from Tableau Server.
    :param authentication: <authentication obj> :class Auth:
    :param log: <logging obj>
    :param name: if not stated will return all users on specified server.
    :return: <User Obj> or list<User Obj>
    """

    logger = log
    done = False
    page_size = 100
    page_number = 1
    total_returned = 0
    return_users = []
    while not (done):
        url = authentication.server + "/api/{0}/sites/{1}/users".format(
            Tools.VERSION, authentication.site_id)
        url += "?pageSize={0}&pageNumber={1}".format(page_size, page_number)

        server_response = authentication.session.get(
            url, headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)
        xml_response = ET.fromstring(
            Tools.encode_for_display(server_response.text))
        # Get total number of records from the <pagination> element
        total_available = xml_response.find('.//t:pagination',
                                            namespaces={
                                                't': "http://tableau.com/api"
                                            }).attrib['totalAvailable']
        # Note! Need to convert "total_available" to integer
        total_available = int(total_available)

        page_number += 1
        total_returned += page_size
        users = xml_response.findall('.//t:user', namespaces=Tools.XMLNS)

        for u in users:
            if name != "":
                if u.get('name').upper() == name.upper():
                    user = User(u.get('id'), u.get('name'), u.get('siteRole'),
                                u.get('lastLogin'))
                    return user
            else:
                user = User(u.get('id'), u.get('name'), u.get('siteRole'),
                            u.get('lastLogin'))
                return_users.append(user)
        if total_returned >= total_available:
            done = True
            if name == "":
                return return_users
    error = "User named '{0}' not found.".format(name)
    raise LookupError(error)
コード例 #15
0
ファイル: Workbooks.py プロジェクト: Sam-Holmes/tableau-rest
    def get_preview_image(self, authentication, path, filename):
        url = authentication.server + "/api/{0}/sites/{1}/workbooks/{2}/views/{3}/previewImage".format(
            Tools.VERSION, authentication.site_id, self.workbook_id,
            self.view_id)

        server_response = authentication.session.get(
            url, headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)
        # Header format: Content-Disposition: name="tableau_workbook"; filename="workbook-filename"
        # filename = re.findall(r'filename="(.*)"', server_response.headers['Content-Disposition'])[0]
        output = path + filename.replace('/', '-')
        with open(output, 'wb') as f:
            f.write(server_response.content)
コード例 #16
0
    def create(self,
               type,
               start_time,
               frequency,
               interval="",
               end_time="",
               execution_order="Parallel",
               priority="50"):
        url = self.authentication.server + "/api/{0}/schedules".format(
            Tools.VERSION)
        # Builds the request
        xml_payload = ET.Element('tsRequest')
        schedule_element = ET.SubElement(xml_payload,
                                         'schedule',
                                         name=self.name,
                                         priority=priority,
                                         type=type,
                                         frequency=frequency,
                                         executionOrder=execution_order)
        fd = ET.SubElement(schedule_element,
                           'frequencyDetails',
                           start=start_time,
                           end=end_time)

        if frequency != "Daily":
            intervals_element = ET.SubElement(fd, 'intervals')
            if frequency == "Hourly":
                ET.SubElement(intervals_element,
                              'interval',
                              hours=interval,
                              minutes=interval)
            elif frequency == "Weekly":
                ET.SubElement(intervals_element, 'interval', weekDay=interval)
            elif frequency == "Monthly":
                ET.SubElement(intervals_element, 'interval', monthDay=interval)
        xml_payload = ET.tostring(xml_payload)
        # Make the request to server
        server_response = requests.post(
            url,
            headers={'x-tableau-auth': self.authentication.get_token()},
            data=xml_payload)
        Tools.check_status(server_response, 201)

        # ASCII encode server response to enable displaying to console
        server_response = Tools.encode_for_display(server_response.text)

        # Reads and parses the response
        parsed_response = ET.fromstring(server_response)
コード例 #17
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
def add_to_site(authentication, name, site_role, log):
    logger = log
    url = authentication.server + "/api/{0}/sites/{1}/users".format(
        Tools.VERSION, authentication.site_id)
    xml_request = ET.Element('tsRequest')
    user_element = ET.SubElement(xml_request,
                                 'user',
                                 name=name,
                                 siteRole=site_role)
    xml_request = ET.tostring(xml_request)

    server_response = authentication.session.post(
        url,
        data=xml_request,
        headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 201)
コード例 #18
0
ファイル: Publish.py プロジェクト: Sam-Holmes/tableau-rest
def start_upload_session(server, auth_token, site_id):
    """
    Creates a POST request that initiates a file upload session.

    'server'        specified server address
    'auth_token'    authentication token that grants user access to API calls
    'site_id'       ID of the site that the user is signed into
    Returns a session ID that is used by subsequent functions to identify the upload session.
    """
    url = server + "/api/{0}/sites/{1}/fileUploads".format(
        Tools.VERSION, site_id)
    server_response = requests.post(url,
                                    headers={'x-tableau-auth': auth_token})
    Tools.check_status(server_response, 201)
    xml_response = ET.fromstring(Tools.encode_for_display(
        server_response.text))
    return xml_response.find('t:fileUpload',
                             namespaces=Tools.XMLNS).get('uploadSessionId')
コード例 #19
0
ファイル: Workbooks.py プロジェクト: Sam-Holmes/tableau-rest
def download(packaged, authentication, workbook_id, path):
    if packaged:
        url = authentication.server + "/api/{0}/sites/{1}/workbooks/{2}/content?includeExtract=True".format(
            Tools.VERSION, authentication.site_id, workbook_id)
    else:
        url = authentication.server + "/api/{0}/sites/{1}/workbooks/{2}/content?includeExtract=False".format(
            Tools.VERSION, authentication.site_id, workbook_id)
    server_response = authentication.session.get(
        url, headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 200)
    # Header format: Content-Disposition: name="tableau_workbook"; filename="workbook-filename"
    # filename = re.findall(r'filename="(.*)"', server_response.headers['Content-Disposition'])[0]
    extension = re.findall(r'filename="(.*)"',
                           server_response.headers['Content-Disposition'])[0]
    extension = extension.split('.')[1]
    with open("{}.{}".format(path, extension), 'wb') as f:
        f.write(server_response.content)
        return "{}.{}".format(path, extension)
コード例 #20
0
ファイル: Auth.py プロジェクト: Sam-Holmes/tableau-rest
    def swap_site(self, site):
        url = self.server + "/api/{0}/auth/switchSite".format(Tools.VERSION)

        if site == "":
            site_name = "Default Site"
        else:
            site_name = site

        # Builds the request
        xml_payload = ET.Element('tsRequest')
        credentials_element = ET.SubElement(xml_payload,
                                            'site',
                                            contentUrl=site.replace(" ", ""))
        xml_payload = ET.tostring(xml_payload)
        print("\nSwapping site to", site_name, "...")
        # Make the request to server
        server_response = self.session.post(
            url,
            headers={'x-tableau-auth': self.get_token()},
            data=xml_payload)
        Tools.check_status(server_response, 200)

        # ASCII encode server response to enable displaying to console
        server_response = Tools.encode_for_display(server_response.text)

        # Reads and parses the response
        parsed_response = ET.fromstring(server_response)

        # Gets the auth token, site ID and user ID
        self.set_token(
            parsed_response.find('t:credentials',
                                 namespaces=Tools.XMLNS).get('token'))
        self.set_site_id(
            parsed_response.find('.//t:site',
                                 namespaces=Tools.XMLNS).get('id'))
        self.set_user_id(
            parsed_response.find('.//t:user',
                                 namespaces=Tools.XMLNS).get('id'))
        print("\nNow Signed into", site_name)

        return self.get_token
コード例 #21
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
    def get_details(self, authentication):
        done = False
        page_size = 100
        page_number = 1
        total_returned = 0

        while not (done):
            url = authentication.server + "/api/{0}/sites/{1}/groups".format(
                Tools.VERSION, authentication.site_id)
            url += "?pageSize={0}&pageNumber={1}".format(
                page_size, page_number)

            server_response = authentication.session.get(
                url, headers={'x-tableau-auth': authentication.get_token()})
            Tools.check_status(server_response, 200)
            xml_response = ET.fromstring(
                Tools.encode_for_display(server_response.text))
            # Get total number of records from the <pagination> element
            total_available = xml_response.find('.//t:pagination',
                                                namespaces={
                                                    't':
                                                    "http://tableau.com/api"
                                                }).attrib['totalAvailable']
            # Note! Need to convert "total_available" to integer
            total_available = int(total_available)

            page_number += 1
            total_returned += page_size
            groups = xml_response.findall('.//t:group', namespaces=Tools.XMLNS)

            for g in groups:
                if g.get('name') == self.name:
                    self.group_id = g.get('id')
                    if self.domain_name == "":
                        self.domain_name = g.find(
                            './/t:domain', namespaces=Tools.XMLNS).get('name')
                    return self
            if total_returned >= total_available:
                done = True
        error = "Group named '{0}' not found.".format(self.name)
        raise LookupError(error)
コード例 #22
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
    def add(self, authentication, user_id):
        """
        Adds the given user_id to the current group.
        :param authentication:
        :param user_id:
        :return:
        """
        url = authentication.server + "/api/{0}/sites/{1}/groups/{2}/users".format(
            Tools.VERSION, authentication.site_id, self.group_id)

        xml_request = ET.Element('tsRequest')
        # for user_id in user_ids:
        group_element = ET.SubElement(xml_request, 'user', id=user_id)

        xml_request = ET.tostring(xml_request)

        server_response = authentication.session.post(
            url,
            data=xml_request,
            headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)
コード例 #23
0
ファイル: Auth.py プロジェクト: Sam-Holmes/tableau-rest
    def sign_in_as(self, user_id):
        """Sign into tableau Server as a user. If user is not unique it will require domain. Creating the Authentication
         Token"""
        url = self.server + "/api/{0}/auth/signin".format(Tools.VERSION)
        # Builds the request
        xml_payload = ET.Element('tsRequest')
        credentials_element = ET.SubElement(xml_payload,
                                            'credentials',
                                            name=self.username,
                                            password=self.password)
        ET.SubElement(credentials_element, 'site', contentUrl=self.site)
        ET.SubElement(credentials_element, 'user', id=user_id)
        xml_payload = ET.tostring(xml_payload)
        logger.info("\nSigning in as {}, to {} on the {} site...".format(
            self.username, self.server, self.site))
        # Make the request to server
        server_response = self.session.post(url, data=xml_payload)
        Tools.check_status(server_response, 200)

        # ASCII encode server response to enable displaying to console
        server_response = Tools.encode_for_display(server_response.text)

        # Reads and parses the response
        parsed_response = ET.fromstring(server_response)
        logger.debug("Returned a response of {}".format(parsed_response))

        # Gets the auth token, site ID and user ID of the signed in user.
        self.set_token(
            parsed_response.find('t:credentials',
                                 namespaces=Tools.XMLNS).get('token'))
        self.set_site_id(
            parsed_response.find('.//t:site',
                                 namespaces=Tools.XMLNS).get('id'))
        self.set_user_id(
            parsed_response.find('.//t:user',
                                 namespaces=Tools.XMLNS).get('id'))
        logger.info("\nSigned in as {}, to {} on the {} site...".format(
            self.username, self.server, self.site))

        return self.get_token
コード例 #24
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
def create_group(authentication, name, log):
    """
    Creates the Group on the server. However to store this group into a group obj you will need to query the
    server.
    :param authentication: authentication: <authentication obj> :class Auth:
    :param name: Group Name
    :param log: <logging obj>
    """
    logger = log
    url = authentication.server + "/api/{0}/sites/{1}/groups".format(
        Tools.VERSION, authentication.site_id)

    xml_request = ET.Element('tsRequest')
    group_element = ET.SubElement(xml_request, 'group', name=name)
    xml_request = ET.tostring(xml_request)
    server_response = authentication.session.post(
        url,
        data=xml_request,
        headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 201)

    return Group("", name, "", logger)
コード例 #25
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
def update_user(authentication, user, log):
    """
    Use to change details of the given User Object on the Server. Will take current values if new value not
    specified
    :param authentication: authentication: <authentication obj> :class Auth:
    :param user: Updated user object.
    :param log: <logging obj>
    :return:
    """
    # PUT /api/api-version/sites/site-id/users/user-id
    logger = log
    url = authentication.server + "/api/{0}/sites/{1}/users/{2}".format(
        Tools.VERSION, authentication.site_id, user.user_id)
    xml_request = ET.Element('tsRequest')
    # Currently we can only change site role, as everything else is drawn through AD
    user_element = ET.SubElement(xml_request, 'user', siteRole=user.site_role)
    xml_request = ET.tostring(xml_request)

    server_response = authentication.session.put(
        url,
        data=xml_request,
        headers={'x-tableau-auth': authentication.get_token()})
    Tools.check_status(server_response, 200)
コード例 #26
0
ファイル: Users.py プロジェクト: Sam-Holmes/tableau-rest
    def get_users(self, authentication):
        done = False
        page_size = 100
        page_number = 1
        total_returned = 0
        users_in_group = []

        while not (done):
            url = authentication.server + "/api/{0}/sites/{1}/groups/{2}/users".format(
                Tools.VERSION, authentication.site_id, self.group_id)
            url += "?pageSize={0}&pageNumber={1}".format(
                page_size, page_number)

            server_response = authentication.session.get(
                url, headers={'x-tableau-auth': authentication.get_token()})
            Tools.check_status(server_response, 200)
            xml_response = ET.fromstring(
                Tools.encode_for_display(server_response.text))
            # Get total number of records from the <pagination> element
            total_available = xml_response.find('.//t:pagination',
                                                namespaces={
                                                    't':
                                                    "http://tableau.com/api"
                                                }).attrib['totalAvailable']
            # Note! Need to convert "total_available" to integer
            total_available = int(total_available)

            page_number += 1
            total_returned += page_size
            users = xml_response.findall('.//t:user', namespaces=Tools.XMLNS)
            for u in users:
                user = User(u.get('id'), u.get('name'), u.get('siteRole'),
                            u.get('lastLogin'))
                users_in_group.append(user)
            if total_returned >= total_available:
                done = True
        return users_in_group
コード例 #27
0
ファイル: Publish.py プロジェクト: Sam-Holmes/tableau-rest
def file_extension_check(file_extension, filename, project_id, ds_user,
                         ds_pass, embed):
    """
    Function to check the file extention to allow for the publish command to handle either workbooks or data sources
    :param file_extension:
    :param filename:
    :param project_id:
    :param ds_user:
    :param ds_pass:
    :param embed: Are the credentials Embedded, true/false
    :return: upload_content, upload_content_type, xml_request
    """
    if file_extension == 'twbx' or file_extension == 'twb':
        upload_content = "workbooks"
        upload_content_type = "workbookType"

        # Build a general request for publishing
        xml_request = ET.Element('tsRequest')
        workbook_element = ET.SubElement(xml_request,
                                         'workbook',
                                         name=filename)
        ET.SubElement(workbook_element, 'project', id=project_id)
        xml_request = ET.tostring(xml_request)
    elif file_extension == 'tde' or file_extension == 'tbsx':
        if embed == "":
            embed = "false"
        upload_content = "datasources"
        upload_content_type = "datasourceType"

        # Build a general request for publishing
        xml_request = ET.Element('tsRequest')
        datasource_element = ET.SubElement(xml_request,
                                           'datasource',
                                           name=filename)
        # errors as always creates elements in alphabetical order.
        ET.SubElement(datasource_element,
                      'connectionCredentials',
                      name=ds_user,
                      password=ds_pass,
                      embed=embed)
        ET.SubElement(datasource_element, 'project', id=project_id)
        xml_request = ET.tostring(xml_request)
    else:
        # Call twb publish methods - long term
        error = "This is an unsupported file type."
        raise Tools.UserDefinedFieldError(error)
    print(xml_request)
    return upload_content, upload_content_type, xml_request
コード例 #28
0
ファイル: Publish.py プロジェクト: Sam-Holmes/tableau-rest
def get_project_id(server, project_name, auth_token, site_id):
    """
    Returns the project ID for the project on the Tableau server.

    'server'        specified server address
    'auth_token'    authentication token that grants user access to API calls
    'site_id'       ID of the site that the user is signed into
    """
    page_num, page_size = 1, 1000  # Default paginating values

    # Builds the request
    url = server + "/api/{0}/sites/{1}/projects".format(Tools.VERSION, site_id)
    paged_url = url + "?pageSize={0}&pageNumber={1}".format(
        page_size, page_num)
    server_response = requests.get(paged_url,
                                   headers={'x-tableau-auth': auth_token})
    Tools.check_status(server_response, 200)
    xml_response = ET.fromstring(Tools.encode_for_display(
        server_response.text))

    # Used to determine if more requests are required to find all projects on server
    total_projects = int(
        xml_response.find('t:pagination',
                          namespaces=Tools.XMLNS).get('totalAvailable'))
    max_page = int(math.ceil(total_projects / page_size))

    projects = xml_response.findall('.//t:project', namespaces=Tools.XMLNS)

    # Continue querying if more projects exist on the server
    for page in range(2, max_page + 1):
        paged_url = url + "?pageSize={0}&pageNumber={1}".format(
            page_size, page)
        server_response = requests.get(paged_url,
                                       headers={'x-tableau-auth': auth_token})
        Tools.check_status(server_response, 200)
        xml_response = ET.fromstring(
            Tools.encode_for_display(server_response.text))
        projects.extend(
            xml_response.findall('.//t:project', namespaces=Tools.XMLNS))

    # Look through all projects to find the 'default' one
    for project in projects:
        if project.get('name') == project_name:  # .replace(" ", ""):
            return project.get('id')
    raise LookupError("Project was not found on server")
コード例 #29
0
ファイル: Publish.py プロジェクト: Sam-Holmes/tableau-rest
def publish(project,
            authentication,
            upload_file_path,
            parameter,
            ds_user="",
            ds_pass="",
            embed=""):
    """
     Handles the publishing of Tableau Workbooks and Tableau Datasources based on the file extension.
    :param project: string of project name.
    :param authentication: authentication object
    :param upload_file_path: File path including extension
    :param parameter: overwrite or (append if TDE)true or false
    :return:
    """
    ##### STEP 0: INITIALIZATION #####
    server = authentication.server
    username = authentication.username
    auth_token = authentication.get_token()
    site_id = authentication.get_site_id()

    # workbook_file_path = raw_input("\nWorkbook file to publish (include file extension): ")
    upload_file_path = os.path.abspath(upload_file_path)

    # Workbook file with extension, without full path
    upload_file = os.path.basename(upload_file_path)

    print("\n*Publishing '{0}' to the {1} project as {2}*".format(
        upload_file, project, username))

    if not os.path.isfile(upload_file_path):
        error = "{0}: file not found".format(upload_file_path)
        raise IOError(error)

    # Break workbook file by name and extension
    filename, file_extension = upload_file.split('.', 1)

    # Get workbook size to check if chunking is necessary
    size = os.path.getsize(upload_file_path)
    chunked = size >= FILESIZE_LIMIT

    ##### STEP 2: OBTAIN DEFAULT PROJECT ID #####
    print("\n2. Finding the '{0}' project to publish to)".format(project))
    project_id = get_project_id(server, project, auth_token, site_id)

    upload_content, upload_content_type, xml_request = file_extension_check(
        file_extension, filename, project_id, ds_user, ds_pass, embed)

    if chunked:
        print("\n3. Publishing '{0}' in {1}MB chunks (workbook over 64MB)".
              format(upload_file, CHUNK_SIZE / 1024000))
        # Initiates an upload session
        uploadID = start_upload_session(server, auth_token, site_id)

        # URL for PUT request to append chunks for publishing
        put_url = server + "/api/{0}/sites/{1}/fileUploads/{2}".format(
            Tools.VERSION, site_id, uploadID)

        # Read the contents of the file in chunks of 100KB
        with open(upload_file_path, 'rb') as f:
            while True:
                data = f.read(CHUNK_SIZE)
                if not data:
                    break
                payload, content_type = Tools.make_multipart({
                    'request_payload': ('', '', 'text/xml'),
                    'tableau_file': ('file', data, 'application/octet-stream')
                })
                print("\tPublishing a chunk...")
                server_response = requests.put(put_url,
                                               data=payload,
                                               headers={
                                                   'x-tableau-auth':
                                                   auth_token,
                                                   "content-type": content_type
                                               })
                Tools.check_status(server_response, 200)

        # Finish building request for chunking method
        payload, content_type = Tools.make_multipart(
            {'request_payload': ('', xml_request, 'text/xml')})
        # workbooks || datasources
        publish_url = server + "/api/{0}/sites/{1}/{2}".format(
            Tools.VERSION, site_id, upload_content)
        publish_url += "?uploadSessionId={0}".format(uploadID)
        # workbookType || datasourceType
        if upload_content_type == "workbookType":
            publish_url += "&{0}={1}&overwrite={2}".format(
                upload_content_type, file_extension, parameter)
        elif upload_content_type == "datasourceType" and file_extension == 'tde':
            publish_url += "&{0}={1}&append={2}".format(
                upload_content_type, file_extension, parameter)
        else:
            publish_url += "&{0}={1}&overwrite={2}".format(
                upload_content_type, file_extension, parameter)
    else:
        print("\n3. Publishing '" + upload_file +
              "' using the all-in-one method (workbook under 64MB)")
        # Read the contents of the file to publish
        with open(upload_file_path, 'rb') as f:
            workbook_bytes = f.read()
        # Finish building request for all-in-one method
        parts = {
            'request_payload': ('', xml_request, 'text/xml'),
            'tableau_workbook':
            (upload_file, workbook_bytes, 'application/octet-stream')
        }
        payload, content_type = Tools.make_multipart(parts)

        publish_url = server + "/api/{0}/sites/{1}/{2}?".format(
            Tools.VERSION, site_id, upload_content)
        if upload_content_type == "workbookType":
            publish_url += "&{0}={1}&overwrite={2}".format(
                upload_content_type, file_extension, parameter)
        elif upload_content_type == "datasourceType" and file_extension == 'tde':
            publish_url += "&{0}={1}&append={2}".format(
                upload_content_type, file_extension, parameter)
        else:
            publish_url += "&{0}={1}&overwrite={2}".format(
                upload_content_type, file_extension, parameter)
    # Make the request to publish and check status code
    print("\tUploading...")
    server_response = requests.post(publish_url,
                                    data=payload,
                                    headers={
                                        'x-tableau-auth': auth_token,
                                        'content-type': content_type
                                    })
    Tools.check_status(server_response, 201)
コード例 #30
0
    def update(self,
               authentication,
               name="",
               description="",
               owners=[],
               limit="",
               lifecycle=""):
        """
        Use to change details of the current Project Object on the Server. Will take current values if new value not
        specified.
        :param authentication:
        :param name:
        :param description:
        :param owners:
        :param limit:
        :param lifecycle:
        :return:
        """
        approvers = ""
        count = 0

        if name == "":
            name = self.name

        if not len(owners) < 1:
            for owner in owners:
                if not count > 3:
                    if count == 0:
                        approvers += "<approver>" + owner + "</approver>"
                        count += 1
                    else:
                        approvers += ", " + "<approver" + str(
                            count) + ">" + owner + "</approver" + str(
                                count) + ">"
                        count += 1

        if description == "":
            description = self.description
            # "\n\nThe project owner(s) and approver(s) for this project is " + approvers \
            description += ".\n\nThis project will have a user limit of " + " <userlimit>" + str(
                limit) + "</userlimit> users."
            # users across it's lifecycle of <projectlife>" + lifecycle + "</projectlife>."

        url = authentication.server + "/api/{0}/sites/{1}/projects/{2}".format(
            Tools.VERSION, authentication.site_id, self.project_id)

        # xml_response = ET.fromstring(Tools.encode_for_display(server_response.text))
        xml_request = ET.Element('tsRequest')
        project_element = ET.SubElement(xml_request,
                                        'project',
                                        parentProjectId="",
                                        name=name,
                                        description=description,
                                        contentPermissions="LockedToProject")
        xml_request = ET.tostring(xml_request)

        server_response = authentication.session.put(
            url,
            data=xml_request,
            headers={'x-tableau-auth': authentication.get_token()})
        Tools.check_status(server_response, 200)