MDL-13000 Adding support for developers to add their own capabilities to local/db/access.php
This relies on a local/ language pack as well for the capability names.
Notes on implementation are in lib/locallib.php
With some subselect-outer-join poison-pill magic, when the we don't
want doanything users, we remove the roles that would grant such
dubious status.
Just a flick of the SQL muscle, actually.
This will help us bridge the gap from olden-style order-by
user_teachers.id. From the phpdoc...
Will re-sort a $users results array (from get_users_by_capability(), usually)
based on a sorting policy. This is to support the odd practice of
sorting teachers by 'authority', where authority was "lowest id of the role
assignment".
Will execute 1 database query. Only suitable for small numbers of users, as it
uses an u.id IN() clause.
Notes about the sorting criteria.
As a default, we cannot rely on role.sortorder because then
admins/coursecreators will always win. That is why the sane
rule "is locality matters most", with sortorder as 2nd
consideration.
If you want role.sortorder, use the 'sortorder' policy, and
name explicitly what roles you want to cover. It's probably
a good idea to see what roles have the capabilities you want
(array_diff() them against roiles that have 'can-do-anything'
to weed out admin-ish roles. Or fetch a list of roles from
variables like $CFG->coursemanagers .
MDL-12452
This fixes the handling of default roles as "tie breakers" for lower
RAs in conflict, and simplifies the code a lot.
The main loop in get_user_by_capability() runs a simpler state machine
that just collects role assignments (roleid and depth), and handles
pagination.
The complex part of the state machine has moved to
has_capability_from_rarc() which will walk the data structures
collected by get_user_by_capability() for each user.
Having all the complex state handling of $hascap there makes things a
lot easier for pagination and general sanity of
get_user_by_capability().
MDL-12452
we don't deal with RAs in the main SELECT -- we deal with _capabilities_
which is an entirely different matter ;-) -- so push the ra.hidden check
into the subselect.
Also, remove ra.hidden from the default list of fields. Hopefully no
callers are using ra.hidden -- if they are, they should be calling
something else, as this function deals with capabilities. So we might
need an audit of callers, to check that noone is expecting ra.hidden
to be there.
MDL-12452
With this commit, we can handle the complex cases with
- correct pagination, but not very efficient over large datasets
- mostly-correct application of the override rules
The structure of the code is fairly complex in that we want to do
it without holding all the recs in memory, so we use a small state
machine. We have to handle the complex override rules over 1 or 2
permissions (when $doanything is set) so it all ends up quite complex.
There is one known issue with this code, in cases where the default
role ends up as the decider between 2 conflicting RAs, we fail to
apply it. This will need a bit of reorg of how the loop works.
MDL-12452
The "simple" case SQL did not handle multiple enrolments for the same
user correctly -- it would generate multiple rows for those users,
incorrectly.
With this patch we move the join to RA to a subselect where DISTINCT
takes care of things.
MDL-12452
With this patch, get_user_by_capability() can handle the cases where
users have multiple role assignments to the same course, and PREVENTs
and PROHIBITs affect the rolecaps of this course.
Without stored procedures we cannot resolve this entirely on the
server side - so in the complex cases we do as much as we can on SQL,
and post-process the data on the PHP side, including SQL-style
pagination.
MDL-12452
This patch reorganises the conditions and field handling so
we can spot if this is a call we can resolve in a single SQL
query that we just pass back the results.
If there are any PREVENTs or PROHIBITs, we need to delve into
more involved stuff...
MDL-12452
cleanup_contexts() was not working on Oracle - mostly due to 2 SQL
syntax problems. So probably marginally working elsewhere.
- We should not use AS when naming table/subselect aliases - only
when referring to column aliases in the resultset
- level is a reserved word - oops! - so back to contextlevel
With this patch, we respect rdef locality when two roles
assignments in the same context have conflicting rdefs.
In that case, the most local rdef wins.
So RA locality still matters most. If you are a teacher
sitewide and a student in course X, student role trumps
teacher.
For a use case, see the discussion here
http://moodle.org/mod/forum/discuss.php?d=84472
Notes:
- If we wanted to have locality of RDEF trump everything
we can. A comment in this patch shows how.
- I don't know how to reproduce this in pure SQL.
And Also:
This patch also fixes a bug where if CAP_PROHIBIT was set
_and_ another role added to it in the same context, we would
add or substract 1 to CAP_PROHIBIT, and it would lose its magic.
And while at it, tighten the code to avoid casts. All the
ints are unambiguously ints.
... where it belongs ;-)
load_all_capabiloties() gets called at several points where we don't
want to be re-querying the enrolment backends. It needs to be called
before load_all_capabilities() and only by callers that are setting up
a logon session.
Those callers need to be calling complete_user_login() anyway, as they
need to set the Moodle cookie, log the logon action, etc. In fact,
those callers duplicate a lot of that code already.
The callers that don't duplicate code for the login are actually the
cases where the backend enrolment plugins should not be queried.
To be followed by callers cleanup...
* user_lastaccess deleted when deleting course
* rewritten deleting of contexts - does not use get_context_instance() anymore because it is much more strict now
* added deleting of grade_letters and settings when deleting course
* improved handling of dirty contexts in general - caching, switching in cron, marking, loading, etc.
* role_assing() and role_unassign() now marks dirty contexts because we use has_capability() in this function - we can not do it later outside to speedup bulk operations
* fixed some inline docs
* fixed notice from rs closing
* removed cached $CONTEXT from has_capability() - $context is now required parameter; this was hiding serious bugs when context did not exist or ppl passed false as parameter
* removed some ===, we can not use these on function parameters - we must support ints, strings, '', nulls, etc. - this could be a source of really dangerous bugs in future
* some other improvements and fixes - documented inline