mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 00:46:50 +02:00
MDL-48594 Report: More filtering options on Activity Completion Report
This commit is contained in:
parent
7811d7ace4
commit
5ad8101553
6 changed files with 339 additions and 73 deletions
70
report/progress/classes/local/helper.php
Normal file
70
report/progress/classes/local/helper.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace report_progress\local;
|
||||
|
||||
/**
|
||||
* Helper for report progress.
|
||||
*
|
||||
* @package report_progress
|
||||
* @copyright 2021 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL Juv3 or later
|
||||
*/
|
||||
class helper {
|
||||
|
||||
/** The default number of results to be shown per page. */
|
||||
const COMPLETION_REPORT_PAGE = 25;
|
||||
|
||||
/**
|
||||
* Get activities information by the activity include and activity order option.
|
||||
*
|
||||
* @param \completion_info $completion Completion information of course.
|
||||
* @param string $activityinclude Activity type for filtering.
|
||||
* @param string $activityorder Activity sort option.
|
||||
* @return array The available activity types and activities array after filtering and sorting.
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public static function get_activities_to_show(\completion_info $completion, string $activityinclude,
|
||||
string $activityorder): array {
|
||||
// Get all activity types.
|
||||
$activities = $completion->get_activities();
|
||||
$availableactivitytypes = [];
|
||||
|
||||
foreach ($activities as $activity) {
|
||||
$availableactivitytypes[$activity->modname] = $activity->get_module_type_name(true);
|
||||
}
|
||||
|
||||
asort($availableactivitytypes);
|
||||
$availableactivitytypes = ['all' => get_string('allactivitiesandresources', 'report_progress')] +
|
||||
$availableactivitytypes;
|
||||
|
||||
// Filter activities by type.
|
||||
if (!empty($activityinclude) && $activityinclude !== 'all') {
|
||||
$activities = array_filter($activities, function($activity) use ($activityinclude) {
|
||||
return $activity->modname === $activityinclude;
|
||||
});
|
||||
}
|
||||
|
||||
// The activities are sorted by activity order on course page by default.
|
||||
if ($activityorder === 'alphabetical') {
|
||||
usort($activities, function($a, $b) {
|
||||
return strcmp($a->name, $b->name);
|
||||
});
|
||||
}
|
||||
|
||||
return [$availableactivitytypes, $activities];
|
||||
}
|
||||
}
|
94
report/progress/classes/output/renderer.php
Normal file
94
report/progress/classes/output/renderer.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace report_progress\output;
|
||||
|
||||
use single_select;
|
||||
use plugin_renderer_base;
|
||||
use html_writer;
|
||||
|
||||
/**
|
||||
* Renderer for report progress.
|
||||
*
|
||||
* @package report_progress
|
||||
* @copyright 2021 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL Juv3 or later
|
||||
*/
|
||||
class renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Render include activity single select box.
|
||||
*
|
||||
* @param \moodle_url $url The base url.
|
||||
* @param array $activitytypes The activity type options.
|
||||
* @param string $activityinclude The current selected option.
|
||||
* @return string HTML
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function render_include_activity_select(\moodle_url $url, array $activitytypes,
|
||||
string $activityinclude): string {
|
||||
$includeurl = fullclone($url);
|
||||
$includeurl->remove_params(['page', 'activityinclude']);
|
||||
$activityincludeselect = new single_select(
|
||||
$url, 'activityinclude',
|
||||
$activitytypes, $activityinclude, null, 'include-activity-select-report'
|
||||
);
|
||||
$activityincludeselect->set_label(get_string('include', 'report_progress'));
|
||||
return \html_writer::div($this->output->render($activityincludeselect),
|
||||
'include-activity-selector d-inline-block ml-3' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render activity order single select box.
|
||||
*
|
||||
* @param \moodle_url $url The base url.
|
||||
* @param string $activityorder The current selected option.
|
||||
* @return string HTML
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function render_activity_order_select(\moodle_url $url, string $activityorder): string {
|
||||
$activityorderurl = fullclone($url);
|
||||
$activityorderurl->remove_params(['activityorder']);
|
||||
$options = ['orderincourse' => get_string('orderincourse', 'report_progress'),
|
||||
'alphabetical' => get_string('alphabetical', 'report_progress')];
|
||||
$sorttable = new single_select(
|
||||
$activityorderurl, 'activityorder',
|
||||
$options, $activityorder, null, 'activity-order-select-report'
|
||||
);
|
||||
$sorttable->set_label(get_string('activityorder', 'report_progress'));
|
||||
return \html_writer::div($this->output->render($sorttable),
|
||||
'activity-order-selector include-activity-selector d-inline-block ml-3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render download buttons.
|
||||
*
|
||||
* @param \moodle_url $url The base url.
|
||||
* @return string HTML
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function render_download_buttons(\moodle_url $url): string {
|
||||
$downloadurl = fullclone($url);
|
||||
$downloadurl->remove_params(['page']);
|
||||
$downloadurl->param('format', 'csv');
|
||||
$downloadhtml = html_writer::start_tag('ul', ['class' => 'progress-actions']);
|
||||
$downloadhtml .= html_writer::tag('li', html_writer::link($downloadurl, get_string('csvdownload', 'completion')));
|
||||
$downloadurl->param('format', 'excelcsv');
|
||||
$downloadhtml .= html_writer::tag('li', html_writer::link($downloadurl, get_string('excelcsvdownload', 'completion')));
|
||||
$downloadhtml .= html_writer::end_tag('ul');
|
||||
|
||||
return $downloadhtml;
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
require('../../config.php');
|
||||
require_once($CFG->libdir . '/completionlib.php');
|
||||
|
||||
define('COMPLETION_REPORT_PAGE', 25);
|
||||
use \report_progress\local\helper;
|
||||
|
||||
// Get course
|
||||
$id = required_param('course',PARAM_INT);
|
||||
|
@ -45,11 +45,13 @@ $format = optional_param('format','',PARAM_ALPHA);
|
|||
$excel = $format == 'excelcsv';
|
||||
$csv = $format == 'csv' || $excel;
|
||||
|
||||
// Paging
|
||||
$start = optional_param('start', 0, PARAM_INT);
|
||||
// Paging, sorting and filtering.
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$sifirst = optional_param('sifirst', 'all', PARAM_NOTAGS);
|
||||
$silast = optional_param('silast', 'all', PARAM_NOTAGS);
|
||||
$start = optional_param('start', 0, PARAM_INT);
|
||||
$groupid = optional_param('group', 0, PARAM_INT);
|
||||
$activityinclude = optional_param('activityinclude', 'all', PARAM_TEXT);
|
||||
$activityorder = optional_param('activityorder', 'orderincourse', PARAM_TEXT);
|
||||
|
||||
// Whether to show extra user identity information
|
||||
// TODO Does not support custom user profile fields (MDL-70456).
|
||||
|
@ -72,8 +74,8 @@ if ($sort !== '') {
|
|||
if ($format !== '') {
|
||||
$url->param('format', $format);
|
||||
}
|
||||
if ($start !== 0) {
|
||||
$url->param('start', $start);
|
||||
if ($page !== 0) {
|
||||
$url->param('page', $page);
|
||||
}
|
||||
if ($sifirst !== 'all') {
|
||||
$url->param('sifirst', $sifirst);
|
||||
|
@ -81,6 +83,16 @@ if ($sifirst !== 'all') {
|
|||
if ($silast !== 'all') {
|
||||
$url->param('silast', $silast);
|
||||
}
|
||||
if ($groupid !== 0) {
|
||||
$url->param('group', $groupid);
|
||||
}
|
||||
if ($activityinclude !== '') {
|
||||
$url->param('activityinclude', $activityinclude);
|
||||
}
|
||||
if ($activityorder !== '') {
|
||||
$url->param('activityorder', $activityorder);
|
||||
}
|
||||
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_pagelayout('report');
|
||||
|
||||
|
@ -96,10 +108,10 @@ if ($group===0 && $course->groupmode==SEPARATEGROUPS) {
|
|||
}
|
||||
|
||||
// Get data on activities and progress of all users, and give error if we've
|
||||
// nothing to display (no users or no activities)
|
||||
$reportsurl = $CFG->wwwroot.'/course/report.php?id='.$course->id;
|
||||
// nothing to display (no users or no activities).
|
||||
$completion = new completion_info($course);
|
||||
$activities = $completion->get_activities();
|
||||
list($activitytypes, $activities) = helper::get_activities_to_show($completion, $activityinclude, $activityorder);
|
||||
$output = $PAGE->get_renderer('report_progress');
|
||||
|
||||
if ($sifirst !== 'all') {
|
||||
set_user_preference('ifirst', $sifirst);
|
||||
|
@ -149,8 +161,8 @@ if ($total) {
|
|||
$where_params,
|
||||
$group,
|
||||
$firstnamesort ? 'u.firstname ASC, u.lastname ASC' : 'u.lastname ASC, u.firstname ASC',
|
||||
$csv ? 0 : COMPLETION_REPORT_PAGE,
|
||||
$csv ? 0 : $start,
|
||||
$csv ? 0 : helper::COMPLETION_REPORT_PAGE,
|
||||
$csv ? 0 : $page * helper::COMPLETION_REPORT_PAGE,
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
@ -182,8 +194,17 @@ if ($csv && $grandtotal && count($activities)>0) { // Only show CSV if there are
|
|||
echo $OUTPUT->header();
|
||||
$PAGE->requires->js_call_amd('report_progress/completion_override', 'init', [fullname($USER)]);
|
||||
|
||||
// Handle groups (if enabled)
|
||||
groups_print_course_menu($course,$CFG->wwwroot.'/report/progress/?course='.$course->id);
|
||||
// Handle groups (if enabled).
|
||||
$groupurl = fullclone($url);
|
||||
$groupurl->remove_params(['page', 'group']);
|
||||
groups_print_course_menu($course, $groupurl);
|
||||
|
||||
// Display include activity filter.
|
||||
echo $output->render_include_activity_select($url, $activitytypes, $activityinclude);
|
||||
|
||||
// Display activity order options.
|
||||
echo $output->render_activity_order_select($url, $activityorder);
|
||||
|
||||
}
|
||||
|
||||
if (count($activities)==0) {
|
||||
|
@ -213,57 +234,12 @@ $prefixfirst = 'sifirst';
|
|||
$prefixlast = 'silast';
|
||||
|
||||
// The URL used in the initials bar should reset the 'start' parameter.
|
||||
$initialsbarurl = new moodle_url($url);
|
||||
$initialsbarurl->remove_params('start');
|
||||
$initialsbarurl = fullclone($url);
|
||||
$initialsbarurl->remove_params('page');
|
||||
|
||||
$pagingbar .= $OUTPUT->initials_bar($sifirst, 'firstinitial', get_string('firstname'), $prefixfirst, $initialsbarurl);
|
||||
$pagingbar .= $OUTPUT->initials_bar($sifirst, 'firstinitial mt-2', get_string('firstname'), $prefixfirst, $initialsbarurl);
|
||||
$pagingbar .= $OUTPUT->initials_bar($silast, 'lastinitial', get_string('lastname'), $prefixlast, $initialsbarurl);
|
||||
|
||||
// Do we need a paging bar?
|
||||
if ($total > COMPLETION_REPORT_PAGE) {
|
||||
|
||||
// Paging bar
|
||||
$pagingbar .= '<div class="paging">';
|
||||
$pagingbar .= get_string('page').': ';
|
||||
|
||||
$sistrings = array();
|
||||
if ($sifirst != 'all') {
|
||||
$sistrings[] = "sifirst={$sifirst}";
|
||||
}
|
||||
if ($silast != 'all') {
|
||||
$sistrings[] = "silast={$silast}";
|
||||
}
|
||||
$sistring = !empty($sistrings) ? '&'.implode('&', $sistrings) : '';
|
||||
|
||||
// Display previous link
|
||||
if ($start > 0) {
|
||||
$pstart = max($start - COMPLETION_REPORT_PAGE, 0);
|
||||
$pagingbar .= "(<a class=\"previous\" href=\"{$link}{$pstart}{$sistring}\">".get_string('previous').'</a>) ';
|
||||
}
|
||||
|
||||
// Create page links
|
||||
$curstart = 0;
|
||||
$curpage = 0;
|
||||
while ($curstart < $total) {
|
||||
$curpage++;
|
||||
|
||||
if ($curstart == $start) {
|
||||
$pagingbar .= ' '.$curpage.' ';
|
||||
} else {
|
||||
$pagingbar .= " <a href=\"{$link}{$curstart}{$sistring}\">$curpage</a> ";
|
||||
}
|
||||
|
||||
$curstart += COMPLETION_REPORT_PAGE;
|
||||
}
|
||||
|
||||
// Display next link
|
||||
$nstart = $start + COMPLETION_REPORT_PAGE;
|
||||
if ($nstart < $total) {
|
||||
$pagingbar .= " (<a class=\"next\" href=\"{$link}{$nstart}{$sistring}\">".get_string('next').'</a>)';
|
||||
}
|
||||
|
||||
$pagingbar .= '</div>';
|
||||
}
|
||||
$pagingbar .= $OUTPUT->paging_bar($total, $page, helper::COMPLETION_REPORT_PAGE, $url);
|
||||
|
||||
// Okay, let's draw the table of progress info,
|
||||
|
||||
|
@ -285,16 +261,16 @@ if (!$csv) {
|
|||
// User heading / sort option
|
||||
print '<th scope="col" class="completion-sortchoice">';
|
||||
|
||||
$sistring = "&silast={$silast}&sifirst={$sifirst}";
|
||||
|
||||
$sorturl = fullclone($url);
|
||||
if ($firstnamesort) {
|
||||
$sorturl->param('sort', 'lastname');
|
||||
$sortlink = html_writer::link($sorturl, get_string('lastname'));
|
||||
print
|
||||
get_string('firstname')." / <a href=\"./?course={$course->id}{$sistring}\">".
|
||||
get_string('lastname').'</a>';
|
||||
get_string('firstname') . " / $sortlink";
|
||||
} else {
|
||||
print "<a href=\"./?course={$course->id}&sort=firstname{$sistring}\">".
|
||||
get_string('firstname').'</a> / '.
|
||||
get_string('lastname');
|
||||
$sorturl->param('sort', 'firstname');
|
||||
$sortlink = html_writer::link($sorturl, get_string('firstname'));
|
||||
print "$sortlink / " . get_string('lastname');
|
||||
}
|
||||
print '</th>';
|
||||
|
||||
|
@ -455,10 +431,7 @@ if ($csv) {
|
|||
print '</tbody></table>';
|
||||
print '</div>';
|
||||
|
||||
print '<ul class="progress-actions"><li><a href="index.php?course='.$course->id.
|
||||
'&format=csv">'.get_string('csvdownload','completion').'</a></li>
|
||||
<li><a href="index.php?course='.$course->id.'&format=excelcsv">'.
|
||||
get_string('excelcsvdownload','completion').'</a></li></ul>';
|
||||
echo $output->render_download_buttons($url);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
*/
|
||||
|
||||
$string['pluginname'] = 'Activity completion';
|
||||
$string['activityorder'] = 'Activity order';
|
||||
$string['allactivitiesandresources'] = 'All activities and resources';
|
||||
$string['alphabetical'] = 'Alphabetical ';
|
||||
$string['include'] = 'Include';
|
||||
$string['orderincourse'] = 'Order in course';
|
||||
$string['page-report-progress-x'] = 'Any activity completion report';
|
||||
$string['page-report-progress-index'] = 'Activity completion report';
|
||||
$string['page-report-progress-user'] = 'User activity completion report';
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
@report @report_progress
|
||||
Feature: Teacher can view and filter activity completion data by group and activity type.
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format | enablecompletion | groupmode |
|
||||
| Course 1 | C1 | topics | 1 | 1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section | completion | completionview |
|
||||
| quiz | My quiz B | A3 desc | C1 | quizb | 0 | 2 | 1 |
|
||||
| quiz | My quiz A | A3 desc | C1 | quiza | 0 | 2 | 1 |
|
||||
| page | My page | A4 desc | C1 | page1 | 0 | 2 | 1 |
|
||||
| assign | My assignment | A1 desc | C1 | assign1 | 0 | 2 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | One | teacher1@example.com |
|
||||
| student1 | Student | One | student1@example.com |
|
||||
| student2 | Student | Two | student2@example.com |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Group 1 | C1 | G1 |
|
||||
| Group 2 | C1 | G2 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G2 |
|
||||
| teacher1 | G1 |
|
||||
| teacher1 | G2 |
|
||||
|
||||
@javascript
|
||||
Scenario: Teacher can view the activity completion report using filtering and sorting options.
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Reports > Activity completion" in current page administration
|
||||
Then "My quiz B" "link" should appear before "My quiz A" "link"
|
||||
And I should see "My assignment"
|
||||
And I should see "My page"
|
||||
And I should see "Student One"
|
||||
And I should see "Student Two"
|
||||
And I set the field "Separate groups" to "Group 1"
|
||||
And I set the field "Include" to "Quizzes"
|
||||
And I set the field "Activity order" to "Alphabetical"
|
||||
And "My quiz A" "link" should appear before "My quiz B" "link"
|
||||
And I should not see "My assignment"
|
||||
And I should not see "My page"
|
||||
And I should see "Student One"
|
||||
And I should not see "Student Two"
|
72
report/progress/tests/report_progress_helper_testcase.php
Normal file
72
report/progress/tests/report_progress_helper_testcase.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for the progress report sorting.
|
||||
*
|
||||
* @package report_progress
|
||||
* @copyright 2021 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class for testing report progress helper.
|
||||
*
|
||||
* @copyright 2021 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
class report_progress_helper_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Set up testcase.
|
||||
*/
|
||||
public function setUp(): void {
|
||||
global $CFG;
|
||||
|
||||
$CFG->enablecompletion = true;
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
$this->generator = $this->getDataGenerator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test process_activities_by_filter_options function.
|
||||
*/
|
||||
public function test_sort_activities() {
|
||||
$expectedactivitytypes = ['all' => 'All activities and resources', 'assign' => 'Assignments', 'quiz' => 'Quizzes'];
|
||||
|
||||
// Generate test data.
|
||||
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
|
||||
$quiz2 = $this->generator->create_module('quiz', ['course' => $course->id, 'name' => 'Quiz 2'],
|
||||
['completion' => 1]);
|
||||
$quiz1 = $this->generator->create_module('quiz', ['course' => $course->id, 'name' => 'Quiz 1'],
|
||||
['completion' => 1]);
|
||||
$assign1 = $this->generator->create_module('assign', ['course' => $course->id, 'name' => 'Assignment'],
|
||||
['completion' => 1]);
|
||||
$completion = new completion_info($course);
|
||||
// Sort the activities by name.
|
||||
list($activitytypes, $activities) = \report_progress\local\helper::get_activities_to_show($completion, 'quiz',
|
||||
'alphabetical');
|
||||
|
||||
// Check weather the result is filtered and sorted.
|
||||
$this->assertEquals(2, count($activities));
|
||||
$this->assertEquals('Quiz 1', $activities[0]->name);
|
||||
$this->assertEquals('Quiz 2', $activities[1]->name);
|
||||
$this->assertEquals($activitytypes, $expectedactivitytypes);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue