first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,88 @@
<?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/>.
/**
* The report_completion report viewed event.
*
* @package report_completion
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace report_completion\event;
defined('MOODLE_INTERNAL') || die();
/**
* The report_completion report viewed event class.
*
* @package report_completion
* @since Moodle 2.7
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class report_viewed extends \core\event\base {
/**
* Init method.
*
* @return void
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventreportviewed', 'report_completion');
}
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' viewed the completion report for the course with id '$this->courseid'.";
}
/**
* Returns relevant URL.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/report/completion/index.php', array('course' => $this->courseid));
}
/**
* custom validations.
*
* @throws \coding_exception when validation fails.
* @return void
*/
protected function validate_data() {
parent::validate_data();
if ($this->contextlevel != CONTEXT_COURSE) {
throw new \coding_exception('Context level must be CONTEXT_COURSE.');
}
}
}
@@ -0,0 +1,92 @@
<?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/>.
/**
* The report_completion user report viewed event.
*
* @package report_completion
* @copyright 2014 onwards Ankit Agarwal<ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace report_completion\event;
defined('MOODLE_INTERNAL') || die();
/**
* The report_completion user report viewed event class.
*
* @package report_completion
* @since Moodle 2.7
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class user_report_viewed extends \core\event\base {
/**
* Init method.
*
* @return void
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventuserreportviewed', 'report_completion');
}
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' viewed the user completion report for the user with id '$this->relateduserid'.";
}
/**
* Returns relevant URL.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/report/completion/user.php', array('course' => $this->courseid, 'id' => $this->relateduserid));
}
/**
* custom validations.
*
* @throws \coding_exception when validation fails.
* @return void
*/
protected function validate_data() {
parent::validate_data();
if ($this->contextlevel != CONTEXT_COURSE) {
throw new \coding_exception('Context level must be CONTEXT_COURSE.');
}
if (!isset($this->relateduserid)) {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
}
@@ -0,0 +1,45 @@
<?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/>.
/**
* Privacy provider implementation for report_completion.
*
* @package report_completion
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace report_completion\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider implementation for report_completion.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
+42
View File
@@ -0,0 +1,42 @@
<?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/>.
/**
* Capabilities
*
* @package report_completion
* @copyright 2009 Catalyst IT Ltd
* @author Aaron Barnes <aaronb@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'report/completion:view' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'coursereport/completion:view',
)
);
+32
View File
@@ -0,0 +1,32 @@
<?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/>.
/**
* Post installation and migration code.
*
* @package report
* @subpackage completion
* @copyright 2011 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
function xmldb_report_completion_install() {
global $DB;
}
+751
View File
@@ -0,0 +1,751 @@
<?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/>.
/**
* Course completion progress report
*
* @package report
* @subpackage completion
* @copyright 2009 Catalyst IT Ltd
* @author Aaron Barnes <aaronb@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core\report_helper;
require_once(__DIR__.'/../../config.php');
require_once("{$CFG->libdir}/completionlib.php");
/**
* Configuration
*/
define('COMPLETION_REPORT_PAGE', 25);
define('COMPLETION_REPORT_COL_TITLES', true);
/*
* Setup page, check permissions
*/
// Get course
$courseid = required_param('course', PARAM_INT);
$format = optional_param('format','',PARAM_ALPHA);
$sort = optional_param('sort','',PARAM_ALPHA);
$edituser = optional_param('edituser', 0, PARAM_INT);
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$context = context_course::instance($course->id);
$url = new moodle_url('/report/completion/index.php', array('course'=>$course->id));
$PAGE->set_url($url);
$PAGE->set_pagelayout('report');
$firstnamesort = ($sort == 'firstname');
$excel = ($format == 'excelcsv');
$csv = ($format == 'csv' || $excel);
if ($csv) {
$dateformat = "%F %T";
} else {
$dateformat = get_string('strftimedatetimeshort', 'langconfig');
}
// Load CSV library
if ($csv) {
require_once("{$CFG->libdir}/csvlib.class.php");
}
// Paging
$start = optional_param('start', 0, PARAM_INT);
$sifirst = optional_param('sifirst', 'all', PARAM_NOTAGS);
$silast = optional_param('silast', 'all', PARAM_NOTAGS);
// Whether to show extra user identity information.
$extrafields = \core_user\fields::get_identity_fields($context, true);
$leftcols = 1 + count($extrafields);
// Check permissions
require_login($course);
require_capability('report/completion:view', $context);
// Get group mode
$group = groups_get_course_group($course, true); // Supposed to verify group
if ($group === 0 && $course->groupmode == SEPARATEGROUPS) {
require_capability('moodle/site:accessallgroups',$context);
}
/**
* Load data
*/
// Retrieve course_module data for all modules in the course
$modinfo = get_fast_modinfo($course);
// Get criteria for course
$completion = new completion_info($course);
if (!$completion->has_criteria()) {
throw new \moodle_exception('nocriteriaset', 'completion', $CFG->wwwroot.'/course/report.php?id='.$course->id);
}
// Get criteria and put in correct order
$criteria = array();
foreach ($completion->get_criteria(COMPLETION_CRITERIA_TYPE_COURSE) as $criterion) {
$criteria[] = $criterion;
}
foreach ($completion->get_criteria(COMPLETION_CRITERIA_TYPE_ACTIVITY) as $criterion) {
$criteria[] = $criterion;
}
foreach ($completion->get_criteria() as $criterion) {
if (!in_array($criterion->criteriatype, array(
COMPLETION_CRITERIA_TYPE_COURSE, COMPLETION_CRITERIA_TYPE_ACTIVITY))) {
$criteria[] = $criterion;
}
}
// Can logged in user mark users as complete?
// (if the logged in user has a role defined in the role criteria)
$allow_marking = false;
$allow_marking_criteria = null;
if (!$csv) {
// Get role criteria
$rcriteria = $completion->get_criteria(COMPLETION_CRITERIA_TYPE_ROLE);
if (!empty($rcriteria)) {
foreach ($rcriteria as $rcriterion) {
$users = get_role_users($rcriterion->role, $context, true);
// If logged in user has this role, allow marking complete
if ($users && in_array($USER->id, array_keys($users))) {
$allow_marking = true;
$allow_marking_criteria = $rcriterion->id;
break;
}
}
}
}
/*
* Setup page header
*/
if ($csv) {
$shortname = format_string($course->shortname, true, array('context' => $context));
$shortname = preg_replace('/[^a-z0-9-]/', '_',core_text::strtolower(strip_tags($shortname)));
$export = new csv_export_writer('comma', '"', 'application/download', $excel);
$export->set_filename('completion-'.$shortname);
} else {
// Navigation and header
$strcompletion = get_string('coursecompletion');
$PAGE->set_title($strcompletion);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
// Print the selected dropdown.
$pluginname = get_string('pluginname', 'report_completion');
report_helper::print_report_selector($pluginname);
// Handle groups (if enabled)
groups_print_course_menu($course, $CFG->wwwroot.'/report/completion/index.php?course='.$course->id);
}
if ($sifirst !== 'all') {
set_user_preference('ifirst', $sifirst);
}
if ($silast !== 'all') {
set_user_preference('ilast', $silast);
}
if (!empty($USER->preference['ifirst'])) {
$sifirst = $USER->preference['ifirst'];
} else {
$sifirst = 'all';
}
if (!empty($USER->preference['ilast'])) {
$silast = $USER->preference['ilast'];
} else {
$silast = 'all';
}
// Generate where clause
$where = array();
$where_params = array();
if ($sifirst !== 'all') {
$where[] = $DB->sql_like('u.firstname', ':sifirst', false, false);
$where_params['sifirst'] = $sifirst.'%';
}
if ($silast !== 'all') {
$where[] = $DB->sql_like('u.lastname', ':silast', false, false);
$where_params['silast'] = $silast.'%';
}
// Get user match count
$total = $completion->get_num_tracked_users(implode(' AND ', $where), $where_params, $group);
// Total user count
$grandtotal = $completion->get_num_tracked_users('', array(), $group);
// If no users in this course what-so-ever
if (!$grandtotal) {
echo $OUTPUT->container(get_string('err_nousers', 'completion'), 'errorbox errorboxcontent');
echo $OUTPUT->footer();
exit;
}
// Get user data
$progress = array();
if ($total) {
$progress = $completion->get_progress_all(
implode(' AND ', $where),
$where_params,
$group,
$firstnamesort ? 'u.firstname ASC' : 'u.lastname ASC',
$csv ? 0 : COMPLETION_REPORT_PAGE,
$csv ? 0 : $start,
$context
);
}
// Build link for paging
$link = $CFG->wwwroot.'/report/completion/index.php?course='.$course->id;
if (strlen($sort)) {
$link .= '&amp;sort='.$sort;
}
$link .= '&amp;start=';
$pagingbar = '';
// Initials bar.
$prefixfirst = 'sifirst';
$prefixlast = 'silast';
$pagingbar .= $OUTPUT->initials_bar($sifirst, 'firstinitial', get_string('firstname'), $prefixfirst, $url);
$pagingbar .= $OUTPUT->initials_bar($silast, 'lastinitial', get_string('lastname'), $prefixlast, $url);
// 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) ? '&amp;'.implode('&amp;', $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>)&nbsp;';
}
// Create page links
$curstart = 0;
$curpage = 0;
while ($curstart < $total) {
$curpage++;
if ($curstart == $start) {
$pagingbar .= '&nbsp;'.$curpage.'&nbsp;';
}
else {
$pagingbar .= "&nbsp;<a href=\"{$link}{$curstart}{$sistring}\">$curpage</a>&nbsp;";
}
$curstart += COMPLETION_REPORT_PAGE;
}
// Display next link
$nstart = $start + COMPLETION_REPORT_PAGE;
if ($nstart < $total) {
$pagingbar .= "&nbsp;(<a class=\"next\" href=\"{$link}{$nstart}{$sistring}\">".get_string('next').'</a>)';
}
$pagingbar .= '</div>';
}
/*
* Draw table header
*/
// Start of table
if (!$csv) {
print '<br class="clearer"/>'; // ugh
$total_header = ($total == $grandtotal) ? $total : "{$total}/{$grandtotal}";
echo $OUTPUT->heading(get_string('allparticipants').": {$total_header}", 3);
print $pagingbar;
if (!$total) {
echo $OUTPUT->notification(get_string('nothingtodisplay'), 'info', false);
echo $OUTPUT->footer();
exit;
}
print '<table id="completion-progress" class="table table-bordered generaltable flexible boxaligncenter
completionreport" cellpadding="5" border="1">';
// Print criteria group names
print PHP_EOL.'<thead><tr style="vertical-align: top">';
echo '<th scope="row" class="rowheader" colspan="' . $leftcols . '">' .
get_string('criteriagroup', 'completion') . '</th>';
$current_group = false;
$col_count = 0;
for ($i = 0; $i <= count($criteria); $i++) {
if (isset($criteria[$i])) {
$criterion = $criteria[$i];
if ($current_group && $criterion->criteriatype === $current_group->criteriatype) {
++$col_count;
continue;
}
}
// Print header cell
if ($col_count) {
print '<th scope="col" colspan="'.$col_count.'" class="colheader criteriagroup">'.$current_group->get_type_title().'</th>';
}
if (isset($criteria[$i])) {
// Move to next criteria type
$current_group = $criterion;
$col_count = 1;
}
}
// Overall course completion status
print '<th style="text-align: center;">'.get_string('course').'</th>';
print '</tr>';
// Print aggregation methods
print PHP_EOL.'<tr style="vertical-align: top">';
echo '<th scope="row" class="rowheader" colspan="' . $leftcols . '">' .
get_string('aggregationmethod', 'completion').'</th>';
$current_group = false;
$col_count = 0;
for ($i = 0; $i <= count($criteria); $i++) {
if (isset($criteria[$i])) {
$criterion = $criteria[$i];
if ($current_group && $criterion->criteriatype === $current_group->criteriatype) {
++$col_count;
continue;
}
}
// Print header cell
if ($col_count) {
$has_agg = array(
COMPLETION_CRITERIA_TYPE_COURSE,
COMPLETION_CRITERIA_TYPE_ACTIVITY,
COMPLETION_CRITERIA_TYPE_ROLE,
);
if (in_array($current_group->criteriatype, $has_agg)) {
// Try load a aggregation method
$method = $completion->get_aggregation_method($current_group->criteriatype);
$method = $method == 1 ? get_string('all') : get_string('any');
} else {
$method = '-';
}
print '<th scope="col" colspan="'.$col_count.'" class="colheader aggheader">'.$method.'</th>';
}
if (isset($criteria[$i])) {
// Move to next criteria type
$current_group = $criterion;
$col_count = 1;
}
}
// Overall course aggregation method
print '<th scope="col" class="colheader aggheader aggcriteriacourse">';
// Get course aggregation
$method = $completion->get_aggregation_method();
print $method == 1 ? get_string('all') : get_string('any');
print '</th>';
print '</tr>';
// Print criteria titles
if (COMPLETION_REPORT_COL_TITLES) {
print PHP_EOL.'<tr>';
echo '<th scope="row" class="rowheader" colspan="' . $leftcols . '">' .
get_string('criteria', 'completion') . '</th>';
foreach ($criteria as $criterion) {
// Get criteria details
$details = $criterion->get_title_detailed();
print '<th scope="col" class="colheader criterianame">';
print '<div class="rotated-text-container"><span class="rotated-text">'.$details.'</span></div>';
print '</th>';
}
// Overall course completion status
print '<th scope="col" class="colheader criterianame">';
print '<div class="rotated-text-container"><span class="rotated-text">'.get_string('coursecomplete', 'completion').'</span></div>';
print '</th></tr>';
}
// Print user heading and icons
print '<tr>';
// User heading / sort option
print '<th scope="col" class="completion-sortchoice" style="clear: both;">';
$sistring = "&amp;silast={$silast}&amp;sifirst={$sifirst}";
if ($firstnamesort) {
print
get_string('firstname')." / <a href=\"./index.php?course={$course->id}{$sistring}\">".
get_string('lastname').'</a>';
} else {
print "<a href=\"./index.php?course={$course->id}&amp;sort=firstname{$sistring}\">".
get_string('firstname').'</a> / '.
get_string('lastname');
}
print '</th>';
// Print user identity columns
foreach ($extrafields as $field) {
echo '<th scope="col" class="completion-identifyfield">' .
\core_user\fields::get_display_name($field) . '</th>';
}
///
/// Print criteria icons
///
foreach ($criteria as $criterion) {
// Generate icon details
$iconlink = '';
$iconalt = ''; // Required
$iconattributes = array('class' => 'icon');
switch ($criterion->criteriatype) {
case COMPLETION_CRITERIA_TYPE_ACTIVITY:
// Display icon
$iconlink = $CFG->wwwroot.'/mod/'.$criterion->module.'/view.php?id='.$criterion->moduleinstance;
$iconattributes['title'] = $modinfo->cms[$criterion->moduleinstance]->get_formatted_name();
$iconalt = get_string('modulename', $criterion->module);
break;
case COMPLETION_CRITERIA_TYPE_COURSE:
// Load course
$crs = $DB->get_record('course', array('id' => $criterion->courseinstance));
// Display icon
$iconlink = $CFG->wwwroot.'/course/view.php?id='.$criterion->courseinstance;
$iconattributes['title'] = format_string($crs->fullname, true, array('context' => context_course::instance($crs->id, MUST_EXIST)));
$iconalt = format_string($crs->shortname, true, array('context' => context_course::instance($crs->id)));
break;
case COMPLETION_CRITERIA_TYPE_ROLE:
// Load role
$role = $DB->get_record('role', array('id' => $criterion->role));
// Display icon
$iconalt = $role->name;
break;
}
// Create icon alt if not supplied
if (!$iconalt) {
$iconalt = $criterion->get_title();
}
// Print icon and cell
print '<th class="criteriaicon">';
print ($iconlink ? '<a href="'.$iconlink.'" title="'.$iconattributes['title'].'">' : '');
print $OUTPUT->render($criterion->get_icon($iconalt, $iconattributes));
print ($iconlink ? '</a>' : '');
print '</th>';
}
// Overall course completion status
print '<th class="criteriaicon">';
print $OUTPUT->pix_icon('i/course', get_string('coursecomplete', 'completion'));
print '</th>';
print '</tr></thead>';
echo '<tbody>';
} else {
// The CSV headers
$row = array();
$row[] = get_string('id', 'report_completion');
$row[] = get_string('name', 'report_completion');
foreach ($extrafields as $field) {
$row[] = \core_user\fields::get_display_name($field);
}
// Add activity headers
foreach ($criteria as $criterion) {
// Handle activity completion differently
if ($criterion->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
// Load activity
$mod = $criterion->get_mod_instance();
$row[] = $formattedname = format_string($mod->name, true,
array('context' => context_module::instance($criterion->moduleinstance)));
$row[] = $formattedname . ' - ' . get_string('completiondate', 'report_completion');
}
else {
// Handle all other criteria
$row[] = strip_tags($criterion->get_title_detailed());
}
}
$row[] = get_string('coursecomplete', 'completion');
$export->add_data($row);
}
///
/// Display a row for each user
///
foreach ($progress as $user) {
// User name
if ($csv) {
$row = array();
$row[] = $user->id;
$row[] = fullname($user, has_capability('moodle/site:viewfullnames', $context));
foreach ($extrafields as $field) {
$row[] = $user->{$field};
}
} else {
print PHP_EOL.'<tr id="user-'.$user->id.'">';
if (completion_can_view_data($user->id, $course)) {
$userurl = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id, 'user' => $user->id));
} else {
$userurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id));
}
print '<th scope="row"><a href="' . $userurl->out() . '">' .
fullname($user, has_capability('moodle/site:viewfullnames', $context)) . '</a></th>';
foreach ($extrafields as $field) {
echo '<td>'.s($user->{$field}).'</td>';
}
}
// Progress for each course completion criteria
foreach ($criteria as $criterion) {
$criteria_completion = $completion->get_user_completion($user->id, $criterion);
$is_complete = $criteria_completion->is_complete();
// Handle activity completion differently
if ($criterion->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
// Load activity
$activity = $modinfo->cms[$criterion->moduleinstance];
// Get progress information and state
if (array_key_exists($activity->id, $user->progress)) {
$state = $user->progress[$activity->id]->completionstate;
} else if ($is_complete) {
$state = COMPLETION_COMPLETE;
} else {
$state = COMPLETION_INCOMPLETE;
}
if ($is_complete) {
$date = userdate($criteria_completion->timecompleted, $dateformat);
} else {
$date = '';
}
// Work out how it corresponds to an icon
switch($state) {
case COMPLETION_INCOMPLETE : $completiontype = 'n'; break;
case COMPLETION_COMPLETE : $completiontype = 'y'; break;
case COMPLETION_COMPLETE_PASS : $completiontype = 'pass'; break;
case COMPLETION_COMPLETE_FAIL : $completiontype = 'fail'; break;
}
$auto = $activity->completion == COMPLETION_TRACKING_AUTOMATIC;
$completionicon = 'completion-'.($auto ? 'auto' : 'manual').'-'.$completiontype;
$describe = get_string('completion-'.$completiontype, 'completion');
$a = new StdClass();
$a->state = $describe;
$a->date = $date;
$a->user = fullname($user);
$a->activity = $activity->get_formatted_name();
$fulldescribe = get_string('progress-title', 'completion', $a);
if ($csv) {
$row[] = $describe;
$row[] = $date;
} else {
print '<td class="completion-progresscell">';
print $OUTPUT->pix_icon('i/' . $completionicon, $fulldescribe);
print '</td>';
}
continue;
}
// Handle all other criteria
$completiontype = $is_complete ? 'y' : 'n';
$completionicon = 'completion-auto-'.$completiontype;
$describe = get_string('completion-'.$completiontype, 'completion');
$a = new stdClass();
$a->state = $describe;
if ($is_complete) {
$a->date = userdate($criteria_completion->timecompleted, $dateformat);
} else {
$a->date = '';
}
$a->user = fullname($user);
$a->activity = strip_tags($criterion->get_title());
$fulldescribe = get_string('progress-title', 'completion', $a);
if ($csv) {
$row[] = $a->date;
} else {
print '<td class="completion-progresscell">';
if ($allow_marking_criteria === $criterion->id) {
$describe = get_string('completion-'.$completiontype, 'completion');
$toggleurl = new moodle_url(
'/course/togglecompletion.php',
array(
'user' => $user->id,
'course' => $course->id,
'rolec' => $allow_marking_criteria,
'sesskey' => sesskey()
)
);
print '<a href="'.$toggleurl->out().'" title="'.s(get_string('clicktomarkusercomplete', 'report_completion')).'">' .
$OUTPUT->pix_icon('i/completion-manual-' . ($is_complete ? 'y' : 'n'), $describe) . '</a></td>';
} else {
print $OUTPUT->pix_icon('i/' . $completionicon, $fulldescribe) . '</td>';
}
print '</td>';
}
}
// Handle overall course completion
// Load course completion
$params = array(
'userid' => $user->id,
'course' => $course->id
);
$ccompletion = new completion_completion($params);
$completiontype = $ccompletion->is_complete() ? 'y' : 'n';
$describe = get_string('completion-'.$completiontype, 'completion');
$a = new StdClass;
if ($ccompletion->is_complete()) {
$a->date = userdate($ccompletion->timecompleted, $dateformat);
} else {
$a->date = '';
}
$a->state = $describe;
$a->user = fullname($user);
$a->activity = strip_tags(get_string('coursecomplete', 'completion'));
$fulldescribe = get_string('progress-title', 'completion', $a);
if ($csv) {
$row[] = $a->date;
} else {
print '<td class="completion-progresscell">';
// Display course completion status icon
print $OUTPUT->pix_icon('i/completion-auto-' . $completiontype, $fulldescribe);
print '</td>';
}
if ($csv) {
$export->add_data($row);
} else {
print '</tr>';
}
}
if ($csv) {
$export->download_file();
} else {
echo '</tbody>';
}
print '</table>';
$csvurl = new moodle_url('/report/completion/index.php', array('course' => $course->id, 'format' => 'csv'));
$excelurl = new moodle_url('/report/completion/index.php', array('course' => $course->id, 'format' => 'excelcsv'));
print '<ul class="export-actions">';
print '<li><a href="'.$csvurl->out().'">'.get_string('csvdownload','completion').'</a></li>';
print '<li><a href="'.$excelurl->out().'">'.get_string('excelcsvdownload','completion').'</a></li>';
print '</ul>';
echo $OUTPUT->footer($course);
// Trigger a report viewed event.
$event = \report_completion\event\report_viewed::create(array('context' => $context));
$event->trigger();
@@ -0,0 +1,39 @@
<?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/>.
/**
* Lang strings
*
* @package report
* @subpackage completion
* @copyright 2009 Catalyst IT Ltd
* @author Aaron Barnes <aaronb@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['clicktomarkusercomplete'] = 'Click to mark user complete';
$string['completion:view'] = 'View course completion report';
$string['completiondate'] = 'Completion date';
$string['id'] = 'ID';
$string['name'] = 'Name';
$string['nocapability'] = 'Can not access user completion report';
$string['page-report-completion-x'] = 'Any completion report';
$string['page-report-completion-index'] = 'Course completion report';
$string['page-report-completion-user'] = 'User course completion report';
$string['pluginname'] = 'Course completion';
$string['privacy:metadata'] = 'The Course completion report only shows data stored in other locations.';
$string['eventreportviewed'] = 'Completion report viewed';
$string['eventuserreportviewed'] = 'Completion user report viewed';
+128
View File
@@ -0,0 +1,128 @@
<?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/>.
/**
* Version details.
*
* @package report
* @subpackage completion
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
/**
* This function extends the navigation with the report items
*
* @param navigation_node $navigation The navigation node to extend
* @param stdClass $course The course to object for the report
* @param stdClass $context The context of the course
*/
function report_completion_extend_navigation_course($navigation, $course, $context) {
global $CFG;
require_once($CFG->libdir.'/completionlib.php');
if (has_capability('report/completion:view', $context)) {
$completion = new completion_info($course);
if ($completion->is_enabled() && $completion->has_criteria()) {
$url = new moodle_url('/report/completion/index.php', array('course'=>$course->id));
$navigation->add(get_string('pluginname','report_completion'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
}
}
}
/**
* This function extends the course navigation with the report items
*
* @param navigation_node $navigation The navigation node to extend
* @param stdClass $user
* @param stdClass $course The course to object for the report
*/
function report_completion_extend_navigation_user($navigation, $user, $course) {
return; //TODO: this plugin was not linked from navigation in 2.0, let's keep it that way for now --skodak
if (report_completion_can_access_user_report($user, $course)) {
$url = new moodle_url('/report/completion/user.php', array('id'=>$user->id, 'course'=>$course->id));
$navigation->add(get_string('coursecompletion'), $url);
}
}
/**
* Is current user allowed to access this report
*
* @private defined in lib.php for performance reasons
*
* @param stdClass $user
* @param stdClass $course
* @return bool
*/
function report_completion_can_access_user_report($user, $course) {
global $USER, $CFG;
if (empty($CFG->enablecompletion)) {
return false;
}
if ($course->id != SITEID and !$course->enablecompletion) {
return false;
}
$coursecontext = context_course::instance($course->id);
$personalcontext = context_user::instance($user->id);
if ($user->id == $USER->id) {
if ($course->showreports and (is_viewing($coursecontext, $USER) or is_enrolled($coursecontext, $USER))) {
return true;
}
} else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext)) {
if ($course->showreports and (is_viewing($coursecontext, $user) or is_enrolled($coursecontext, $user))) {
return true;
}
}
// Check if $USER shares group with $user (in case separated groups are enabled and 'moodle/site:accessallgroups' is disabled).
if (!groups_user_groups_visible($course, $user->id)) {
return false;
}
if (has_capability('report/completion:view', $coursecontext)) {
return true;
}
return false;
}
/**
* Return a list of page types
* @param string $pagetype current page type
* @param stdClass $parentcontext Block's parent context
* @param stdClass $currentcontext Current context of block
* @return array
*/
function report_completion_page_type_list($pagetype, $parentcontext, $currentcontext) {
$array = array(
'*' => get_string('page-x', 'pagetype'),
'report-*' => get_string('page-report-x', 'pagetype'),
'report-completion-*' => get_string('page-report-completion-x', 'report_completion'),
'report-completion-index' => get_string('page-report-completion-index', 'report_completion'),
'report-completion-user' => get_string('page-report-completion-user', 'report_completion')
);
return $array;
}
+38
View File
@@ -0,0 +1,38 @@
#page-report-completion-index table#completion-progress {
margin-top: 20px;
margin-bottom: 30px;
}
#page-report-completion-index .export-actions {
text-align: center;
list-style: none;
}
#page-report-completion-index .criterianame,
#page-report-completion-index .criteriaicon,
#page-report-completion-index .completion-progresscell {
text-align: center;
}
/* Custom CSS for rotated header.. */
#page-report-completion-index .rotated-text-container {
display: inline-block;
width: 16px;
}
/*rtl:begin:ignore*/
#page-report-completion-index .rotated-text {
display: inline-block;
white-space: nowrap;
transform: translate(0, 100%) rotate(-90deg);
transform-origin: 0 0;
vertical-align: middle;
}
#page-report-completion-index .rotated-text:after {
content: "";
float: left;
margin-top: 100%;
}
/*rtl:end:ignore*/
@@ -0,0 +1,58 @@
@report @report_completion
Feature: See the completion for items in a course
In order see completion data
As a teacher
I need to view completion report
Background:
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | fruit | Fruit |
And the following "users" exist:
| username | firstname | lastname | email | middlename | alternatename | firstnamephonetic | lastnamephonetic | profile_field_fruit |
| teacher1 | Teacher | 1 | teacher1@example.com | | fred | | | |
| student1 | Grainne | Beauchamp | student1@example.com | Ann | Jill | Gronya | Beecham | Kumquat |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | completion | completionview |
| page | PageName1 | PageDesc1 | C1 | PAGE1 | 1 | 1 |
@javascript
Scenario: The completion report respects user fullname setting
Given the following config values are set as admin:
| fullnamedisplay | firstname |
| alternativefullnameformat | middlename, alternatename, firstname, lastname |
And I am on the "C1" "Course" page logged in as "teacher1"
And I navigate to "Course completion" in current page administration
And I expand all fieldsets
And I set the following fields to these values:
| Page - PageName1 | 1 |
And I press "Save changes"
And I am on "Course 1" course homepage
When I navigate to "Reports" in current page administration
And I click on "Course completion" "link" in the "region-main" "region"
Then I should see "Ann, Jill, Grainne, Beauchamp"
@javascript
Scenario: The completion report displays custom user profile fields
Given the following config values are set as admin:
| showuseridentity | email,profile_field_fruit |
And I am on the "C1" "Course" page logged in as "teacher1"
And I navigate to "Course completion" in current page administration
And I expand all fieldsets
And I set the following fields to these values:
| Page - PageName1 | 1 |
And I press "Save changes"
And I am on "Course 1" course homepage
When I navigate to "Reports" in current page administration
And I click on "Course completion" "link" in the "region-main" "region"
# We can't refer to table headings by name because they aren't on the first row.
Then the following should exist in the "completionreport" table:
| -1- | -2- | -3- |
| Grainne Beauchamp | student1@example.com | Kumquat |
@@ -0,0 +1,32 @@
@report @report_completion
Feature: In a course administration page, navigate through report page, test for course completion page
In order to navigate through report page
As an admin
Go to course administration -> reports -> course completion
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode | enablecompletion |
| Course 1 | C1 | 0 | 1 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| admin | C1 | editingteacher |
| student1 | C1 | student |
@javascript
Scenario: Selector should be available in the course completion page
Given I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I navigate to "Course completion" in current page administration
And I expand all fieldsets
And I set the following fields to these values:
| id_criteria_self | 1 |
And I press "Save changes"
And I am on "Course 1" course homepage
When I navigate to "Reports" in current page administration
And I click on "Course completion" "link" in the "region-main" "region"
Then "Report" "field" should exist in the "tertiary-navigation" "region"
And I should see "Course completion" in the "tertiary-navigation" "region"
@@ -0,0 +1,96 @@
<?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 report completion events.
*
* @package report_completion
* @copyright 2014 onwards Ankit Agarwal<ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace report_completion\event;
/**
* Class report_completion_events_testcase
*
* Class for tests related to completion report events.
*
* @package report_completion
* @copyright 2014 onwards Ankit Agarwal<ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
class events_test extends \advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
$this->setAdminUser();
$this->resetAfterTest();
}
/**
* Test the report viewed event.
*
* It's not possible to use the moodle API to simulate the viewing of log report, so here we
* simply create the event and trigger it.
*/
public function test_report_viewed(): void {
$course = $this->getDataGenerator()->create_course();
$context = \context_course::instance($course->id);
// Trigger event for completion report viewed.
$event = \report_completion\event\report_viewed::create(array('context' => $context));
// Trigger and capture the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$event = reset($events);
$this->assertInstanceOf('\report_completion\event\report_viewed', $event);
$this->assertEquals($context, $event->get_context());
$url = new \moodle_url('/report/completion/index.php', array('course' => $course->id));
$this->assertEquals($url, $event->get_url());
$this->assertEventContextNotUsed($event);
}
/**
* Test the user report viewed event.
*
* It's not possible to use the moodle API to simulate the viewing of log report, so here we
* simply create the event and trigger it.
*/
public function test_user_report_viewed(): void {
$course = $this->getDataGenerator()->create_course();
$context = \context_course::instance($course->id);
// Trigger event for completion report viewed.
$event = \report_completion\event\user_report_viewed::create(array('context' => $context, 'relateduserid' => 3));
// Trigger and capture the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$event = reset($events);
$this->assertInstanceOf('\report_completion\event\user_report_viewed', $event);
$this->assertEquals($context, $event->get_context());
$this->assertEquals(3, $event->relateduserid);
$this->assertEquals(new \moodle_url('/report/completion/user.php', array('id' => 3, 'course' => $course->id)),
$event->get_url());
$this->assertEventContextNotUsed($event);
}
}
+304
View File
@@ -0,0 +1,304 @@
<?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/>.
/**
* Display user completion report
*
* @package report
* @subpackage completion
* @copyright 2009 Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require('../../config.php');
require_once($CFG->dirroot.'/report/completion/lib.php');
require_once($CFG->libdir.'/completionlib.php');
$userid = required_param('id', PARAM_INT);
$courseid = required_param('course', PARAM_INT);
$user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0), '*', MUST_EXIST);
$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
$coursecontext = context_course::instance($course->id);
$personalcontext = context_user::instance($user->id);
if ($USER->id != $user->id and has_capability('moodle/user:viewuseractivitiesreport', $personalcontext)
and !is_enrolled($coursecontext, $USER) and is_enrolled($coursecontext, $user)) {
//TODO: do not require parents to be enrolled in courses - this is a hack!
require_login();
$PAGE->set_course($course);
} else {
require_login($course);
}
if (!report_completion_can_access_user_report($user, $course)) {
// this should never happen
throw new \moodle_exception('nocapability', 'report_completion');
}
$stractivityreport = get_string('activityreport');
$PAGE->set_pagelayout('admin');
$PAGE->set_url('/report/completion/user.php', array('id'=>$user->id, 'course'=>$course->id));
$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");
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
// Display course completion user report
// Grab all courses the user is enrolled in and their completion status
$sql = "
SELECT DISTINCT
c.id AS id
FROM
{course} c
INNER JOIN
{context} con
ON con.instanceid = c.id
INNER JOIN
{role_assignments} ra
ON ra.contextid = con.id
INNER JOIN
{enrol} e
ON c.id = e.courseid
INNER JOIN
{user_enrolments} ue
ON e.id = ue.enrolid AND ra.userid = ue.userid
AND ra.userid = {$user->id}
";
// Get roles that are tracked by course completion
if ($roles = $CFG->gradebookroles) {
$sql .= '
AND ra.roleid IN ('.$roles.')
';
}
$sql .= '
WHERE
con.contextlevel = '.CONTEXT_COURSE.'
AND c.enablecompletion = 1
';
// If we are looking at a specific course
if ($course->id != 1) {
$sql .= '
AND c.id = '.(int)$course->id.'
';
}
// Check if result is empty
$rs = $DB->get_recordset_sql($sql);
if (!$rs->valid()) {
if ($course->id != 1) {
$error = get_string('nocompletions', 'report_completion'); // TODO: missing string
} else {
$error = get_string('nocompletioncoursesenroled', 'report_completion'); // TODO: missing string
}
echo $OUTPUT->notification($error);
$rs->close(); // not going to loop (but break), close rs
echo $OUTPUT->footer();
die();
}
// Categorize courses by their status
$courses = array(
'inprogress' => array(),
'complete' => array(),
'unstarted' => array()
);
// Sort courses by the user's status in each
foreach ($rs as $course_completion) {
$c_info = new completion_info((object)$course_completion);
// Is course complete?
$coursecomplete = $c_info->is_course_complete($user->id);
// Has this user completed any criteria?
$criteriacomplete = $c_info->count_course_user_data($user->id);
if ($coursecomplete) {
$courses['complete'][] = $c_info;
} else if ($criteriacomplete) {
$courses['inprogress'][] = $c_info;
} else {
$courses['unstarted'][] = $c_info;
}
}
$rs->close(); // after loop, close rs
// Loop through course status groups
foreach ($courses as $type => $infos) {
// If there are courses with this status
if (!empty($infos)) {
echo '<h1 align="center">'.get_string($type, 'report_completion').'</h1>';
echo '<table class="generaltable boxaligncenter">';
echo '<tr class="ccheader">';
echo '<th class="c0 header" scope="col">'.get_string('course').'</th>';
echo '<th class="c1 header" scope="col">'.get_string('requiredcriteria', 'completion').'</th>';
echo '<th class="c2 header" scope="col">'.get_string('status').'</th>';
echo '<th class="c3 header" scope="col" width="15%">'.get_string('info').'</th>';
if ($type === 'complete') {
echo '<th class="c4 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
}
echo '</tr>';
// For each course
foreach ($infos as $c_info) {
// Get course info
$c_course = $DB->get_record('course', array('id' => $c_info->course_id));
$course_context = context_course::instance($c_course->id, MUST_EXIST);
$course_name = format_string($c_course->fullname, true, array('context' => $course_context));
// Get completions
$completions = $c_info->get_completions($user->id);
// Save row data
$rows = array();
// For aggregating activity completion
$activities = array();
$activities_complete = 0;
// For aggregating prerequisites
$prerequisites = array();
$prerequisites_complete = 0;
// Loop through course criteria
foreach ($completions as $completion) {
$criteria = $completion->get_criteria();
$complete = $completion->is_complete();
// Activities are a special case, so cache them and leave them till last
if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
$activities[$criteria->moduleinstance] = $complete;
if ($complete) {
$activities_complete++;
}
continue;
}
// Prerequisites are also a special case, so cache them and leave them till last
if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
$prerequisites[$criteria->courseinstance] = $complete;
if ($complete) {
$prerequisites_complete++;
}
continue;
}
$row = array();
$row['title'] = $criteria->get_title();
$row['status'] = $completion->get_status();
$rows[] = $row;
}
// Aggregate activities
if (!empty($activities)) {
$row = array();
$row['title'] = get_string('activitiescomplete', 'report_completion');
$row['status'] = $activities_complete.' of '.count($activities);
$rows[] = $row;
}
// Aggregate prerequisites
if (!empty($prerequisites)) {
$row = array();
$row['title'] = get_string('prerequisitescompleted', 'completion');
$row['status'] = $prerequisites_complete.' of '.count($prerequisites);
array_splice($rows, 0, 0, array($row));
}
$first_row = true;
// Print table
foreach ($rows as $row) {
// Display course name on first row
if ($first_row) {
echo '<tr><td class="c0"><a href="'.$CFG->wwwroot.'/course/view.php?id='.$c_course->id.'">'.$course_name.'</a></td>';
} else {
echo '<tr><td class="c0"></td>';
}
echo '<td class="c1">';
echo $row['title'];
echo '</td><td class="c2">';
switch ($row['status']) {
case 'Yes':
echo get_string('complete');
break;
case 'No':
echo get_string('incomplete', 'report_completion');
break;
default:
echo $row['status'];
}
// Display link on first row
echo '</td><td class="c3">';
if ($first_row) {
echo '<a href="'.$CFG->wwwroot.'/blocks/completionstatus/details.php?course='.$c_course->id.'&user='.$user->id.'">'.get_string('detailedview', 'report_completion').'</a>';
}
echo '</td>';
// Display completion date for completed courses on first row
if ($type === 'complete' && $first_row) {
$params = array(
'userid' => $user->id,
'course' => $c_course->id
);
$ccompletion = new completion_completion($params);
echo '<td class="c4">'.userdate($ccompletion->timecompleted, '%e %B %G').'</td>';
}
$first_row = false;
echo '</tr>';
}
}
echo '</table>';
}
}
echo $OUTPUT->footer();
// Trigger a user report viewed event.
$event = \report_completion\event\user_report_viewed::create(array('context' => $coursecontext, 'relateduserid' => $userid));
$event->trigger();
+31
View File
@@ -0,0 +1,31 @@
<?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/>.
/**
* Version details
*
* @package report
* @subpackage completion
* @copyright 2009 Catalyst IT Ltd
* @author Aaron Barnes <aaronb@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'report_completion'; // Full name of the plugin (used for diagnostics)