diff --git a/tableauserverclient/models/user_item.py b/tableauserverclient/models/user_item.py index 365e44c1d..d7d029940 100644 --- a/tableauserverclient/models/user_item.py +++ b/tableauserverclient/models/user_item.py @@ -79,7 +79,11 @@ class Auth: ServerDefault = "ServerDefault" def __init__( - self, name: Optional[str] = None, site_role: Optional[str] = None, auth_setting: Optional[str] = None + self, + name: Optional[str] = None, + site_role: Optional[str] = None, + auth_setting: Optional[str] = None, + idp_configuration_id: Optional[str] = None, ) -> None: self._auth_setting: Optional[str] = None self._domain_name: Optional[str] = None @@ -89,11 +93,13 @@ def __init__( self._workbooks = None self._favorites: Optional[dict[str, list]] = None self._groups = None + self._idp_configuration_id: Optional[str] = None self.email: Optional[str] = None self.fullname: Optional[str] = None self.name: Optional[str] = name self.site_role: Optional[str] = site_role self.auth_setting: Optional[str] = auth_setting + self._idp_configuration_id = idp_configuration_id return None @@ -129,6 +135,10 @@ def id(self) -> Optional[str]: def id(self, value: str) -> None: self._id = value + @property + def idp_configuration_id(self) -> Optional[str]: + return self._idp_configuration_id + @property def last_login(self) -> Optional[datetime]: return self._last_login @@ -204,8 +214,11 @@ def _parse_common_tags(self, user_xml, ns) -> "UserItem": email, auth_setting, _, + idp_configuration_id, ) = self._parse_element(user_xml, ns) - self._set_values(None, None, site_role, None, None, fullname, email, auth_setting, None) + self._set_values( + None, None, site_role, None, None, fullname, email, auth_setting, None, idp_configuration_id + ) return self def _set_values( @@ -219,6 +232,7 @@ def _set_values( email, auth_setting, domain_name, + idp_configuration_id=None, ): if id is not None: self._id = id @@ -238,6 +252,8 @@ def _set_values( self._auth_setting = auth_setting if domain_name: self._domain_name = domain_name + if idp_configuration_id: + self._idp_configuration_id = idp_configuration_id @classmethod def from_response(cls, resp, ns) -> list["UserItem"]: @@ -265,6 +281,7 @@ def _parse_xml(cls, element_name, resp, ns): email, auth_setting, domain_name, + idp_configuration_id, ) = cls._parse_element(user_xml, ns) user_item = cls(name, site_role) user_item._set_values( @@ -277,6 +294,7 @@ def _parse_xml(cls, element_name, resp, ns): email, auth_setting, domain_name, + idp_configuration_id, ) all_user_items.append(user_item) return all_user_items @@ -295,6 +313,7 @@ def _parse_element(user_xml, ns): fullname = user_xml.get("fullName", None) email = user_xml.get("email", None) auth_setting = user_xml.get("authSetting", None) + idp_configuration_id = user_xml.get("idpConfigurationId", None) domain_name = None domain_elem = user_xml.find(".//t:domain", namespaces=ns) @@ -311,6 +330,7 @@ def _parse_element(user_xml, ns): email, auth_setting, domain_name, + idp_configuration_id, ) class CSVImport: diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py index 575423612..e7fbd37b4 100644 --- a/tableauserverclient/server/request_factory.py +++ b/tableauserverclient/server/request_factory.py @@ -911,6 +911,8 @@ def update_req(self, user_item: UserItem, password: Optional[str]) -> bytes: user_element.attrib["siteRole"] = user_item.site_role if user_item.auth_setting: user_element.attrib["authSetting"] = user_item.auth_setting + if user_item.idp_configuration_id: + user_element.attrib["idpConfigurationId"] = user_item.idp_configuration_id if password: user_element.attrib["password"] = password return ET.tostring(xml_request) @@ -929,6 +931,8 @@ def add_req(self, user_item: UserItem) -> bytes: if user_item.auth_setting: user_element.attrib["authSetting"] = user_item.auth_setting + if user_item.idp_configuration_id: + user_element.attrib["idpConfigurationId"] = user_item.idp_configuration_id return ET.tostring(xml_request) diff --git a/test/assets/user_add.xml b/test/assets/user_add.xml index 6a19ab0e6..8e3f27b0e 100644 --- a/test/assets/user_add.xml +++ b/test/assets/user_add.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/test/test_user.py b/test/test_user.py index 645adcfd5..066520db3 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -1,5 +1,6 @@ import os import unittest +import uuid import requests_mock @@ -132,13 +133,18 @@ def test_add(self) -> None: response_xml = f.read().decode("utf-8") with requests_mock.mock() as m: m.post(self.baseurl + "", text=response_xml) - new_user = TSC.UserItem(name="Cassie", site_role="Viewer", auth_setting="ServerDefault") + # Use a fixed UUID for testing so it matches the XML response + test_idp_id = "b47f41b1-2c47-41a3-8b17-a38ebe8b340c" + new_user = TSC.UserItem( + name="Cassie", site_role="Viewer", auth_setting="ServerDefault", idp_configuration_id=test_idp_id + ) new_user = self.server.users.add(new_user) self.assertEqual("4cc4c17f-898a-4de4-abed-a1681c673ced", new_user.id) self.assertEqual("Cassie", new_user.name) self.assertEqual("Viewer", new_user.site_role) self.assertEqual("ServerDefault", new_user.auth_setting) + self.assertEqual(test_idp_id, new_user.idp_configuration_id) def test_populate_workbooks(self) -> None: with open(POPULATE_WORKBOOKS_XML, "rb") as f: diff --git a/test/test_user_model.py b/test/test_user_model.py index a8a2c51cb..df3f336f4 100644 --- a/test/test_user_model.py +++ b/test/test_user_model.py @@ -2,6 +2,7 @@ import unittest from unittest.mock import * import io +import uuid import pytest @@ -19,6 +20,11 @@ def test_invalid_site_role(self): with self.assertRaises(ValueError): user.site_role = "Hello" + def test_idp_configuration_id(self): + idp_id = str(uuid.uuid4()) + user = TSC.UserItem("test", "Viewer", auth_setting="SAML", idp_configuration_id=idp_id) + self.assertEqual(idp_id, user.idp_configuration_id) + class UserDataTest(unittest.TestCase): logger = logging.getLogger("UserDataTest")