MDL-58768 calendar: Add $requestinguser to the container class
The requesting user is not always the same as the current user. The container class now allows a different user to be set as the requesting user. All capability checks are done against the requesting user. Also, the $requestinguser is passed to core_calendar_provide_event_action and core_calendar_is_event_visible callback functions. These callback functions need to be updated in all activity modules to accept a $user parameter.
This commit is contained in:
@@ -81,6 +81,11 @@ class container {
|
||||
*/
|
||||
protected static $modulecache = array();
|
||||
|
||||
/**
|
||||
* @var int The requesting user. All capability checks are done against this user.
|
||||
*/
|
||||
protected static $requestinguserid;
|
||||
|
||||
/**
|
||||
* Initialises the dependency graph if it hasn't yet been.
|
||||
*/
|
||||
@@ -117,11 +122,13 @@ class container {
|
||||
[self::class, 'apply_component_provide_event_action'],
|
||||
[self::class, 'apply_component_is_event_visible'],
|
||||
function ($dbrow) {
|
||||
$requestinguserid = self::get_requesting_user();
|
||||
|
||||
if (!empty($dbrow->categoryid)) {
|
||||
// This is a category event. Check that the category is visible to this user.
|
||||
$category = \coursecat::get($dbrow->categoryid, IGNORE_MISSING, true);
|
||||
$category = \coursecat::get($dbrow->categoryid, IGNORE_MISSING, true, $requestinguserid);
|
||||
|
||||
if (empty($category) || !$category->is_uservisible()) {
|
||||
if (empty($category) || !$category->is_uservisible($requestinguserid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +138,7 @@ class container {
|
||||
return false;
|
||||
}
|
||||
|
||||
$instances = get_fast_modinfo($dbrow->courseid)->instances;
|
||||
$instances = get_fast_modinfo($dbrow->courseid, $requestinguserid)->instances;
|
||||
|
||||
// If modinfo doesn't know about the module, we should ignore it.
|
||||
if (!isset($instances[$dbrow->modulename]) || !isset($instances[$dbrow->modulename][$dbrow->instance])) {
|
||||
@@ -156,11 +163,13 @@ class container {
|
||||
}
|
||||
|
||||
$coursecontext = \context_course::instance($dbrow->courseid);
|
||||
if (!$cm->get_course()->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
|
||||
if (!$cm->get_course()->visible &&
|
||||
!has_capability('moodle/course:viewhiddencourses', $coursecontext, $requestinguserid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/course:view', $coursecontext) && !is_enrolled($coursecontext)) {
|
||||
if (!has_capability('moodle/course:view', $coursecontext, $requestinguserid) &&
|
||||
!is_enrolled($coursecontext, $requestinguserid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -191,6 +200,7 @@ class container {
|
||||
* Reset all static caches, called between tests.
|
||||
*/
|
||||
public static function reset_caches() {
|
||||
self::$requestinguserid = null;
|
||||
self::$eventfactory = null;
|
||||
self::$eventmapper = null;
|
||||
self::$eventvault = null;
|
||||
@@ -230,6 +240,31 @@ class container {
|
||||
return self::$eventvault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the requesting user so that all capability checks are done against this user.
|
||||
* Setting the requesting user (hence calling this function) is optional and if you do not so,
|
||||
* $USER will be used as the requesting user. However, if you wish to set the requesting user yourself,
|
||||
* you should call this function before any other function of the container class is called.
|
||||
*
|
||||
* @param int $userid The user id.
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public static function set_requesting_user($userid) {
|
||||
self::$requestinguserid = $userid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requesting user id.
|
||||
* It usually is the current user unless it has been set explicitly using set_requesting_user.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_requesting_user() {
|
||||
global $USER;
|
||||
|
||||
return empty(self::$requestinguserid) ? $USER->id : self::$requestinguserid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls callback 'core_calendar_provide_event_action' from the component responsible for the event
|
||||
*
|
||||
@@ -245,14 +280,23 @@ class container {
|
||||
$mapper = self::$eventmapper;
|
||||
$action = null;
|
||||
if ($event->get_course_module()) {
|
||||
$requestinguserid = self::get_requesting_user();
|
||||
$legacyevent = $mapper->from_event_to_legacy_event($event);
|
||||
// We know for a fact that the the requesting user might be different from the logged in user,
|
||||
// but the event mapper is not aware of that.
|
||||
if (empty($event->user) && !empty($legacyevent->userid)) {
|
||||
$legacyevent->userid = $requestinguserid;
|
||||
}
|
||||
|
||||
// TODO MDL-58866 Only activity modules currently support this callback.
|
||||
// Any other event will not be displayed on the dashboard.
|
||||
$action = component_callback(
|
||||
'mod_' . $event->get_course_module()->get('modname'),
|
||||
'core_calendar_provide_event_action',
|
||||
[
|
||||
$mapper->from_event_to_legacy_event($event),
|
||||
self::$actionfactory
|
||||
$legacyevent,
|
||||
self::$actionfactory,
|
||||
$requestinguserid
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -279,12 +323,21 @@ class container {
|
||||
$mapper = self::$eventmapper;
|
||||
$eventvisible = null;
|
||||
if ($event->get_course_module()) {
|
||||
$requestinguserid = self::get_requesting_user();
|
||||
$legacyevent = $mapper->from_event_to_legacy_event($event);
|
||||
// We know for a fact that the the requesting user might be different from the logged in user,
|
||||
// but the event mapper is not aware of that.
|
||||
if (empty($event->user) && !empty($legacyevent->userid)) {
|
||||
$legacyevent->userid = $requestinguserid;
|
||||
}
|
||||
|
||||
// TODO MDL-58866 Only activity modules currently support this callback.
|
||||
$eventvisible = component_callback(
|
||||
'mod_' . $event->get_course_module()->get('modname'),
|
||||
'core_calendar_is_event_visible',
|
||||
[
|
||||
$mapper->from_event_to_legacy_event($event)
|
||||
$legacyevent,
|
||||
$requestinguserid
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3326,6 +3326,11 @@ function calendar_get_legacy_events($tstart, $tend, $users, $groups, $courses,
|
||||
return $param;
|
||||
}, [$users, $groups, $courses, $categories]);
|
||||
|
||||
// If a single user is provided, we can use that for capability checks.
|
||||
// Otherwise current logged in user is used - See MDL-58768.
|
||||
if (is_array($userparam) && count($userparam) == 1) {
|
||||
\core_calendar\local\event\container::set_requesting_user($userparam[0]);
|
||||
}
|
||||
$mapper = \core_calendar\local\event\container::get_event_mapper();
|
||||
$events = \core_calendar\local\api::get_events(
|
||||
$tstart,
|
||||
|
||||
@@ -4,6 +4,8 @@ information provided here is intended especially for developers.
|
||||
=== 3.5.2 ===
|
||||
* calendar_get_default_courses() function now has optional $userid parameter.
|
||||
* calendar_set_filters() function now has optional $user parameter.
|
||||
* The core_calendar\local\event\container class now provides two new helper methods for getting and setting the requesting user:
|
||||
set_requesting_user() and get_requesting_user().
|
||||
|
||||
=== 3.5 ===
|
||||
* core_calendar_external::get_calendar_events now returns the categoryid for category events.
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
This files describes API changes in /mod/* - activity modules,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.5.2 ===
|
||||
|
||||
* Now, when mod_<modname>_core_calendar_is_event_visible or mod_<modname>_core_calendar_provide_event_action callback functions
|
||||
are called, the userid of the requesting user is also passed to them.
|
||||
|
||||
=== 3.5 ===
|
||||
|
||||
* There is a new privacy API that every subsystem and plugin has to implement so that the site can become GDPR
|
||||
|
||||
Reference in New Issue
Block a user