We had quite a bit of leftover rdef and ra mangling.
Be more thorough and clear it up.
While at it, make load_user_accessdata() and load_all_capabilities()
more consistent.
There are some exceptions when checking for caps that are inherited
from the default role. Move the check into has_cap_fad() and stop
mangling the data we put in $ad[rdef].
We now also set $ad[dr] to record default roles added.
This will later allow us to share rdef across many users in $ACCESS.
Affects:
load_user_accessdata()
has_cap_fad()
While at it, document has_cap_fad() a bit.
When setting things up for the guest user, the RA entry in accessdata
was not multi-enrol-friendly. Must have glossed it over in the
multi-enrol rework.
The name for new data structure holding access control data
is "accessdata". And we have a new moniker "fad", short for
"from accessdata".
So
- has_cap_fromsess() -> has_cap_fad()
- access_inaccessdata() -> path_inaccessdata()
- aggr_roles_fromsess() -> aggr_roles_fad()
- $sess -> $ad
- $access -> $ad
Consistency, save typing, shorter codelines...
move_courses() now calls content_moved() which will take care of any
accesslib-required changes. And introducing move_category() which
also calls content_moved() when needed.
With the new accesslib, moving courses and categories has a major
impact on enrolments and unenrolments.
At _least_ we need to signal accesslib that it has happened. So here
is context_moved() for exactly that.
Open to refactoring later into something along the lines of
- move_course()
- move_category()
However, at this stage the most important of those two: move_course()
does not fit very well with the code in course/edit. So keep it simple
for now.
Combined with the path creation in create_context() we can now create
a course, enter and edit it immediately. Amazing.
Like - 21st century technology.
... and it populates the context cache too.
Unfortunately, it needs an INSERT followed by an UPDATE. Other than
a stored procedure, I don't know how to deal with this better.
(We could save the SELECT though! that's a thought...)
OTOH, we are getting so much mileage out of the path field
that it's probably a hit we have to take in the chin and move on.
Callers _must_ do their homework before calling create_context().
This allows us to save 2/3 queries per call (!!!).
As it stands, callers are all in accesslib anyway.
Manually enrolling and unenrolling self, and other users should
transparently set the context dirty. So walk all callers to
role_assign() and role_unassign() and mark the context dirty
where appropriate.
OTOH, most automated-backend enrol/unenrol mechanisms should not.
The backend lookups that happen when you login are well covered
by the login/enrolment process, and don't need to be marked dirty.
If accessinfo is stale, we need to reload it without losing
out "interesting" state -- transparently for the end user.
That means preserving active role switches, loginas (site and course
level), etc. The logic for that is encapsulated in
reload_all_capabilities().
Also affected:
- has_capability() which now calls reload_all_capabilities()
- role_switch() - minor tidyup
The refactor that created make_context_subobj() triggered a bug.
Smack in the hand to the sloppy programmer using variables outside
of the context they were meant to be used in!
And will force a reload of $USER->access for logged-in users that need
to read _this_ context. Much lower impact - still not a great idea to
edit assignments/caps on very busy courses, but impact should be low.
And will force a reload of $USER->access for all logged-in users
on their next request.
We will have to tell admins of large sites to avoid making role changes
at busy times, as it does generate extra load.
has_capability() now (ab)uses a new global: DIRTYCONTEXTS where we
load the contexts that have changed since since $USER->access[time]
The shallow/easy checks are done in has_capability(), deeper checks
go into the newfangled is_contextpath_clean().
The only complication now is to reload the relevant caps without losing
switches, loginas, etc...
The accessinfo held in $USER->access can easily get out of
sync with reality if and admin has removed our access,
or expanded it after we loaded our accessinfo.
To handle this, we'll use the config_plugins table with an
'accesslib/dirtycontexts' plugin signature to store the paths of
recently changed contexts. To handle those dirrrty entries, here
we introduce
get_dirty_contexts() - for lib/setup
mark_context_dirty()
cleanup_dirty_contexts() - for cron
Now get_role_users() joins with contexts and roles too, so we can
push more work into it, and simplify the callers.
One important change is that the $view flag gets reworked into
$gethidden, pushing the cap check to the caller.
This commit is followed by a cleanup of the callers...
This patch saves 1600 context lookups on a 1600 course category. rcache
does help a bit with small categories, but on large setups, this is
not sustainable.
And it's not needed either. We have the data right at our fingertips.
Just get it when it's cheap...
Introducing get_context_users_bycap() which gets the data in
2 DB queries, takes around 10ms on my laptop, and returns
the records with a nice context property attached.
Note Note Note: right now, some user recs do not have a context
associated, so are _not_ returned. So this awaits Matt's fix
to contexts maintenance to be 100% accurate...
A walkthrough of course-login-as functionality shows that is
Just Works, except that get_my_courses() was showing all the
courses. So we fix it.
And cleanup load_all_capabilities() - things just work
transparently.
This is *the* scary commit. No more scaffolding, no more
training wheels. Remove the legacy has_capabilty_old() and
several supporting functions.
has_capability_old()
capability_search()
is_parent_context()
roles_context_cmp()
load_user_capability()
capability_prohibits()
I've grepped far and wide. Noone else uses the supporting
functions anywhere in-the-known-universe. If I could not
find it, it does not exist.
[Thankful that cvs/git/whatever will hold on to them
if I end up having to regret this.]
This patch introduces a new global $ACCESS that will cache
accessdata (our ra/rdef array) for users that are _not_ the
logged in user.
Most of the time it will be empty (luckily).
Each new user we have to get "in" costs us 3 or 4 cheap
dbqueries at the moment, so it is not that bad.
has_capability() now calls load_user_accessdata() if the
call is for a non-logged-user. So $ACCESS is autopopulated
transparently.
This also means that has_capability no longer calls
has_capability_old(). Yay!
With this patch, user/view.php for looking at a user in a course...
Before: 62 dbqueries, 10.3MB, 0.7s
After: 49 dbqueries, 8.5MB, 0.3s
Implemented all the relevant checks for role_switch().
accesslib's role_switch() doesn't do any UI-related checks any more,
being a backend lib call. These belong here.