MDL-72133 report_log: Display logs filtered by deleted course ids

This commit is contained in:
Benjamin Walker
2025-07-28 09:06:42 +10:00
parent 5780da5481
commit 283f0855c0
8 changed files with 107 additions and 25 deletions
+22 -2
View File
@@ -90,6 +90,9 @@ class report_log_renderable implements renderable {
/** @var int group id */
public $groupid;
/** @var int forces the use of a course filter in site context */
public $sitecoursefilter;
/** @var table_log table log which will be used for rendering logs */
public $tablelog;
@@ -121,6 +124,7 @@ class report_log_renderable implements renderable {
* @param string $order (optional) sortorder of fetched records
* @param string $origin (optional) origin of the event.
* @param bool $isactivitypage (optional) if the page is activity page.
* @param int $sitecoursefilter (optional) use a course filter in site context.
*/
public function __construct(
$logreader = "",
@@ -142,9 +146,10 @@ class report_log_renderable implements renderable {
$order = "timecreated ASC",
$origin ='',
bool $isactivitypage = false,
$sitecoursefilter = 0,
) {
global $PAGE;
global $PAGE, $SITE;
// Use first reader as selected reader, if not passed.
if (empty($logreader)) {
@@ -167,7 +172,14 @@ class report_log_renderable implements renderable {
// Use site course id, if course is empty.
if (!empty($course) && is_int($course)) {
$course = get_course($course);
$courseid = $course;
try {
$course = get_course($courseid);
} catch (dml_missing_record_exception) {
// Missing courses may have be deleted, so display them in site context.
$course = $SITE;
$sitecoursefilter = $courseid;
}
}
$this->course = $course;
@@ -188,6 +200,7 @@ class report_log_renderable implements renderable {
$this->logformat = $logformat;
$this->origin = $origin;
$this->isactivitypage = $isactivitypage;
$this->sitecoursefilter = $sitecoursefilter;
}
/**
@@ -407,6 +420,12 @@ class report_log_renderable implements renderable {
}
}
}
// If filtering by a missing course, add a placeholder.
if (!empty($this->sitecoursefilter)) {
$courses[$this->sitecoursefilter] = get_string('missingcourse', 'report_log', [
'instanceid' => $this->sitecoursefilter,
]);
}
core_collator::asort($courses);
}
return $courses;
@@ -596,6 +615,7 @@ class report_log_renderable implements renderable {
$filter->date = $this->date;
$filter->orderby = $this->order;
$filter->origin = $this->origin;
$filter->sitecoursefilter = $this->sitecoursefilter;
// If showing site_errors.
if ('site_errors' === $this->modid) {
$filter->siteerrors = true;
+3 -1
View File
@@ -93,7 +93,9 @@ class report_log_renderer extends plugin_renderer_base {
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'showcourses',
'value' => $reportlog->showcourses));
$selectedcourseid = empty($reportlog->course) ? 0 : $reportlog->course->id;
$selectedcourseid = empty($reportlog->sitecoursefilter)
? (empty($reportlog->course) ? 0 : $reportlog->course->id)
: $reportlog->sitecoursefilter;
echo $this->get_course_selector_field($reportlog, $selectedcourseid);
+4
View File
@@ -420,6 +420,10 @@ class report_log_table_log extends table_sql {
if (!empty($this->filterparams->courseid) && $this->filterparams->courseid != SITEID) {
$joins[] = "courseid = :courseid";
$params['courseid'] = $this->filterparams->courseid;
} else if (!empty($this->filterparams->sitecoursefilter)) {
// Add filters for missing/deleted courses in site context.
$joins[] = "courseid = :courseid";
$params['courseid'] = $this->filterparams->sitecoursefilter;
}
if (!empty($this->filterparams->siteerrors)) {
+16 -7
View File
@@ -113,15 +113,23 @@ if ($isactivitypage) {
}
// Get course details.
$sitecoursefilter = 0;
if ($id != $SITE->id) {
$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
require_login($course);
$context = context_course::instance($course->id);
if ($cminfo !== null) {
$context = $cminfo->context;
$PAGE->set_cm($cminfo);
$course = $DB->get_record('course', ['id' => $id], '*');
if ($course) {
require_login($course);
$context = context_course::instance($course->id);
if ($cminfo !== null) {
$context = $cminfo->context;
$PAGE->set_cm($cminfo);
}
} else {
// Missing courses may have be deleted, so display them in site context.
$sitecoursefilter = $id;
}
} else {
}
if (empty($course)) {
$course = $SITE;
require_login();
$context = context_system::instance();
@@ -186,6 +194,7 @@ $reportlog = new report_log_renderable(
order: 'timecreated DESC',
origin: $origin,
isactivitypage: $isactivitypage,
sitecoursefilter: $sitecoursefilter,
);
$readers = $reportlog->get_readers();
+1
View File
@@ -37,6 +37,7 @@ $string['log:view'] = 'View course logs';
$string['log:viewtoday'] = 'View today\'s logs';
$string['page'] = 'Page {$a}';
$string['logsformat'] = 'Logs format';
$string['missingcourse'] = 'Missing course (id \'{$a->instanceid}\')';
$string['nocapability'] = 'Can not access user log report';
$string['nologreaderenabled'] = 'No log reader enabled';
$string['origin'] = 'Source';
+10 -7
View File
@@ -41,9 +41,10 @@ require_once(__DIR__.'/lib.php');
* @param string $typeormode type of logs graph needed (usercourse.png/userday.png) or the mode (today, all).
* @param int $date timestamp in GMT (seconds since epoch)
* @param string $logreader Log reader.
* @param int $sitecoursefilter use a course filter in site context.
* @return void
*/
function report_log_print_graph($course, $user, $typeormode, $date=0, $logreader='') {
function report_log_print_graph($course, $user, $typeormode, $date=0, $logreader='', $sitecoursefilter = 0) {
global $CFG, $OUTPUT;
if (!is_object($user)) {
@@ -69,10 +70,10 @@ function report_log_print_graph($course, $user, $typeormode, $date=0, $logreader
$a->username = fullname($user, true);
if ($typeormode == 'today' || $typeormode == 'userday.png') {
$logs = report_log_usertoday_data($course, $user, $date, $logreader);
$logs = report_log_usertoday_data($course, $user, $date, $logreader, $sitecoursefilter);
$title = get_string("hitsoncoursetoday", "", $a);
} else if ($typeormode == 'all' || $typeormode == 'usercourse.png') {
$logs = report_log_userall_data($course, $user, $logreader);
$logs = report_log_userall_data($course, $user, $logreader, $sitecoursefilter);
$title = get_string("hitsoncourse", "", $a);
}
@@ -527,15 +528,16 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
* @param stdClass $course the course object
* @param stdClass $user user object
* @param string $logreader the log reader where the logs are.
* @param int $sitecoursefilter use a course filter in site context.
* @return array structured array to be sent to chart API, split in two indexes (series and labels).
*/
function report_log_userall_data($course, $user, $logreader) {
function report_log_userall_data($course, $user, $logreader, $sitecoursefilter = 0) {
global $CFG;
$site = get_site();
$timenow = time();
$logs = [];
if ($course->id == $site->id) {
$courseselect = 0;
$courseselect = $sitecoursefilter;
} else {
$courseselect = $course->id;
}
@@ -582,14 +584,15 @@ function report_log_userall_data($course, $user, $logreader) {
* @param stdClass $user user object
* @param int $date A time of a day (in GMT).
* @param string $logreader the log reader where the logs are.
* @param int $sitecoursefilter use a course filter in site context.
* @return array $logs structured array to be sent to chart API, split in two indexes (series and labels).
*/
function report_log_usertoday_data($course, $user, $date, $logreader) {
function report_log_usertoday_data($course, $user, $date, $logreader, $sitecoursefilter = 0) {
$site = get_site();
$logs = [];
if ($course->id == $site->id) {
$courseselect = 0;
$courseselect = $sitecoursefilter;
} else {
$courseselect = $course->id;
}
+37
View File
@@ -437,4 +437,41 @@ final class renderable_test extends \advanced_testcase {
sort($usernames);
$this->assertEquals($expectedusers, $usernames);
}
/**
* Test getting logs for deleted courses.
*
* @covers \report_log_renderable::setup_table
* @return void
*/
public function test_get_deleted_course_logs(): void {
global $DB, $PAGE;
$this->preventResetByRollback(); // Ensure events can be recorded in log store.
// Configure log store and user.
set_config('enabled_stores', 'logstore_standard', 'tool_log');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$store = $stores['logstore_standard'];
$this->setUser(get_admin());
// Set and delete course.
$course = reset($this->courses);
$deletedcourseid = $course->id;
delete_course($course, false);
$this->assertFalse($DB->record_exists('course', ['id' => $deletedcourseid]));
// Test rendering.
$PAGE->set_url('/report/log/index.php?id=' . $deletedcourseid);
$renderable = new \report_log_renderable('', (int) $deletedcourseid);
$renderable->setup_table();
$store->flush();
$table = $renderable->tablelog;
$table->query_db(100);
// Confirm we have logs for the course deletion and that the filtering is correct.
$this->assertNotEmpty($table->totalrows);
$expectedrows = count($DB->get_records('logstore_standard_log', ['courseid' => $deletedcourseid]));
$this->assertEquals($expectedrows, $table->totalrows);
}
}
+14 -8
View File
@@ -38,12 +38,18 @@ if ($mode !== 'today' and $mode !== 'all') {
}
$user = $DB->get_record('user', array('id' => $userid, 'deleted' => 0), '*', MUST_EXIST);
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$course = $DB->get_record('course', ['id' => $courseid], '*');
$sitecoursefilter = 0;
if (!$course) {
// Missing courses may have be deleted, so display them in site context.
$course = $SITE;
$sitecoursefilter = $courseid;
}
$coursecontext = context_course::instance($course->id);
$personalcontext = context_user::instance($user->id);
if ($courseid == SITEID) {
if ($course->id == SITEID) {
$PAGE->set_context($personalcontext);
}
@@ -75,14 +81,14 @@ if ($mode === 'today') {
$stractivityreport = get_string('activityreport');
$PAGE->set_pagelayout('report');
$PAGE->set_url('/report/log/user.php', array('id' => $user->id, 'course' => $course->id, 'mode' => $mode));
$PAGE->set_url('/report/log/user.php', ['id' => $user->id, 'course' => $courseid, 'mode' => $mode]);
$PAGE->navigation->extend_for_user($user);
$PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
$PAGE->set_title("$course->shortname: $stractivityreport");
// Create the appropriate breadcrumb.
$navigationnode = array(
'url' => new moodle_url('/report/log/user.php', array('id' => $user->id, 'course' => $course->id, 'mode' => $mode))
'url' => new moodle_url('/report/log/user.php', ['id' => $user->id, 'course' => $courseid, 'mode' => $mode]),
);
if ($mode === 'today') {
$navigationnode['name'] = get_string('todaylogs');
@@ -91,7 +97,7 @@ if ($mode === 'today') {
}
$PAGE->add_report_nodes($user->id, $navigationnode);
if ($courseid == SITEID) {
if ($course->id == SITEID) {
$PAGE->set_heading(fullname($user, has_capability('moodle/site:viewfullnames', $PAGE->context)));
} else {
$PAGE->set_heading($course->fullname);
@@ -103,7 +109,7 @@ $event = \report_log\event\user_report_viewed::create(array('context' => $course
$event->trigger();
echo $OUTPUT->header();
if ($courseid != SITEID) {
if ($course->id != SITEID) {
$userheading = array(
'heading' => fullname($user, has_capability('moodle/site:viewfullnames', $PAGE->context)),
'user' => $user,
@@ -126,7 +132,7 @@ if ($mode === 'today') {
$output = $PAGE->get_renderer('report_log');
$reportlog = new report_log_renderable($logreader, $course, $user->id, 0, '', -1, -1, false, false, true, false, $PAGE->url,
$timefrom, '', $page, $perpage, 'timecreated DESC');
$timefrom, '', $page, $perpage, 'timecreated DESC', '' , $sitecoursefilter);
// Setup table if log reader is enabled.
if (!empty($reportlog->selectedlogreader)) {
@@ -138,7 +144,7 @@ echo $output->reader_selector($reportlog);
// Print the graphic chart accordingly to the mode (all, today).
echo '<div class="graph">';
report_log_print_graph($course, $user, $mode, 0, $logreader);
report_log_print_graph($course, $user, $mode, 0, $logreader, $sitecoursefilter);
echo '</div>';
echo $output->render($reportlog);