Course ID 2

advertisement
Moodle Capabilities, Roles & Permissions – Moodle 2.3.3
Moodle capabilities can be quite complicated to properly get your head around until you go
quite deep into code and follow it to see where it all goes and where it all comes from.
Here is an attempt at explaining it, as far as I have worked out.
Before we look at the roles and capabilities themselves, first we should understand Moodle
contexts and how they are structured.
Here is an example context from my Moodle database (mdl_context):
contextlevel
This defines what kind of context it is, based on the value.
These values are set in the accesslib.php file within Moodle.
10 = System
30 = User
40 = Course Category
50 = Course
70 = Module
80 = Block
So if the level is 50 we know the record is the context of a course.
If it’s 30 we know the record is the context of a user.
And so on.
instanceid
This points to a record in another table, dependant on what level the context has.
For instance, if it’s a course context, the instanceid is a course id from mdl_course.
If it’s a user context, instanceid is a user id from mdl_user.
And so on.
So in this example, this context record is a course context pointing to course id (2).
path
The context paths are very important in working out whether a user has a certain capability
or not. They are structured as a string with forward slashes separating each context id.
From left to right, it goes from parent to children contexts.
So using the example record from earlier, our path is 1/3/19
The last element in that path is 19, which is the id of the record itself (that is always the
case).
From what we did earlier we know that context id 19 is a course context pointing to course
id (2).
Next we move one step up to its first parent, which is context id 3:
As we can see from the database that context is level 40 which is a course category of id (1).
So that makes sense, we have a course (id 2) within a course category (id 1).
And then the last step up the parenting ladder is to context id 1. Context id 1 will always be
the first element in the path (the highest parent) as context id 1 refers to the SYSTEM:
So if we break that down into a tree we can see that it makes total sense really:
System (/1)
Course Category (/1/3)
Course (/1/3/19)
So the context we are looking at is a course, within a course category, within the whole
system.
Makes sense so far.
The context record also has a depth field which just specifies how many layers of contexts
there are in the path. So ours has 3.
So now we know what the contexts actually are and how they are structured it’s time to look
at how they are used to specify what capabilities a user has.
When you are logged into Moodle, there will be a property on your $USER object called
“access” which stores various pieces of information in an array. The two bits of information
we are interested in are the elements “ra” and “rdef”.
If you print out the access property doing something like:
print_object($USER->access);
You should be able to see all this information for the currently logged in user.
$USER->access[‘ra’]:
The “ra” element holds an array of all the context paths the user is assigned to (ra = “role
assignments”).
This might look something like this:
Each context path holds the role ids that the user has linked to that particular context. Role
ids can be looked up in the mdl_role table. For example, these are mine:
So let’s look at that example we have in the [‘ra’] element.
Our logged in user has a role on 4 contexts within Moodle:
/1 – System. Here we have role id 7, which means that our user is an AUTHENICATED USER
in the context of the SYSTEM
/1/2 – This context refers to the front page course and our user has roles 8 & 9. So that
means that she is an AUTHENTICATED USER ON FRONTPAGE and a FRONT PAGE TEACHER in
the context of the front page course (same as any course really).
/1/3/19 – This context refers to a course with id 2 (as used in an example earlier). With role
id 4 which is non-editing teacher. This means our user is a NON-EDITING TEACHER in the
context of COURSE ID 2
/1/45 – This is a user context (lvl 30) which refers to a user with the id of 14 (instanceid). It
has the role id of 10, which is one of my custom roles “Personal Tutor”. This means that our
user is a PERSONAL TUTOR in the context of USER id 14, who happens to be called George
Reynolds.
/1/52 – This is the same as above but for a different student.
So that all makes logical sense, the user is a <<ROLE>> in the context of <<context>>.
So that information is all loaded up when the user logs in (if they are assigned to a new role
they might need to logout/login for it to appear).
Next we’ll have a brief look at the [‘rdef’] element, which will be much larger and look
something like:
Etc….
Each element within the [‘rdef’] array is defined with the system context (/1) and a role id
(e.g. in that picture “9”) in the format of: [CONTEXT:ROLE]. Each of those then contains an
array of capabilities that role has.
I’ll explain that a bit more later once we get there.
So let’s say I have something in Moodle that generates a report about a student and I only
want certain people to be able to see that report (certainly not the student!).
Let’s call the capability “view_report” and we’ll say it’s in a block called “test” for example’s
sake.
In our example system there are only two types of people we want to be able to see this
report:
- Teachers who are teaching on the student’s course
- The student’s personal tutor
And again as an example let’s say the course the student is on is ID # 2, since we used that
earlier and it’s easier to reuse the same example. Let’s also say our user is user id # 21.
So, if the user is a teacher (non-editing for this example) on course # 2 – YES
If the user is a personal tutor of user id #21 – YES
Otherwise – NO
At the moment I have not given any roles the ALLOW value for this capability, so everyone
has it set to either “Not Set” or “Prevent”, so nobody will pass the test for has_capability on
it.
So firstly I’ll go into Moodle Site Administration -> Users -> Permissions -> Define Roles and
I’ll set that non-editing teachers have the value of ALLOW for capability “view_report”. This
in itself is meaningless, what is really relevant is the context which is passed into the
has_capability function.
Since we are testing is the user is a non-editing teacher on course id #2, the context we want
to use is:
get_context_instance(CONTEXT_COURSE, 2)
Which when printed out looks like this:
So this is just a record from mdl_context really with the same values as we’d find in there.
So let’s pass that into our has_capability function and then follow the process it goes
through:
If (has_capability('block/test:view_report', get_context_instance(CONTEXT_COURSE, 2))){
// Do something…
}
The first thing that happens is that the path of the context we passed in is converted to an
array of all its parent/child elements.
So we passed in a context with the path “/1/3/19”, which is converted to the array:
$paths = array(
“/1/3/19”, “/1/3”, “/1”
);
Next an array of all your roles within any of these contexts is built up.
So we loop through that array of context paths and see if there is a record within our [‘ra’]
element of the $USER->access array.
So first one, is there an element [‘ra’][‘/1/3/19’]? Yes there is an in there we have the role id
of 4, so that role id is added to our new $roles array with the value of null (I’ll explain why
null in a bit).
Next one, is there a [‘ra’][‘1/3’]? No, so move on.
Is there a [‘ra’][‘/1’]? Yes, with the role id of 7, so that’s added to our $roles array.
Now we have an array called $roles which looks like this:
$roles = array(
4 => null,
7 => null
);
What does that mean? That means that in the given context (the course we passed in) and
all its parent contexts (category and then system) we have the following valid roles assigned
to us:
4 – Non-Editing teacher
7 – Authenticated User
If at this point we have passed in the context of a course we were NOT assigned to our
$roles array would only have the value 7. We have the value 4 here because we ARE a nonediting teacher on that specific course.
So now we have an array of all the roles we have within the given context, we can see if any
of those roles has the capability we are looking for.
To do that it loops through the $paths array again and for each element in there, it then
loops round the $roles array as well. What it’s doing is looking in [‘rdef’] for an element with
the name [PATH:ROLE].
So for example let’s loop through everything like the code does:
Looping $paths
- /1/3/19
- Looping $roles
o 4


