cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
jcole3
Community Contributor

Hiding links based on role using CSS?

Can anyone help me figure out how I could hide a link (native to Canvas) based on a user role & sub-account using CSS? I am specifically trying to limit access to the Import Course Content into this Course link.

We have an instructional site located in another state with a few rogue instructors that continually destroy their courses, despite my best efforts to prevent it from happening. 

Tags (1)
13 Replies
MattHanes
Community Champion

You can try adding something like this to your custom Javascript file:

if (ENV.current_user_roles.indexOf("teacher") >= 1){

$(document).ready(function(){
$( "a.btn.button-sidebar-wide.import_content" ).remove();
});
}

That's kind of off the top of my head and I didn't test anything other than the actual remove command in my Chrome console. Someone else might chime in with a more elegant solution. 

An alternative option is to create sandbox courses for instructors to play around with for imports so they don't mess up the real courses. 

cesbrandt
Community Champion

 @MattHanes , You'll want to add a check that they don't have the admin or root_admin roles, too. Just checking for teacher will remove the button for everyone. We do this same thing for several buttons throughout the course to prevent avoidable damage to the course functionality.

Here's the snippet we are using which removes the Conclude this Course, Permanently Delete this Course, Copy this CourseImport Content into this CourseExport Course Content, and Reset Course Content buttons:

$(function() {
     var roles = ENV.current_user_roles;
     if(!roles.includes('root_admin') && !roles.includes('admin') && window.location.href.match(/\/courses\/\d+\/settings$/g)) {
          $('#right-side a').each(function() {
               if($(this).text().match(/(Import Content into this|Conclude this|Permanently Delete this|Copy this) Course|(Expor|Rese)t Course Content/)) {
                    $(this).remove();
               }
          });
     }
});‍‍‍‍‍‍

With this setup, the script to remove the buttons will only run on the Course Settings page and you can adjust what buttons to remove by editing the regex on line 5.

 @c1224994 ‌, Matt is correct that you would need to use JavaScript to make this work. CSS is not currently capable of identifying the information needed to make this work.

MattHanes
Community Champion

Thanks for the tip! Yours looks a lot better.

cesbrandt
Community Champion

I just got tired of seeing errors in my console while I'm working. ^^'

What if you have users that have Account Roles, but aren't full system admins? We have a "Program Chairs" account role, with limited permissions, so our Program Chairs can do things like associate Blueprint sections to regular sections. However, it's giving them way too many other permissions, so we want to use your code above. I can't figure out how to make it only block certain "admins" and not all of them. Tried by role id and proper name...still doesn't work. Any ideas?

0 Kudos
cesbrandt
Community Champion

It's not easily doable.

I did some extensive concept development and research trying to make exactly that happen, but the only solution I could come up with requires use of a third-party system that queries the API. Why a third-party system? Because querying the information produces highly variant results dependent upon the users permissions. To ensure the validation always works, you need to use an account with full permissions, and it's a massive security issue to do that via JavaScript.

The concept to this setup is that you use JavaScript to query the roles of a user from the third-party system. The third-party system then queries the Canvas API to retrieve the role data for the user and returns it to the JavaScript.

I had put forward an idea to expand the ENV.current_user_roles to actually list the roles assigned, but there wasn't enough interest.

0 Kudos

That's a bummer. If Canvas only had more granular permissions, I could just set things the way I wanted in settings and be done with it, without all these goofy workarounds... 😕

0 Kudos
cesbrandt
Community Champion

Expanding permission granularity is a work in progress: https://community.canvaslms.com/docs/DOC-6253

0 Kudos

There is an "idea" that's been out there since 2015 with almost 500 up-votes. Kinda seems like if they haven't addressed it at this point, they probably just won't at all. It's kind of disappointing that of all things, security has taken a back seat.

https://community.canvaslms.com/ideas/1527-more-granular-permissions-for-admins

0 Kudos
cesbrandt
Community Champion

It is being worked on. Take a look at the priority: https://community.canvaslms.com/community/ideas/priority-granular-permissions

I ended up changing it up a bit. Works fine for our needs, just means that if we hire someone else who needs access to some of these processes I'll have to edit the code to allow them in.

$(function() {
var userid = ENV.current_user_id;
if((userid != '1') && (userid != '2') && (userid != '191') && (userid != '57') && (userid != '4') && window.location.href.match(/\/courses\/\d+\/settings$/g)) {
$('#right-side a').each(function() {
if($(this).text().match(/(Conclude this|Permanently Delete this|Copy this|Delete this) Course|Reset Course Content/)) {
$(this).remove();
}
});
document.getElementById("course_course_code").style.display = "none";
document.getElementById("course_visibility").style.display = "none";
document.getElementById("course_account_id").style.display = "none";
document.getElementById("blueprint_menu").style.display = "none";
}
});
James
Community Champion

 @mgudites 

You can make lines 2 and 3 a little more extendable by using an array and indexOf.

Your string of user != a number can be written as

['1','2','4','57','191'].indexOf(ENV.current_user_id) === -1

It will return false when it is found in the list and true if it's not found in the list.

The other way you could go is to use parseInt() and convert the userId to an integer. Then you won't have to quote each one.

[1,2,4,57,191].indexOf(parseInt(ENV.current_user_id)) === -1
jcole3
Community Contributor

Thanks so much! This is exactly what I needed.