Need Clarity on Users and Roles

I’ve read the documentation on Users and Roles, but these seem to be related to Five users and roles, not my application’s users and roles.

My aim is to have user roles in my application, which allows them to see certain forms but not others.

For example, a registrar should be able to see and edit all groups that belong to their portfolio. Quick explanation: each group belongs to one of our 4 portfolios (A, B, C and D). A Portfolio registrar role should be able to see groups of any portfolio, but only edit groups in their own portfolio. Can a form be read-only for some data and read-write for other particular data (such as a group which is in their own portfolio)?

I also need to be able to limit certain menus to those who have the proper permissions.

It seems like once I have roles defined properly, when a user logs on they should maybe be taken to a dashboard which they can use to navigate to certain forms without needing to use the menu system.

Do you have any documentation which addresses this issue? I can’t be the only one who needs this functionality.

Thanks…

I think I’m getting the hang of this. For each data source, I have to add a permission to the role. Either read only or various levels of control, right?

This is going to be a long process, as I will need to add a bunch of data sources, both tables and queries, for every single role I define.

Am I understanding this correctly? Is there an easier way to do this, or do I just need to go through the same process for every role I create?

thanks…

Hi Ron,

That is correct, you will need to make each role and assign the permissions for each data source. Alternatively, the default permissions on the first page of the Roles form will apply to all tables or queries in your application.

So I guess it’s safer to not give default permissions to roles, but instead force all needed data sources to be explicitly setup for each role???

When I created a test user with a role, and the role had no default permissions, I got several errors each time I tried to log the user in, and had to add a new data source permission each time. While cumbersome, that may be safer than giving the role default permissions of full access on all data sources, right?

Another issue is what menus each role can see. It’s one thing to assign roles on data sources and another to limit the visible menus for each role.

If I (and ChatGPT) correctly understand your menu visibility methods, I need to add a top-level menu for each role and assign that to the role’s “Menu” property. Is this correct? If so, that means I need to duplicate a bunch of menus that are shared between roles so both roles can see them. This is incredibly cumbersome. Please verify that this is how the current menu visibility scheme works.

I’d like to propose a more software-oriented way to do this: Since I know the user’s iUserKey value, I can use this to read the iRoleKey from the user’s iUser record, then make a setting saying which menu items a given role can see, then use this in the “Show If” field of the menu item. A single lookup in the “InitialSetup” function can give me this. I can query iUser in the query design window, so I should be able to query it in the server function also, right?

Since it would be more user friendly to keep my setting for available menus by role name rather than iRoleKey, would you be willing to give me the name of the roles table and the field names (mainly just the role key and role name), and can that be queried by me?

If you won’t give me the table and field names, I would need to get the role names from the Setup Roles screen, then somehow locate their IDs, which are not shown on that screen. It would be much easier if I can query the iUser table and the roles table at user login time. Perhaps you could add the iRoleKey field to the setup roles screen? This wouldn’t be needed if you let me query the Roles table.

If you can answer the bold questions, that would be very helpful.

Thanks so much…

Hi Ron,

So I guess it’s safer to not give default permissions to roles, but instead force all needed data sources to be explicitly setup for each role?

While cumbersome, that may be safer than giving the role default permissions of full access on all data sources, right?

This is correct, as a general rule from a security point of view, this is always the preferred, even better is no access by default, and only add access that is required. Good news is you should only need to ever set this up once, and only alter when needed.

If I (and ChatGPT) correctly understand your menu visibility methods, I need to add a top-level menu for each role and assign that to the role’s “Menu” property. Is this correct?

Yes, and as your assumption in the next line, this is correct.

For functions in the back end, we have getRoleKey(name: string); which will return the key of the role passed in as the name of the role, and we also allow support for getting the current role key using five.currentRoleKey() which is available in both the backend and UI.

If you need any further help regarding the roles, let us know, and we can add additional query options for access to the role information as it is not available via a table as such.

Kind regards,

Jo

Thanks for the reply Jo.

It seems like a challenge to limit menu items that a role can see by using a master menu item for that role, because it requires you to duplicate menu items that may be shared by multiple roles.

I like the idea of using currentRoleKey to identify this rather than having to read that key from the iUser table. If I want to roll my own menu enabler based on role key it would be easier and more user friendly to use the role name instead of role key, but the role key will work for now?

I wish you would make the role key visible in the role maintenance form, so I could store that information in my settings table.

Thanks…

Ron Mittelman

I believe I’ve solved the menu visibility issue without the overhead of duplicating menu items for each role.

I put this in the menu’s Show If setting:
=(JSON.parse(five.variable.AllowedMenus || "[]").some(x => x === "all" || x === "GenerateEmails" ))
The last part needs to be changed for each menu.

I have a setting called RoleMenus, which contains the following JSON:

