Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions tableauserverclient/models/user_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,27 @@ def _validate_attribute_value(item: str, possible_values: list[str], column_type
return
raise AttributeError(f"Invalid value {item} for {column_type}")

# Inverse of _evaluate_site_role: decompose a site role back to (license, admin_level, publish)
# for writing the CSV import format.
@staticmethod
def _decompose_site_role(site_role: str) -> tuple[str, str, str]:
"""Return (license, admin_level, publish) CSV column values for a given site role."""
_role_map: dict[str, tuple[str, str, str]] = {
"ServerAdministrator": ("Creator", "System", "1"),
"SiteAdministratorCreator": ("Creator", "Site", "1"),
"SiteAdministratorExplorer": ("Explorer", "Site", "1"),
"SiteAdministrator": ("Explorer", "Site", "1"), # legacy role, treat as SiteAdministratorExplorer
"Creator": ("Creator", "None", "1"),
"ExplorerCanPublish": ("Explorer", "None", "1"),
"Explorer": ("Explorer", "None", "0"),
"Viewer": ("Viewer", "None", "0"),
"Unlicensed": ("Unlicensed", "None", "0"),
"ReadOnly": ("Viewer", "None", "0"),
"Publisher": ("Explorer", "None", "1"),
"Interactor": ("Explorer", "None", "0"),
}
return _role_map.get(site_role, ("Unlicensed", "None", "0"))

# https://help.tableau.com/current/server/en-us/csvguidelines.htm#settings_and_site_roles
# This logic is hardcoded to match the existing rules for import csv files
@staticmethod
Expand Down
23 changes: 4 additions & 19 deletions tableauserverclient/server/endpoint/users_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ def create_from_file(self, filepath: str) -> tuple[list[UserItem], list[tuple[Us
warnings.warn("This method is deprecated, use bulk_add instead", DeprecationWarning)
created = []
failed = []
if not filepath.find("csv"):
if "csv" not in filepath:
raise ValueError("Only csv files are accepted")

with open(filepath) as csv_file:
Expand All @@ -536,11 +536,9 @@ def create_from_file(self, filepath: str) -> tuple[list[UserItem], list[tuple[Us
while line and line != "":
user: UserItem = UserItem.CSVImport.create_user_from_line(line)
try:
print(user)
result = self.add(user)
created.append(result)
except ServerResponseError as serverError:
print("failed")
failed.append((user, serverError))
line = csv_file.readline()
return created, failed
Expand Down Expand Up @@ -751,6 +749,7 @@ def create_users_csv(users: Iterable[UserItem]) -> bytes:
- Admin Level
- Publish capability
- Email
- Auth setting

Parameters
----------
Expand All @@ -765,22 +764,7 @@ def create_users_csv(users: Iterable[UserItem]) -> bytes:
with io.StringIO() as output:
writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
for user in users:
site_role = user.site_role or "Unlicensed"
if site_role == "ServerAdministrator":
license = "Creator"
admin_level = "System"
elif site_role.startswith("SiteAdministrator"):
admin_level = "Site"
license = site_role.replace("SiteAdministrator", "")
else:
license = site_role
admin_level = ""

if any(x in site_role for x in ("Creator", "Admin", "Publish")):
publish = 1
else:
publish = 0

license, admin_level, publish = UserItem.CSVImport._decompose_site_role(user.site_role or "Unlicensed")
writer.writerow(
(
f"{user.domain_name}\\{user.name}" if user.domain_name else user.name,
Expand All @@ -790,6 +774,7 @@ def create_users_csv(users: Iterable[UserItem]) -> bytes:
admin_level,
publish,
user.email,
user.auth_setting or "",
)
)
output.seek(0)
Expand Down
5 changes: 3 additions & 2 deletions test/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ def test_create_users_csv() -> None:
"ServerAdministrator": "System",
}

csv_columns = ["name", "password", "fullname", "license", "admin", "publish", "email"]
csv_columns = ["name", "password", "fullname", "license", "admin", "publish", "email", "auth"]
csv_data = create_users_csv(users)
csv_file = io.StringIO(csv_data.decode("utf-8"))
csv_reader = csv.reader(csv_file)
Expand All @@ -417,8 +417,9 @@ def test_create_users_csv() -> None:
assert (user.fullname or "") == csv_user["fullname"]
assert (user.email or "") == csv_user["email"]
assert license_map[site_role] == csv_user["license"]
assert admin_map.get(site_role, "") == csv_user["admin"]
assert admin_map.get(site_role, "None") == csv_user["admin"]
assert publish_map[site_role] == int(csv_user["publish"])
assert (user.auth_setting or "") == csv_user["auth"]


def test_bulk_add(server: TSC.Server) -> None:
Expand Down
Loading