o 7


- /1/3
- Looping $roles
o 4


o 7


- /1
- Looping $roles
o 4





o
Is there an element [‘rdef’][‘/1/3/19:4’]?
No, move on
Is there an element [‘rdef’][‘/1/3/19:7’]?
No, move on
Is there an element [‘rdef’][‘/1/3:4’]?
No, move on
Is there an element [‘rdef’][‘/1/3:7’]?
No, move on
Is there an element [‘rdef’][‘/1:4’]?
Yes there is.
Does it have its own array element with the name of the
capability in it? [‘rdef’][‘/1:4’][‘block/test:view_report’]?
Yes it does
What value is it?
 1 = ALLOW
 -1 = PREVENT
 -1000 = PROHIBIT
7


Is there an element [‘rdef’][‘/1:7’]?
No, move on
So now we’ve finished looping everything we found one value in our [‘rdef’] and that was
with the value 1. It was in the path and role: /1:4, which is system with role id 4 (non-editing
teacher).
Where it can be confusing is that when you make the has_capability call it seems like you are
saying:
“Does this user has the capability <<x>> on the course <<y>>”
This isn’t the case. Essentially it’s doing 2 different things, firstly its saying:
“For this given context (course) is the user assigned to it in any roles?”
-
Our answer here was yes: role 4 and role 7
“Do any of these roles have capability <<x>>?”
-
Our answer was yes – non-editing teacher has it
When you set a capability to a role, you are setting it at system level, not to a specific course
or a specific user (usually), so the has_capability check is checking if you have a role in that
context (any role will do) and then if any of those roles have that capability.
So for example, let’s say the following is true:
-
Logged in user is a non-editing teacher on course id 2
Logged in user is not assigned to course id 3 at all
Logged in user is a student on course id 6
We then do test runs of has_capability using those course ids along with CONTEXT_COURSE
to see if the user has that capability in the context of those 3 courses.
Course ID 2
The first check will return that the user has the roles 4 & 7 in this context (note: not “on this
course”, but “in this context”).
Then it checks if any of those roles have the capability, which returns true as role id 4 (nonediting teacher) does.
Course ID 3
Returns only role id 7 (authenticated user in system context) and so the check for the
capability on that role returns false.
Course ID 6
Returns roles 5 (student) and 7. It checks those roles for the capability and returns false
because they don’t have it.
It works exactly the same for other contexts, for example if we only wanted Personal Tutors
to have that capability, we would pass in the context of the student. The first part would
check to see if the user has any valid roles assigned to that student, and if so, it then checks
to see if they of those roles have that capability in the system.
Download