{
  "Help": [
    "List of roles and which menus they can access"
  ],
  "0c5f05b5-8df7-460f-b88f-fb3834e3ea6e": {
    "RoleName": "admin",
    "AllowedMenus": [
      "all"
    ]
  },
  "fa56f29e-e6c0-45de-8473-94cb32ffc5ac": {
    "RoleName": "PortfolioRegistrar",
    "AllowedMenus": [
      "GenerateEmails",
      "GenerateReports",
      "Members",
      "InterestGroups",
      "ClearStagingTablesProcess"
    ]
  }
}

Right at login time, my InitialSetup function reads the proper setting based on the new RoleID, and saves it into a variable called AllowedMenus.

The above Show If formula then prevents the menu from showing if it is not included in the list of menus defined in Settings.

This is working just fine. It would be simpler if the Show If formula could know which menu it was being used on, so I wouldn’t need to customize the formula for each menu.

Is there any way to know the menuID without hard-coding it? It would need to be known before actually clicking on the menu.

Thanks…

Hi Ron,

These links should help.

https://help.five.org/3.0/docs/api/five/functions/get-selected-menu-id

https://help.five.org/3.0/docs/api-examples/function-examples/get-selected-menu-id/

I appreciate the quick response. But getSelectedMenuID seems like you need to actually select a menu item. I’m wondering if there is a way to identify the menu ID during design of the menu item so formulas for show if can all be identical.

Thanks…

Ron Mittelman

Thanks Jo.

I’m confused that the role information is not available via a table. I’d like to see a field that I could maintain in the Roles table, controlling what menus a user can see.

While the Menu field works, some developers may not want to use that, because common menus will need to be created multiple times so different roles can see them.

My setting for available menus by role seems to work fine. It would be better to store the available list of menus in a Role field, perhaps AvailableMenus, and a way to see that in code, similar to five.currentRoleKey. This way, developers could use either method to control which menus are available to which roles.

Also under this topic, can you advise how to let users see some records but not others in a particular table? More accurately, how to make some records read-only and some full permissions, or the permissions given during role setup. For example, I have 4 portfolio registrars who are each responsible for some of the interest groups, depending on which portfolio the group belongs to (this is a field in the InterestGroups table). Portfolio registrar for “A” portfolio should have full control over the applicable tables. The other registrars should be able to see those groups but not change them.

Can you point me to documentation which shows how to do this?

Thanks…

Hi Ron,

Regarding : can you advise how to let users see some records but not others in a particular table?

Just clarifying, if a user is logged in, will this user be able to see certain records from a table, and some are hidden, and some are read only all at the same time, or are you meaning if user A logs in they see all records and can edit them, user B logs in and everything is hidden for the same table, and User C logs in and all records are read only ?

Thanks for the quick reply.

Most permissions are obtained by giving the role specific data source permissions. Also by limiting which menus can be seen.

I’m asking about further limiting by data. I’ll try to explain.

There are 80 interest groups, each assigned to a portfolio by setting their Portfolio field to point to portfolio A B C or D.

Portfolio A registrar should have complete control over her groups but read only for groups that don’t belong to her portfolio.

Would this be accomplished by using a security table? I read about that but the docs don’t really explain how to do it.

I hope I’ve explained the requirement clearly?

Thanks…

Ron Mittelman

Hi Ron,

You can try the following if this helps :

Add a security table, example :

UserPortfolio

UserPortfolioKey - primary key

UserKey - foreign key to Five’s iUser table

PortfolioKey - foreign key to Portfolio

A row in UserPortfolio means “this user has full control of this portfolio”. If there’s no row, the user has read-only access. So the Portfolio A registrar gets one row (her user and Portfolio A), and everyone with the Registrar role can still read all 80 groups.

Using a link table rather than a Portfolio field on the user record gives you some flexibility for free:

  • A registrar can cover two portfolios.
  • A deputy can be given Portfolio A while someone is on leave.
  • A portfolio can have more than one person with edit rights.

None of these need a schema change, just a row added or removed.

Then in the table events you can add something along the lines of :

count = SELECT COUNT(*) FROM UserPortfolio WHERE UserKey = currentUserKey AND PortfolioKey = portfolioToCheck

if count = 0 → return an error (“This interest group belongs to another portfolio”) otherwise → allow the save

You could also create a function to set the security level, which after they login, you can set a global value on window.security ={} which holds the values, with which you can change the behaviour in the forms to show applicable access as well (as a note, always handle the enforcement server side in the table events, as this is where the true security belongs, not in the UI)

Hi Jo,

Not sure if I quite understand your reply.

Currently there is an InterestGroups table. One of its fields is PortfolioKey, which is itself a foreign key pointing to the Portfolios table.

My intent is to limit the full control of various interest groups based on the PortfolioKey stored in the interest group record. So the portfolio registrar for portfolio A has full control over those interest groups whose PortfolioKey is A, and read-only to the other groups.

I started with a PortfolioRegistrar role, but now I’m thinking I need PortfolioARegistrar, PortfolioBRegistrar, etc. for roles to make it easier to decide which groups each can edit.

Also, rather than causing some type of error when trying to save an interest group record, I would prefer to make the form read-only with some sort of visual indicator of that, so saving is not even an option.

Sorry to be so obtuse about this. I wish you had more documentation on the subject.

thanks…