tl;dr:
How can I load only user’s own records if user doesn’t have advanced role but load all user records within a tenant if user has advanced role.?
What I tried first
I had a security filter that referenced other rows in the table it was filtering, and AppSheet won’t process it and flags the self-reference as an error, which I now see makes perfect sense. I’m glad for the tight security, but I’m not sure how to accomplish what I need, so I’m reaching out here.
My table
I have a Users table in my multi-tenant app. Every row has (in addition to other columns):
- a UNIQUEID() as the [User ID]
- the user’s [Email] address
- a [Tenant ID] from my Tenants table
- an [Active] boolean
- a [Role] (i.e., Admin, Leader, or Member)
A single email address can exist in multiple Users table rows because the person who owns that email address could have an account with multiple tenants, and potentially have a different role in each tenant (e.g., a Leader user in one tenant could be a Member user in another tenant).
My goal
I need the security filter on the Users table to load rows as follows:
- For users with any role: All the Active rows where the email address equals the USEREMAIL() of the app user
- For users with an Active row that has an Admin or Leader role for a tenant: All the tenant’s users’ rows
My ideas to try next
Is there any way to do this in a single table? Maybe by somehow maintaining (via an action?) a column that for Admin/Leader rows includes all the tenant’s User IDs?
If that doesn’t make sense, I’ll likely try maintaining a shadow table with only rows for users with advanced roles. Although I haven’t yet explored automation and action functionality, it sounds plausible to me that I could add/delete a row in an Advanced Users table everytime a user receives/loses an advanced role in the main Users table. Then, I think I should be able to reference that Advanced Users table in the main Users table’s security filter. Does this approach make sense?
Any different guidance?
More background
In case it helps illustrate, here’s the self-referential security filter expression for my Users table:
OR(USEREMAIL() = CONTEXT(OwnerEmail), AND([Email] = USEREMAIL(), [Active]), IN([Tenant ID], SELECT(Users[Tenant ID], AND([Email] = USEREMAIL(), [Active], IN([Role], LIST("Admin", "Leader"))))))
In case it’s relevant, here’s more context that I think precludes certain alternative approaches:
- I’m not limiting users to a single row in the Users table (e.g., with a column that lists multiple tenants) because I don’t want changes made by one tenant who can manage user details to affect the user’s record for another tenant.
- I assume I’ll need to make the app public for anyone to sign into rather than explicitly share the app to authorized users because I need tenants to be able to add/remove users, including assigning advanced roles to some users, rather than depend on me (the app owner) to do that. (This raises other challenges–e.g., related to billing if a non-user or inactive user signs in–that I’m working through and will likely ask about later in this forum.)
Thanks for reading through this and offering any suggestions. I’ve found lots of great guidance in this forum and hope someone has already figured out how to address this use case in their own apps.
