Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Definition of the grade_overview_report class 19 * 20 * @package gradereport_overview 21 * @copyright 2007 Nicolas Connault 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 require_once($CFG->dirroot . '/grade/report/lib.php'); 26 require_once($CFG->libdir.'/tablelib.php'); 27 28 /** 29 * Class providing an API for the overview report building and displaying. 30 * @uses grade_report 31 * @package gradereport_overview 32 */ 33 class grade_report_overview extends grade_report { 34 35 /** 36 * The user. 37 * @var object $user 38 */ 39 public $user; 40 41 /** 42 * The user's courses 43 * @var array $courses 44 */ 45 public $courses; 46 47 /** 48 * A flexitable to hold the data. 49 * @var object $table 50 */ 51 public $table; 52 53 /** 54 * Show student ranks within each course. 55 * @var array $showrank 56 */ 57 public $showrank; 58 59 /** 60 * show course/category totals if they contain hidden items 61 */ 62 var $showtotalsifcontainhidden; 63 64 /** 65 * An array of course ids that the user is a student in. 66 * @var array $studentcourseids 67 */ 68 public $studentcourseids; 69 70 /** 71 * An array of courses that the user is a teacher in. 72 * @var array $teachercourses 73 */ 74 public $teachercourses; 75 76 /** 77 * Constructor. Sets local copies of user preferences and initialises grade_tree. 78 * @param int $userid 79 * @param object $gpr grade plugin return tracking object 80 * @param string $context 81 */ 82 public function __construct($userid, $gpr, $context) { 83 global $CFG, $COURSE, $DB; 84 parent::__construct($COURSE->id, $gpr, $context); 85 86 // Get the user (for full name). 87 $this->user = $DB->get_record('user', array('id' => $userid)); 88 89 // Load the user's courses. 90 $this->courses = enrol_get_users_courses($this->user->id, false, 'id, shortname, showgrades'); 91 92 $this->showrank = array(); 93 $this->showrank['any'] = false; 94 95 $this->showtotalsifcontainhidden = array(); 96 97 $this->studentcourseids = array(); 98 $this->teachercourses = array(); 99 $roleids = explode(',', get_config('moodle', 'gradebookroles')); 100 101 if ($this->courses) { 102 foreach ($this->courses as $course) { 103 $this->showrank[$course->id] = grade_get_setting($course->id, 'report_overview_showrank', !empty($CFG->grade_report_overview_showrank)); 104 if ($this->showrank[$course->id]) { 105 $this->showrank['any'] = true; 106 } 107 108 $this->showtotalsifcontainhidden[$course->id] = grade_get_setting($course->id, 'report_overview_showtotalsifcontainhidden', $CFG->grade_report_overview_showtotalsifcontainhidden); 109 110 $coursecontext = context_course::instance($course->id); 111 112 foreach ($roleids as $roleid) { 113 if (user_has_role_assignment($userid, $roleid, $coursecontext->id)) { 114 $this->studentcourseids[$course->id] = $course->id; 115 // We only need to check if one of the roleids has been assigned. 116 break; 117 } 118 } 119 120 if (has_capability('moodle/grade:viewall', $coursecontext, $userid)) { 121 $this->teachercourses[$course->id] = $course; 122 } 123 } 124 } 125 126 127 // base url for sorting by first/last name 128 $this->baseurl = $CFG->wwwroot.'/grade/overview/index.php?id='.$userid; 129 $this->pbarurl = $this->baseurl; 130 131 $this->setup_table(); 132 } 133 134 /** 135 * Prepares the headers and attributes of the flexitable. 136 */ 137 public function setup_table() { 138 /* 139 * Table has 3 columns 140 *| course | final grade | rank (optional) | 141 */ 142 143 // setting up table headers 144 if ($this->showrank['any']) { 145 $tablecolumns = array('coursename', 'grade', 'rank'); 146 $tableheaders = array($this->get_lang_string('coursename', 'grades'), 147 $this->get_lang_string('gradenoun'), 148 $this->get_lang_string('rank', 'grades')); 149 } else { 150 $tablecolumns = array('coursename', 'grade'); 151 $tableheaders = array($this->get_lang_string('coursename', 'grades'), 152 $this->get_lang_string('gradenoun')); 153 } 154 $this->table = new flexible_table('grade-report-overview-'.$this->user->id); 155 156 $this->table->define_columns($tablecolumns); 157 $this->table->define_headers($tableheaders); 158 $this->table->define_baseurl($this->baseurl); 159 160 $this->table->set_attribute('cellspacing', '0'); 161 $this->table->set_attribute('id', 'overview-grade'); 162 $this->table->set_attribute('class', 'boxaligncenter generaltable'); 163 164 $this->table->setup(); 165 } 166 167 /** 168 * Set up the courses grades data for the report. 169 * 170 * @param bool $studentcoursesonly Only show courses that the user is a student of. 171 * @return array of course grades information 172 */ 173 public function setup_courses_data($studentcoursesonly) { 174 global $USER, $DB; 175 176 $coursesdata = array(); 177 $numusers = $this->get_numusers(false); 178 179 foreach ($this->courses as $course) { 180 if (!$course->showgrades) { 181 continue; 182 } 183 184 // If we are only showing student courses and this course isn't part of the group, then move on. 185 if ($studentcoursesonly && !isset($this->studentcourseids[$course->id])) { 186 continue; 187 } 188 189 $coursecontext = context_course::instance($course->id); 190 191 if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { 192 // The course is hidden and the user isn't allowed to see it. 193 continue; 194 } 195 196 if (!has_capability('moodle/user:viewuseractivitiesreport', context_user::instance($this->user->id)) && 197 ((!has_capability('moodle/grade:view', $coursecontext) || $this->user->id != $USER->id) && 198 !has_capability('moodle/grade:viewall', $coursecontext))) { 199 continue; 200 } 201 202 $coursesdata[$course->id]['course'] = $course; 203 $coursesdata[$course->id]['context'] = $coursecontext; 204 205 $canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext); 206 207 // Get course grade_item. 208 $courseitem = grade_item::fetch_course_item($course->id); 209 210 // Get the stored grade. 211 $coursegrade = new grade_grade(array('itemid' => $courseitem->id, 'userid' => $this->user->id)); 212 $coursegrade->grade_item =& $courseitem; 213 $finalgrade = $coursegrade->finalgrade; 214 215 if (!$canviewhidden and !is_null($finalgrade)) { 216 if ($coursegrade->is_hidden()) { 217 $finalgrade = null; 218 } else { 219 $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($course->id, 220 $courseitem, 221 $finalgrade); 222 223 // We temporarily adjust the view of this grade item - because the min and 224 // max are affected by the hidden values in the aggregation. 225 $finalgrade = $adjustedgrade['grade']; 226 $courseitem->grademax = $adjustedgrade['grademax']; 227 $courseitem->grademin = $adjustedgrade['grademin']; 228 } 229 } else { 230 // We must use the specific max/min because it can be different for 231 // each grade_grade when items are excluded from sum of grades. 232 if (!is_null($finalgrade)) { 233 $courseitem->grademin = $coursegrade->get_grade_min(); 234 $courseitem->grademax = $coursegrade->get_grade_max(); 235 } 236 } 237 238 $coursesdata[$course->id]['finalgrade'] = $finalgrade; 239 $coursesdata[$course->id]['courseitem'] = $courseitem; 240 241 if ($this->showrank['any'] && $this->showrank[$course->id] && !is_null($finalgrade)) { 242 // Find the number of users with a higher grade. 243 // Please note this can not work if hidden grades involved :-( to be fixed in 2.0. 244 $params = array($finalgrade, $courseitem->id); 245 $sql = "SELECT COUNT(DISTINCT(userid)) 246 FROM {grade_grades} 247 WHERE finalgrade IS NOT NULL AND finalgrade > ? 248 AND itemid = ?"; 249 $rank = $DB->count_records_sql($sql, $params) + 1; 250 251 $coursesdata[$course->id]['rank'] = $rank; 252 $coursesdata[$course->id]['numusers'] = $numusers; 253 } 254 } 255 return $coursesdata; 256 } 257 258 /** 259 * Fill the table for displaying. 260 * 261 * @param bool $activitylink If this report link to the activity report or the user report. 262 * @param bool $studentcoursesonly Only show courses that the user is a student of. 263 */ 264 public function fill_table($activitylink = false, $studentcoursesonly = false) { 265 global $CFG, $DB, $OUTPUT, $USER; 266 267 if ($studentcoursesonly && count($this->studentcourseids) == 0) { 268 return false; 269 } 270 271 // Only show user's courses instead of all courses. 272 if ($this->courses) { 273 $coursesdata = $this->setup_courses_data($studentcoursesonly); 274 275 // Check whether current user can view all grades of this user - parent most probably. 276 $viewasuser = $this->course->showgrades && has_any_capability([ 277 'moodle/grade:viewall', 278 'moodle/user:viewuseractivitiesreport', 279 ], context_user::instance($this->user->id)); 280 281 foreach ($coursesdata as $coursedata) { 282 283 $course = $coursedata['course']; 284 $coursecontext = $coursedata['context']; 285 $finalgrade = $coursedata['finalgrade']; 286 $courseitem = $coursedata['courseitem']; 287 288 $coursenamelink = format_string(get_course_display_name_for_list($course), true, ['context' => $coursecontext]); 289 290 // Link to the course grade report pages (performing same capability checks as the pages themselves). 291 if ($activitylink && 292 (has_capability('gradereport/' . $CFG->grade_profilereport .':view', $coursecontext) || $viewasuser)) { 293 294 $coursenamelink = html_writer::link(new moodle_url('/course/user.php', [ 295 'mode' => 'grade', 296 'id' => $course->id, 297 'user' => $this->user->id, 298 ]), $coursenamelink); 299 } else if (!$activitylink && (has_capability('gradereport/user:view', $coursecontext) || $viewasuser)) { 300 $coursenamelink = html_writer::link(new moodle_url('/grade/report/user/index.php', [ 301 'id' => $course->id, 302 'userid' => $this->user->id, 303 'group' => $this->gpr->groupid, 304 ]), $coursenamelink); 305 } 306 307 $data = [$coursenamelink, grade_format_gradevalue($finalgrade, $courseitem, true)]; 308 309 if ($this->showrank['any']) { 310 if ($this->showrank[$course->id] && !is_null($finalgrade)) { 311 $rank = $coursedata['rank']; 312 $numusers = $coursedata['numusers']; 313 $data[] = "$rank/$numusers"; 314 } else { 315 // No grade, no rank. 316 // Or this course wants rank hidden. 317 $data[] = '-'; 318 } 319 } 320 321 $this->table->add_data($data); 322 } 323 324 return true; 325 } else { 326 echo $OUTPUT->notification(get_string('notenrolled', 'grades'), 'notifymessage'); 327 return false; 328 } 329 } 330 331 /** 332 * Prints or returns the HTML from the flexitable. 333 * @param bool $return Whether or not to return the data instead of printing it directly. 334 * @return string 335 */ 336 public function print_table($return=false) { 337 ob_start(); 338 $this->table->print_html(); 339 $html = ob_get_clean(); 340 if ($return) { 341 return $html; 342 } else { 343 echo $html; 344 } 345 } 346 347 /** 348 * Print a table to show courses that the user is able to grade. 349 */ 350 public function print_teacher_table() { 351 $table = new html_table(); 352 $table->head = array(get_string('coursename', 'grades')); 353 $table->data = null; 354 foreach ($this->teachercourses as $courseid => $course) { 355 $url = new moodle_url('/grade/report/index.php', array('id' => $courseid)); 356 $table->data[] = array(html_writer::link($url, $course->fullname)); 357 } 358 echo html_writer::table($table); 359 } 360 361 /** 362 * Processes the data sent by the form (grades and feedbacks). 363 * @param array $data 364 * @return bool Success or Failure (array of errors). 365 */ 366 function process_data($data) { 367 } 368 function process_action($target, $action) { 369 } 370 371 /** 372 * This report supports being set as the 'grades' report. 373 */ 374 public static function supports_mygrades() { 375 return true; 376 } 377 378 /** 379 * Check if the user can access the report. 380 * 381 * @param stdClass $systemcontext system context 382 * @param stdClass $context course context 383 * @param stdClass $personalcontext personal context 384 * @param stdClass $course course object 385 * @param int $userid userid 386 * @return bool true if the user can access the report 387 * @since Moodle 3.2 388 */ 389 public static function check_access($systemcontext, $context, $personalcontext, $course, $userid) { 390 global $USER; 391 392 $access = false; 393 if (has_capability('moodle/grade:viewall', $systemcontext)) { 394 // Ok - can view all course grades. 395 $access = true; 396 397 } else if (has_capability('moodle/grade:viewall', $context)) { 398 // Ok - can view any grades in context. 399 $access = true; 400 401 } else if ($userid == $USER->id and ((has_capability('moodle/grade:view', $context) and $course->showgrades) 402 || $course->id == SITEID)) { 403 // Ok - can view own course grades. 404 $access = true; 405 406 } else if (has_capability('moodle/grade:viewall', $personalcontext) and $course->showgrades) { 407 // Ok - can view grades of this user - parent most probably. 408 $access = true; 409 } else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and $course->showgrades) { 410 // Ok - can view grades of this user - parent most probably. 411 $access = true; 412 } 413 return $access; 414 } 415 416 /** 417 * Trigger the grade_report_viewed event 418 * 419 * @param stdClass $context course context 420 * @param int $courseid course id 421 * @param int $userid user id 422 * @since Moodle 3.2 423 */ 424 public static function viewed($context, $courseid, $userid) { 425 $event = \gradereport_overview\event\grade_report_viewed::create( 426 array( 427 'context' => $context, 428 'courseid' => $courseid, 429 'relateduserid' => $userid, 430 ) 431 ); 432 $event->trigger(); 433 } 434 } 435 436 function grade_report_overview_settings_definition(&$mform) { 437 global $CFG; 438 439 //show rank 440 $options = array(-1 => get_string('default', 'grades'), 441 0 => get_string('hide'), 442 1 => get_string('show')); 443 444 if (empty($CFG->grade_report_overview_showrank)) { 445 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 446 } else { 447 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 448 } 449 450 $mform->addElement('select', 'report_overview_showrank', get_string('showrank', 'grades'), $options); 451 $mform->addHelpButton('report_overview_showrank', 'showrank', 'grades'); 452 453 //showtotalsifcontainhidden 454 $options = array(-1 => get_string('default', 'grades'), 455 GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN => get_string('hide'), 456 GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowexhiddenitems', 'grades'), 457 GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowinchiddenitems', 'grades') ); 458 459 if (!array_key_exists($CFG->grade_report_overview_showtotalsifcontainhidden, $options)) { 460 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 461 } else { 462 $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_overview_showtotalsifcontainhidden]); 463 } 464 465 $mform->addElement('select', 'report_overview_showtotalsifcontainhidden', get_string('hidetotalifhiddenitems', 'grades'), $options); 466 $mform->addHelpButton('report_overview_showtotalsifcontainhidden', 'hidetotalifhiddenitems', 'grades'); 467 } 468 469 /** 470 * Add nodes to myprofile page. 471 * 472 * @param \core_user\output\myprofile\tree $tree Tree object 473 * @param stdClass $user user object 474 * @param bool $iscurrentuser 475 * @param stdClass $course Course object 476 */ 477 function gradereport_overview_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) { 478 if (empty($course)) { 479 // We want to display these reports under the site context. 480 $course = get_fast_modinfo(SITEID)->get_course(); 481 } 482 $systemcontext = context_system::instance(); 483 $usercontext = context_user::instance($user->id); 484 $coursecontext = context_course::instance($course->id); 485 if (grade_report_overview::check_access($systemcontext, $coursecontext, $usercontext, $course, $user->id)) { 486 $url = new moodle_url('/grade/report/overview/index.php', array('userid' => $user->id, 'id' => $course->id)); 487 $node = new core_user\output\myprofile\node('reports', 'grades', get_string('gradesoverview', 'gradereport_overview'), 488 null, $url); 489 $tree->add_node($node); 490 } 491 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body