Forum Discussion

elbranscomb's avatar
elbranscomb
Executive
2 years ago

Multiple roles in a custom component using userHasrole

We have a custom component that checks for the user's assigned role before allowing them to see the feature. Currently it is set to check if the user has the 'Administrator' Role. 

We would like to have it make this feature available to anyone who has either 'Administrator' or 'Moderator' role.

Is it possible to specify 2 roles in the following code or is this achieved in a different way?

<#if user.registered && commonFuncs.userHasRole(user.id,'Administrator')>
<#assign messageId = env.context.message.uniqueId />
<#assign threadId = page.context.thread.topicMessage.uniqueId />

<#assign showOption = true />

 

 

  • It depends on your function, but I'm betting you can't just add more to the same call. Just call it twice, like this. I've added an initialization to set that variable to false, if you're not doing it elsewhere.

    <#assign showOption = false />
    <#if user.registered>
     <#if commonFuncs.userHasRole(user.id,'Administrator') || commonFuncs.userHasRole(user.id,'Moderator')>
     <#assign messageId = env.context.message.uniqueId />
     <#assign threadId = page.context.thread.topicMessage.uniqueId />
     <#assign showOption = true />
     </#if>
    </#if>

     

    Here's another option, done in the component (sans-function) and used to display content differently based on roles. Just get all of the user's roles and then check them. Computationally, this is probably slightly less expensive, but I'm not sure.

    <#-- if the user is anonymous -->
    <#assign hasCategoryAccess = false />
    <#assign isABCXYZuser = false />
    <#if !user.anonymous>
      <#-- REST call to get the user's roles -->
      <#list restadmin("/users/id/${user.id?c}/roles").roles.role as role>
          <#-- If user is assigned these roles or is an employee -->
          <#if role.name?? && (role.name == "CategoryABC-Mod") || (role.name == "CategoryABC-User") || (role.name == "Employee")>
              <#assign hasCategoryAccess = true />
          <#-- If not employee, check if role is ABCXYZ -->
          <#elseif role.name?? && (role.name == "ABCXYZ")>
              <#assign isABCXYZuser = true />
          </#if>
      </#list>
    </#if>

     Based on the True/False results, the component displays the intended info.

4 Replies

  • It depends on your function, but I'm betting you can't just add more to the same call. Just call it twice, like this. I've added an initialization to set that variable to false, if you're not doing it elsewhere.

    <#assign showOption = false />
    <#if user.registered>
     <#if commonFuncs.userHasRole(user.id,'Administrator') || commonFuncs.userHasRole(user.id,'Moderator')>
     <#assign messageId = env.context.message.uniqueId />
     <#assign threadId = page.context.thread.topicMessage.uniqueId />
     <#assign showOption = true />
     </#if>
    </#if>

     

    Here's another option, done in the component (sans-function) and used to display content differently based on roles. Just get all of the user's roles and then check them. Computationally, this is probably slightly less expensive, but I'm not sure.

    <#-- if the user is anonymous -->
    <#assign hasCategoryAccess = false />
    <#assign isABCXYZuser = false />
    <#if !user.anonymous>
      <#-- REST call to get the user's roles -->
      <#list restadmin("/users/id/${user.id?c}/roles").roles.role as role>
          <#-- If user is assigned these roles or is an employee -->
          <#if role.name?? && (role.name == "CategoryABC-Mod") || (role.name == "CategoryABC-User") || (role.name == "Employee")>
              <#assign hasCategoryAccess = true />
          <#-- If not employee, check if role is ABCXYZ -->
          <#elseif role.name?? && (role.name == "ABCXYZ")>
              <#assign isABCXYZuser = true />
          </#if>
      </#list>
    </#if>

     Based on the True/False results, the component displays the intended info.

  • Thanks Drew_C that first option totally fixed it and now both roles can see the dropdown option. 

  • Here's a more efficient way of checking if a user has at least one of the specified roles (had to rewrite it a bit as the one i use depends on other functions, so this is untested, but should make the idea clear):

     

     

    <#function hasRoles roles = '' id = ''>
    
    	<#local hasroles = false />
    
    	<#if ( roles?has_content && id?has_content )>
    		<#-- API v2 is much more efficient checking for roles than v1 -->
    		<#local query = "SELECT id FROM users WHERE roles.name IN ('" + roles?replace("\\s*,\\s*", "','", 'rmi') + "') AND id = '${id}'" />
    		<#-- alternatively use count(*), although official best practises recommend against it, real performance results lack evidence though -->
    		<#-- <#local query = "SELECT count(*) FROM users WHERE roles.name IN ('" + roles?replace("\\s*,\\s*", "','", 'rmi') + "') AND id = '${id}'" /> -->
    
    		<#local response = restBuilder().admin(true).liql(query) />
    		<#if (response.status == 'success') && (response.data.size > 0)>
    		<#-- alternatively with count(*) -->
    		<#-- <#if (response.status == 'success') && (response.data.count > 0)> -->
    			<#local hasroles = true />
    		<#else>
    			<#local hasroles = false />
    		</#if>
    	</#if>
    
    	<#return hasroles>
    </#function>
    
    <#-- test it with messy whitespace -->
    ${hasRoles('Administrator, Moderator ,  Somethingelse,Whatever', '203')?c}

     

     

    Note that this function just checks if a user has one of the specified (comma separated) roles, not if he/she has all of them, that could of course be added. Also, it does not return the user's roles (names), just a boolean, but code is here to be modified if that is what you need ;).