Dan Poltawski said:
> Previously users with different permissions could have granular
> access to the admin menu for the items they have access to, so
> limiting to only users with moodle/site:config would break that.
> Although I agree that that menu is slowww to render and needs
> fixing. Perhaps permissions for the various elements could be
> gathered and checked first
This commit addresses the problem checking for all the caps that are
mentioned by code in /admin (according to grep, at least). Some light
testing with the "moodle/user:create" seems to work properly.
This burdens us with maintaining the list in has_admin_caps() -- less
than ideal, but easier than rewriting /admin.
is_siteadmin checks a few key capabilities to suss out if the user is
an admin. The main virtue of the function is that it does not use
the accesslib infrastructure -- it reads directly from the DB, which
is useful for the 1.9 accesslib upgrade.
If we are passed an empty string for $order, still create valid
SQL. Some callers in 1.9 seem to not care about order, passing
an explicit ''. Shocking! ;-)
These references to the deprecated functions were erroring out. Remove
them.
Note however that other role related cleanups done as part of
MDL-10679 "improvement to context_rel table and load_user_capability()"
are kept.
The accesslib cleanups aren't needed every 5. Also, add
build_context_path() and instructions on how to run it
as build_context_path(true) to force a path rebuild.
We now populate the context.path only where it's empty,
this means that we take 0.15s instead of 0.6s. More importantly,
we avoid thrashing the DB's indexes pointlessly.
We also support Oracle and its dirty hack here.
And the function now has a $force parameter that can be used to
actually overwrite the paths/depths in case they've been corrupted.
There is something _weird_ about the table setup on this page
and I cannot figure it out. This change "fixes" it in that
FF stops complaining.
However, the fix looks very broken to me.
get_assignable_roles() was calling user_can_assign() (cost of 1~2 DBq)
once-per-role. Instead, we can do a single DB query that answers
all our questions in one go.
On a Moodle w 8 roles defined, saves 19 DB queries for the course page
for teachers/admins.
NOTE NOTE NOTE! With this patch we drop the insane strip/escape bit.
Only the caller knows if this is for display on html or for other uses,
so we'll be true and not mangle the data.
A review of all callers in 1.8 shows no problem - the strings were being
strip/escaped already.
- The code uses the system context a lot. Declare
$sysctx at the top and use it.
- If the category has a context property, use it
(saves 1 DB query per category displayed)
The DB costs of this page in editing mode are
- ~100 DB queries for fix_course_sortorder()
- ~50 DB queries for the categories listing
If we rewrite both to lose the recursion, we could resolve the
page in perhaps 5 DBq.
With this patch, get_categories() now adds a nice context
sub-object to the returned object, which means callers can
save DB traffic.
It now also supports "deep" retrievals, which means we can
rewrite the course categories display pages to avoid
costly recursion.
Don't update fields unnecessarily. Cuts 3 DB queries per category
on course/index page (45 in a 15 category setup).
fix_course_sortorder() should be fixed to avoid recursion.
print_course() can now recognise a $course object that already has a
$course->context obj and a $course->managers array, which means that
there will be no DB access triggered by print_course().
(Backwards compat is retained so it still works the old way for
callers that get a single course printed anyway (during enrolment
for example.)
And print_courses() now uses get_courses_wmanagers(), and passes the
returned $course objects to print_course().
With this patch, a homepage listing 9 courses (with varying numbers of
teachers) sheds 63 DB queries (88 to 25). A course listing page with
3 courses sheds 9 (33 to 24).
On a single server overall time spent serving the homepage is reduced just
a little bit (262ms to 238ms) -- on a clustered environment, less DB queries
mean much lower latency and DB costs.
For an efficient print_courses() we need to grab in a constant number
of queries...
- course data
- "course manager" role assignments
- user records for the coursemanagers' fullname()
So here we do it in 2 DB queries. The 2nd one (grabbing RAs and user
records) can be expensive if we are dealing with a large number of
courses.
Which we shouldn't - When the number of courses is large the course
listing doesn't come this way anyway...
When querying capabilities of non-logged-in users, has_capability()
will now load accessdata for the subcontexts as needed.
Without this patch, below-the-course RAs and rdefs were ignored when
checking caps for a user different from $USER. I don't think it is
ever done in current moodle code, so the problem wasn't visible.
In any case - it's fixed ;-)
A bit of rework around require_login()
- Fixed a subtle bug in the check whether a user can see sitecourse
hidden activities
- Save 1 DBq and 2 includes per call by only calling
get_auth_plugin() only when needed.
- Grab the contexts we are interested in only once and keep them in
variables.
Both of them are dead code in 18_STABLE and HEAD. And if
role_add_lastaccess_entries() is ever used on a large site it will
hammer the DB to bits.
Remove before anyone is foolish enough to try it.
We had a 1s race condition where a user could get their rights loaded
at the exact time an admin is changing roles/caps and see the "old"
data. Or even see a half-updated view of the access controls.
Yuck.
So we fix the race condition backdating the dirtyness. Cheap, but
effective. And then we backdate it some more to cover for minor clock
flutter on clusters (you still need ntp however!).
Saves >10DBq and 18 includes at the homepage for all nonadmin users.
For non admin users, this makes the homepage _much_ more lightweight.
Before: inc 101 DBq 51 time 1.2s
After: inc 76 DBq 36 time 0.2s
So this commit shaves 1 full second for the non-logged-in homepage.
Still pretty bad on the includes, but shaved a good 25 files and 15 DBqs.
If cron hasn't run for a few days, it would take
several runs for chat_update_chat_times() to get things back on track.
Now it's all fixed in one go, saving a bit of DB traffic. It all adds
up...
Delete stale msgs in one DB query rather than in 1-per-chat-instance.
(From 600 DB queries to 1 on a site with 600 chat instances.)
Also - a walkthrough of chat_update_chat_times(), which seems buggy.
has_capability() can handle the fake user that forum cron sets up
and will load the appropriate accessdata into $USER->access.
This makes forum cron work again. A test comparison between before
this patchseries yields:
With 1 forum post, sent total 24 times
- Before 11 000 DB queries (approx)
- After 506 DB queries
With 6 forum posts, sent a total of 452 times
- Before 47 876 DB queries
- After 8 256 DB queries
There is a very high variability, but we are going from 100-500
queries per sent email to 18-21 queries per sent email. The
variability probably stems from 2 of the 6 posts being in a 200-user
forum.
Still huge - by the time we are sending the email, we should know
everything we need to know about the user, the forum/thread/post and
the form. The average should be well below 1 DB query per email sent!
print_user_picture() was forcing an unneeded dbquery
if you need an imagealt. And who doesn't need one these days.
So - teach print_user_picture() to take either $userid
_or_ $userobj as the first parameter. If that first
parameter has the fields we need, never touch the db.
In other words, only touch the DB as a last resort.
There is a bit of ugliness in testing whether we have
the fields or not, because these fields are inconsistently
with/without NOT NULL in the DB definitions. So we cannot
use isset() because it barfs on nulls. And we cannot use empty()
because it will match both on "missing key" and ''.
And while at it, silence warnings that we are missing string
for the year(s). Also fixes a missing string bug in really boring
courses that noone's visitied in many years ;-)
Reworked the logic of the visibility checks so that we evaluate in a
chain:
- can view course (visible or user can see hidden)
- can view category (visible or user can see hidden)
Without this patch, users that could see hidden categories could not get
into courses inside of them.
While at it, fix reference to the old $USER->switchrole