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
11 changes: 10 additions & 1 deletion tableauserverclient/models/user_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,16 @@ class UserItem:
Parameters
----------
name: str
The name of the user.
The username used to authenticate the user, NOT the person's display
name (that is ``fullname``). The required format depends on the site's
authentication scheme:

- Tableau Cloud: the sign-in email address (e.g. ``user@example.com``).
- Local authentication (on-prem Tableau Server): any unique username
for the site (e.g. ``jsmith``).
- Active Directory: the fully-qualified AD username, typically
``SAMAccountName@FullyQualifiedDomain`` (e.g.
``jsmith@corp.example.com``), or the User Principal Name (UPN).

site_role: str
The role of the user on the site.
Expand Down
26 changes: 26 additions & 0 deletions tableauserverclient/server/endpoint/projects_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,32 @@ def update_permissions(self, item: ProjectItem, rules: list[PermissionsRule]) ->
-------
list[PermissionsRule]
Returns the updated list of permissions rules.

Examples
--------
Assign a group as Project Leader on a project. ``ProjectLeader`` is
the capability that grants the group the ability to publish and
manage content in the project as if they were the project owner.

>>> import tableauserverclient as TSC
>>> server = TSC.Server('https://SERVERURL')
>>> # Login to the server

>>> project = next(p for p in TSC.Pager(server.projects) if p.name == 'Marketing')
>>> group = next(g for g in TSC.Pager(server.groups) if g.name == 'Marketing Leads')

>>> rule = TSC.PermissionsRule(
... grantee=group,
... capabilities={
... TSC.Permission.Capability.ProjectLeader: TSC.Permission.Mode.Allow,
... },
... )
>>> server.projects.update_permissions(project, [rule])

Note: ``update_permissions`` REPLACES the full permissions list on the
project. Any existing rules not included in the call will be removed.
To preserve existing rules, call ``populate_permissions(project)``
first, then modify ``project.permissions`` and pass the full list.
"""

return self._permissions.update(item, rules)
Expand Down
34 changes: 28 additions & 6 deletions tableauserverclient/server/endpoint/users_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,26 @@ def add(self, user_item: UserItem) -> UserItem:
To add a new user to the site you need to first create a new user_item
(from UserItem class). When you create a new user, you specify the name
of the user and their site role. For Tableau Cloud, you also specify
the auth_setting attribute in your request. When you add user to
Tableau Cloud, the name of the user must be the email address that is
used to sign in to Tableau Cloud. After you add a user, Tableau Cloud
sends the user an email invitation. The user can click the link in the
invitation to sign in and update their full name and password.
the auth_setting attribute in your request. After you add a user, Tableau
Cloud sends the user an email invitation. The user can click the link in
the invitation to sign in and update their full name and password.

The value of ``user_item.name`` is the username the server uses to
authenticate the user, NOT the person's display name. Its required
format depends on the site's authentication scheme:

- Tableau Cloud: the user's email address (e.g. ``user@example.com``),
which is also what they sign in with.
- Local authentication (on-prem Tableau Server): any username unique to
the site (e.g. ``jsmith``).
- Active Directory: the fully-qualified AD username, either
``SAMAccountName@FullyQualifiedDomain`` (e.g.
``jsmith@corp.example.com``) or the User Principal Name (UPN) if AD
is configured to use UPNs. A bare ``SAMAccountName`` typically will
not resolve.

Set the person's display name via ``user_item.fullname`` — it is a
separate attribute.

Parameters
----------
Expand Down Expand Up @@ -333,9 +348,16 @@ def add(self, user_item: UserItem) -> UserItem:
>>> server = TSC.Server('https://SERVERURL')
>>> # Login to the server

>>> new_user = TSC.UserItem(name='new_user', site_role=TSC.UserItem.Role.Unlicensed)
>>> # Tableau Cloud: name must be the sign-in email address
>>> new_user = TSC.UserItem(name='jsmith@example.com', site_role=TSC.UserItem.Role.Explorer)
>>> new_user.auth_setting = TSC.UserItem.Auth.TableauIDWithMFA
>>> new_user.fullname = 'Jane Smith'
>>> new_user = server.users.add(new_user)

>>> # Active Directory-backed Tableau Server: name is SAMAccountName@Domain
>>> ad_user = TSC.UserItem(name='jsmith@corp.example.com', site_role=TSC.UserItem.Role.Viewer)
>>> ad_user = server.users.add(ad_user)

"""
url = self.baseurl
logger.info(f"Add user {user_item.name}")
Expand Down
40 changes: 40 additions & 0 deletions tableauserverclient/server/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,46 @@


class Filter:
"""Represents a single Tableau REST API filter clause.

A `Filter` is one entry in a `?filter=` query parameter and serializes as
``<field>:<operator>:<value>``. Use one filter per attribute, and pass
multiple filters via `RequestOptions.filter.add(...)` if you need to AND
conditions.

Special characters in filter values
----------------------------------
The REST API's filter grammar treats several characters as delimiters. The
server does NOT support escaping them, so a value containing any of these
characters cannot be matched exactly with the `Equals` operator:

- ``,`` — separates values in an ``in`` list.
- ``&`` — separates filter clauses.
- ``:`` — separates field/operator/value.
- ``[`` and ``]`` — bracket an ``in`` value list.

Workaround for names containing these characters: use the ``Equals``
operator with an asterisk substituted for the special character. Asterisk
behaves as a wildcard, so for example filtering a workbook named
``T(L-F,SZ&V-MY) - PC`` can be found via ``name="T(L-F*SZ*V-MY) - PC"``.
Post-filter the result client-side to disambiguate if multiple names could
match.

Parameters
----------
field : str
The field to filter on (e.g. ``RequestOptions.Field.Name``).

operator : str
The operator to apply (e.g. ``RequestOptions.Operator.Equals``,
``In``, ``GreaterThan``).

value : str | int | bool | datetime | list
The value to compare against. Lists require operator ``In``. Datetimes
must be timezone-aware and serialize as ISO-8601 UTC. Bools serialize
as lowercase ``true``/``false``.
"""

def __init__(self, field, operator, value):
self.field = field
self.operator = operator
Expand Down
12 changes: 12 additions & 0 deletions tableauserverclient/server/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ def page_size(self: Self) -> int:
return self._pagination_item.page_size or self.request_options.pagesize

def filter(self: Self, *invalid, page_size: int | None = None, **kwargs) -> Self:
"""Add filter clauses to the queryset.

Each keyword argument becomes one filter. Shorthand suffixes select
the operator (e.g. ``name__gt="A"`` -> operator ``GreaterThan``); a
bare keyword uses ``Equals``. See ``docs/filter-sort.md`` for the
supported suffixes.

Special-character caveat: values containing ``,``, ``&``, ``:``, ``[``
or ``]`` cannot be matched exactly with ``Equals``; the REST filter
grammar treats them as delimiters and the server does not support
escaping. See ``Filter`` for details and the wildcard workaround.
"""
if invalid:
raise RuntimeError("Only accepts keyword arguments.")
for kwarg_key, value in kwargs.items():
Expand Down
Loading