tableau / document-api-python

Create and modify Tableau workbook and datasource files
https://tableau.github.io/document-api-python/
MIT License
331 stars 177 forks source link

Functionality for interacting with group filters (for use in row level security) #177

Closed graham-macleod closed 4 years ago

graham-macleod commented 4 years ago

Implement functionality to allow me to iterate through groups, and groupfilters. Included in this should be the ability to add or alter groupfilters.

We currently implement row level security by creating a user filter on the column in question which is used to filter, and then applying this as a data source filter, mapping groups to values.

If we then have new values to be filtered on, it is a tedious process to update all of these especially if it is a volatile dimension.

For our use-case we would need the ability to target a group by name, check if the groupfilter expression exists, and if it doesn't exist, add in the new groupfilter expression and groupfilter function.

For example, an example below shows a user filter called "RLS User Filter" which has 5 groups listed within the row level security.

  <group name='[RLS User Filter]' name-style='unqualified' user:ui-builder='identity-set'>
    <groupfilter function='intersection'>
      <groupfilter function='level-members' level='[Security Column Name]' />
      <groupfilter function='union'>
        <groupfilter expression='false' function='filter'>
          <groupfilter function='level-members' level='[Security Column Name]' />
        </groupfilter>
        <groupfilter expression='ISMEMBEROF(&apos;group 1&apos;)' function='filter'>
          <groupfilter function='member' level='[Security Column Name]' member='&quot;RLS Dimension Value 1&quot;' />
        </groupfilter>
        <groupfilter expression='ISMEMBEROF(&apos;group 2&apos;)' function='filter'>
          <groupfilter function='member' level='[Security Column Name]' member='&quot;RLS Dimension Value 2&quot;' />
        </groupfilter>
        <groupfilter expression='ISMEMBEROF(&apos;group 3&apos;)' function='filter'>
          <groupfilter function='member' level='[Security Column Name]' member='&quot;RLS Dimension Value 3&quot;' />
        </groupfilter>
        <groupfilter expression='ISMEMBEROF(&apos;group 4&apos;)' function='filter'>
          <groupfilter function='member' level='[Security Column Name]' member='&quot;RLS Dimension Value 4&quot;' />
        </groupfilter>
        <groupfilter expression='ISMEMBEROF(&apos;group 5&apos;)' function='filter'>
          <groupfilter function='member' level='[Security Column Name]' member='&quot;RLS Dimension Value 5&quot;' />
        </groupfilter>
      </groupfilter>
    </groupfilter>
  </group>

If I then wanted to add an entry for a new group called "group 6", the XML in the group would be updated to include the following groupfilter expression and groupfilter function.

<groupfilter expression='ISMEMBEROF(&apos;group 6&apos;)' function='filter'>
  <groupfilter function='member' level='[Security Column Name]' member='&quot;RLS Dimension Value 6&quot;' />
</groupfilter>
graham-macleod commented 4 years ago

This already exists as #33